Skip to main content

gpui/
window.rs

1#[cfg(feature = "profiler")]
2use crate::DebugFrameOverlayMode;
3#[cfg(debug_assertions)]
4use crate::Inspector;
5#[cfg(feature = "profiler")]
6use crate::profiler;
7use crate::subscription::SingleSubscriberSet;
8use crate::taffy::TaffyLayoutEngine;
9use crate::{
10    Action, AnyDrag, AnyElement, AnyImageCache, AnyTooltip, AnyView, App, AppContext, Arena, Asset,
11    AsyncWindowContext, AtlasTile, AvailableSpace, Background, BorderStyle, Bounds, BoxShadow,
12    Capslock, Context, Corners, CursorHideMode, CursorStyle, Decorations, DevicePixels,
13    DispatchActionListener, DispatchNodeId, DispatchTree, DisplayId, Edges, Effect, Entity,
14    EntityId, EventEmitter, FileDropEvent, FontId, Global, GlobalElementId, GlyphId, GpuSpecs,
15    Hsla, InputHandler, InputPreference, IsZero, KeyBinding, KeyContext, KeyDownEvent, KeyEvent,
16    Keystroke, KeystrokeEvent, LayoutId, LineLayoutIndex, Modifiers, ModifiersChangedEvent,
17    MonochromeSprite, MouseButton, MouseEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels,
18    PlatformAtlas, PlatformDisplay, PlatformInput, PlatformInputHandler, PlatformWindow, Point,
19    PolychromeSprite, Priority, PromptButton, PromptLevel, Quad, Render, RenderGlyphParams,
20    RenderImage, RenderImageParams, RenderSvgParams, Replay, ResizeEdge, SMOOTH_SVG_SCALE_FACTOR,
21    SUBPIXEL_VARIANTS_X, SUBPIXEL_VARIANTS_Y, ScaledPixels, Scene, Shadow, SharedString, Size,
22    StrikethroughStyle, Style, SubpixelSprite, Subscription, SystemWindowTab,
23    SystemWindowTabController, TabStopMap, Task, TextInputConfiguration, TextInputStateChange,
24    TextRenderingMode, TextStyle, TextStyleRefinement, ThermalState, TransformationMatrix,
25    Underline, UnderlineStyle, WindowAppearance, WindowBackgroundAppearance, WindowBounds,
26    WindowControls, WindowDecorations, WindowInsets, WindowOptions, WindowParams, WindowTextSystem,
27    WindowVisibility, point, prelude::*, px, rems, size, transparent_black,
28};
29
30use crate::gestures::{GestureTuning, RecognizedTouchGesture, TouchGestureRecognizer};
31use crate::interactive::TouchEvent;
32use anyhow::{Context as _, Result, anyhow};
33use collections::{FxHashMap, FxHashSet};
34use derive_more::{Deref, DerefMut};
35use futures::channel::oneshot;
36use gpui_util::post_inc;
37use gpui_util::{ResultExt, measure};
38use itertools::FoldWhile::{Continue, Done};
39use itertools::Itertools;
40#[cfg(any(target_os = "macos", target_os = "ios"))]
41use objc2_core_foundation::CFRetained;
42#[cfg(any(target_os = "macos", target_os = "ios"))]
43use objc2_core_video::CVPixelBuffer;
44use parking_lot::{RwLock, RwLockUpgradableReadGuard};
45use raw_window_handle::{HandleError, HasDisplayHandle, HasWindowHandle};
46use refineable::Refineable;
47use scheduler::Instant;
48use slotmap::SlotMap;
49use smallvec::SmallVec;
50use std::{
51    any::{Any, TypeId},
52    borrow::Cow,
53    cell::{Cell, RefCell},
54    cmp,
55    fmt::{Debug, Display},
56    hash::{Hash, Hasher},
57    marker::PhantomData,
58    mem,
59    ops::{DerefMut, Range},
60    rc::Rc,
61    sync::{
62        Arc, Weak,
63        atomic::{AtomicBool, AtomicUsize, Ordering::SeqCst},
64    },
65    thread::AccessError,
66    time::Duration,
67};
68use uuid::Uuid;
69
70pub(crate) mod a11y;
71mod prompts;
72
73pub use a11y::A11ySubtreeBuilder;
74
75use self::a11y::A11y;
76#[cfg(not(target_family = "wasm"))]
77use self::a11y::ROOT_NODE_ID;
78use crate::util::{
79    atomic_incr_if_not_zero, ceil_to_device_pixel, floor_to_device_pixel, round_half_toward_zero,
80    round_half_toward_zero_f64, round_stroke_to_device_pixel, round_to_device_pixel,
81};
82pub use prompts::*;
83
84/// Default window size used when no explicit size is provided.
85pub const DEFAULT_WINDOW_SIZE: Size<Pixels> = size(px(1536.), px(1095.));
86
87/// A 6:5 aspect ratio minimum window size to be used for functional,
88/// additional-to-main-Zed windows, like the settings and rules library windows.
89pub const DEFAULT_ADDITIONAL_WINDOW_SIZE: Size<Pixels> = Size {
90    width: Pixels(900.),
91    height: Pixels(750.),
92};
93
94/// Represents the two different phases when dispatching events.
95#[derive(Default, Copy, Clone, Debug, Eq, PartialEq)]
96pub enum DispatchPhase {
97    /// After the capture phase comes the bubble phase, in which mouse event listeners are
98    /// invoked front to back and keyboard event listeners are invoked from the focused element
99    /// to the root of the element tree. This is the phase you'll most commonly want to use when
100    /// registering event listeners.
101    #[default]
102    Bubble,
103    /// During the initial capture phase, mouse event listeners are invoked back to front, and keyboard
104    /// listeners are invoked from the root of the tree downward toward the focused element. This phase
105    /// is used for special purposes such as clearing the "pressed" state for click events. If
106    /// you stop event propagation during this phase, you need to know what you're doing. Handlers
107    /// outside of the immediate region may rely on detecting non-local events during this phase.
108    Capture,
109}
110
111impl DispatchPhase {
112    /// Returns true if this represents the "bubble" phase.
113    #[inline]
114    pub fn bubble(self) -> bool {
115        self == DispatchPhase::Bubble
116    }
117
118    /// Returns true if this represents the "capture" phase.
119    #[inline]
120    pub fn capture(self) -> bool {
121        self == DispatchPhase::Capture
122    }
123}
124
125struct WindowInvalidatorInner {
126    #[cfg(feature = "profiler")]
127    pub window_id: WindowId,
128    pub dirty: bool,
129    pub draw_phase: DrawPhase,
130    pub dirty_views: FxHashSet<EntityId>,
131    pub update_count: usize,
132    #[cfg(feature = "profiler")]
133    pub frame_dirty: FrameDirtyAccumulator,
134    pub platform_waker: Option<Rc<dyn Fn()>>,
135}
136
137/// Per-frame invalidation bookkeeping, drained at draw time and emitted to the
138/// frame profiler. Tracks when the current frame first became dirty and how
139/// many invalidations were coalesced into it, whenever the profiler is
140/// compiled in. Retention of the resulting per-frame records is what
141/// `profiler::trace_enabled()` controls, not this measurement.
142#[cfg(feature = "profiler")]
143#[derive(Default)]
144struct FrameDirtyAccumulator {
145    dirty_at: Option<Instant>,
146    invalidations: u64,
147}
148
149#[derive(Clone)]
150pub(crate) struct WindowInvalidator {
151    inner: Rc<RefCell<WindowInvalidatorInner>>,
152}
153
154impl WindowInvalidator {
155    pub fn new(#[allow(unused_variables)] window_id: WindowId) -> Self {
156        WindowInvalidator {
157            inner: Rc::new(RefCell::new(WindowInvalidatorInner {
158                #[cfg(feature = "profiler")]
159                window_id,
160                dirty: true,
161                draw_phase: DrawPhase::None,
162                dirty_views: FxHashSet::default(),
163                update_count: 0,
164                #[cfg(feature = "profiler")]
165                frame_dirty: FrameDirtyAccumulator::default(),
166                platform_waker: None,
167            })),
168        }
169    }
170
171    pub fn invalidate_view(&self, entity: EntityId, cx: &mut App) -> bool {
172        let mut inner = self.inner.borrow_mut();
173        inner.update_count += 1;
174        inner.dirty_views.insert(entity);
175        if inner.draw_phase == DrawPhase::None {
176            #[cfg(feature = "profiler")]
177            let dirty_at = Self::record_frame_dirty(&mut inner);
178            let became_dirty = !inner.dirty;
179            inner.dirty = true;
180            let waker = became_dirty.then(|| inner.platform_waker.clone()).flatten();
181            #[cfg(feature = "profiler")]
182            let window_id = inner.window_id;
183            drop(inner);
184            #[cfg(feature = "profiler")]
185            if became_dirty {
186                profiler::journal::record_frame_pending(window_id, dirty_at);
187            }
188            cx.push_effect(Effect::Notify { emitter: entity });
189            if let Some(waker) = waker {
190                waker();
191            }
192            true
193        } else {
194            false
195        }
196    }
197
198    pub fn is_dirty(&self) -> bool {
199        self.inner.borrow().dirty
200    }
201
202    pub fn set_dirty(&self, dirty: bool) {
203        let mut inner = self.inner.borrow_mut();
204        let became_dirty = dirty && !inner.dirty;
205        inner.dirty = dirty;
206        if dirty {
207            inner.update_count += 1;
208        }
209        #[cfg(feature = "profiler")]
210        let dirty_at = dirty.then(|| Self::record_frame_dirty(&mut inner));
211        let waker = became_dirty.then(|| inner.platform_waker.clone()).flatten();
212        #[cfg(feature = "profiler")]
213        let window_id = inner.window_id;
214        drop(inner);
215        #[cfg(feature = "profiler")]
216        if became_dirty && let Some(dirty_at) = dirty_at {
217            profiler::journal::record_frame_pending(window_id, dirty_at);
218        }
219        if let Some(waker) = waker {
220            waker();
221        }
222    }
223
224    pub fn set_platform_waker(&self, waker: Option<Rc<dyn Fn()>>) {
225        let mut inner = self.inner.borrow_mut();
226        inner.platform_waker = waker;
227        let waker = inner.dirty.then(|| inner.platform_waker.clone()).flatten();
228        drop(inner);
229        if let Some(waker) = waker {
230            waker();
231        }
232    }
233
234    /// Wakes the platform's frame-request source so a frame request is
235    /// delivered even if the platform stops requesting frames for idle
236    /// windows. No-op on platforms without a frame waker.
237    pub fn wake_platform(&self) {
238        let waker = self.inner.borrow().platform_waker.clone();
239        if let Some(waker) = waker {
240            waker();
241        }
242    }
243
244    pub fn set_phase(&self, phase: DrawPhase) {
245        self.inner.borrow_mut().draw_phase = phase
246    }
247
248    pub fn update_count(&self) -> usize {
249        self.inner.borrow().update_count
250    }
251
252    #[cfg(feature = "profiler")]
253    fn record_frame_dirty(inner: &mut WindowInvalidatorInner) -> Instant {
254        let dirty_at = *inner.frame_dirty.dirty_at.get_or_insert_with(Instant::now);
255        inner.frame_dirty.invalidations += 1;
256        dirty_at
257    }
258
259    #[cfg(feature = "profiler")]
260    fn take_frame_dirty(&self) -> FrameDirtyAccumulator {
261        mem::take(&mut self.inner.borrow_mut().frame_dirty)
262    }
263
264    pub fn take_views(&self) -> FxHashSet<EntityId> {
265        mem::take(&mut self.inner.borrow_mut().dirty_views)
266    }
267
268    pub fn replace_views(&self, views: FxHashSet<EntityId>) {
269        self.inner.borrow_mut().dirty_views = views;
270    }
271
272    pub fn not_drawing(&self) -> bool {
273        self.inner.borrow().draw_phase == DrawPhase::None
274    }
275
276    #[track_caller]
277    pub fn debug_assert_paint(&self) {
278        debug_assert!(
279            matches!(self.inner.borrow().draw_phase, DrawPhase::Paint),
280            "this method can only be called during paint"
281        );
282    }
283
284    #[track_caller]
285    pub fn debug_assert_prepaint(&self) {
286        debug_assert!(
287            matches!(self.inner.borrow().draw_phase, DrawPhase::Prepaint),
288            "this method can only be called during request_layout, or prepaint"
289        );
290    }
291
292    #[track_caller]
293    pub fn debug_assert_paint_or_prepaint(&self) {
294        debug_assert!(
295            matches!(
296                self.inner.borrow().draw_phase,
297                DrawPhase::Paint | DrawPhase::Prepaint
298            ),
299            "this method can only be called during request_layout, prepaint, or paint"
300        );
301    }
302}
303
304type AnyObserver = Box<dyn FnMut(&mut Window, &mut App) -> bool + 'static>;
305
306pub(crate) type AnyWindowFocusListener =
307    Box<dyn FnMut(&WindowFocusEvent, &mut Window, &mut App) -> bool + 'static>;
308
309pub(crate) struct WindowFocusEvent {
310    pub(crate) previous_focus_path: SmallVec<[FocusId; 8]>,
311    pub(crate) current_focus_path: SmallVec<[FocusId; 8]>,
312}
313
314impl WindowFocusEvent {
315    pub fn is_focus_in(&self, focus_id: FocusId) -> bool {
316        !self.previous_focus_path.contains(&focus_id) && self.current_focus_path.contains(&focus_id)
317    }
318
319    pub fn is_focus_out(&self, focus_id: FocusId) -> bool {
320        self.previous_focus_path.contains(&focus_id) && !self.current_focus_path.contains(&focus_id)
321    }
322}
323
324/// This is provided when subscribing for `Context::on_focus_out` events.
325pub struct FocusOutEvent {
326    /// A weak focus handle representing what was blurred.
327    pub blurred: WeakFocusHandle,
328}
329
330slotmap::new_key_type! {
331    /// A globally unique identifier for a focusable element.
332    pub struct FocusId;
333}
334
335thread_local! {
336    /// Fallback arena used when no app-specific arena is active.
337    /// In production, each window draw sets CURRENT_ELEMENT_ARENA to the app's arena.
338    pub(crate) static ELEMENT_ARENA: RefCell<Arena> = RefCell::new(Arena::new(1024 * 1024));
339
340    /// Points to the current App's element arena during draw operations.
341    /// This allows multiple test Apps to have isolated arenas, preventing
342    /// cross-session corruption when the scheduler interleaves their tasks.
343    static CURRENT_ELEMENT_ARENA: Cell<Option<*const RefCell<Arena>>> = const { Cell::new(None) };
344}
345
346/// Whether a window draw is currently in progress on this thread.
347///
348/// This holds exactly while an `ElementArenaScope` is active: nested scopes
349/// restore the previous (still set) arena pointer, so `CURRENT_ELEMENT_ARENA`
350/// is `Some` from the outermost draw's start to its end.
351///
352/// The `on_request_frame` callback uses this to defer draw requests that
353/// arrive re-entrantly while a draw is already on the stack (e.g. via nested
354/// message pumping in the Windows window procedure), instead of running a
355/// nested draw or panicking on the already-borrowed App.
356fn draw_in_progress() -> bool {
357    CURRENT_ELEMENT_ARENA.with(|current| current.get().is_some())
358}
359
360/// Allocates an element in the current arena. Uses the app-specific arena if one
361/// is active (during draw), otherwise falls back to the thread-local ELEMENT_ARENA.
362#[inline(always)]
363pub(crate) fn with_element_arena<R>(callback: impl FnOnce(&mut Arena) -> R) -> R {
364    let mut callback = Some(callback);
365    let mut result = None;
366    let access = with_element_arena_erased(&mut |arena| {
367        result = Some(callback.take().expect("arena callback runs once")(arena));
368    });
369    drop(callback);
370    access.expect("cannot access a Thread Local Storage value during or after destruction");
371    result.expect("arena callback produces a result")
372}
373
374/// Scope guard that sets CURRENT_ELEMENT_ARENA for the duration of a draw
375/// operation and tracks the arena's scope depth, so that a nested draw's
376/// `ArenaClearNeeded::clear` is deferred rather than freeing memory the outer
377/// draw still references (see `Arena::clear`).
378///
379/// Call [`ElementArenaScope::exit`] with the same arena that was entered to
380/// obtain the [`ArenaClearNeeded`] token the draw now owes; requiring `exit`
381/// makes it impossible to request a clear before the scope has ended. The
382/// scope's teardown — restoring the thread-local and balancing `begin_scope`
383/// with `end_scope` — happens in `Drop`, so the arena's scope depth stays
384/// balanced on every path, including when a panic unwinds a draw before `exit`
385/// is reached. (If teardown lived only in `exit`, such a panic would leave the
386/// scope depth permanently elevated and defer every future clear, leaking
387/// memory unboundedly.)
388pub(crate) struct ElementArenaScope {
389    /// The entered arena: compared against the argument in `exit`, and
390    /// dereferenced in `Drop` to end its scope (see the SAFETY note there).
391    entered: *const RefCell<Arena>,
392    previous: Option<*const RefCell<Arena>>,
393    exited: bool,
394}
395
396impl ElementArenaScope {
397    /// Enter a scope where element allocations use the given arena.
398    pub(crate) fn enter(arena: &RefCell<Arena>) -> Self {
399        arena.borrow_mut().begin_scope();
400        let previous = CURRENT_ELEMENT_ARENA.with(|current| {
401            let prev = current.get();
402            current.set(Some(arena as *const RefCell<Arena>));
403            prev
404        });
405        Self {
406            entered: arena as *const RefCell<Arena>,
407            previous,
408            exited: false,
409        }
410    }
411
412    /// End the scope: restores the previously-current arena and ends the
413    /// arena's clear-deferral scope. Returns the token for the arena clear the
414    /// draw now owes; producing it here makes it impossible to request a clear
415    /// before the scope has ended (which would be silently deferred forever).
416    ///
417    /// Panics if passed a different arena than was entered: ending the scope
418    /// of the wrong arena would unbalance two arenas' scope depths, allowing
419    /// one of them to clear while a draw still references its memory.
420    pub(crate) fn exit(mut self, arena: &RefCell<Arena>) -> ArenaClearNeeded {
421        assert!(
422            std::ptr::eq(self.entered, arena),
423            "ElementArenaScope::exit called with a different arena than was entered"
424        );
425        self.exited = true;
426        // Teardown (restoring the thread-local and ending the arena's
427        // clear-deferral scope) runs in `Drop`, which fires both here — `self`
428        // is dropped as `exit` returns, before the token reaches the caller —
429        // and when a panic unwinds the draw before `exit` is reached.
430        ArenaClearNeeded::new(arena)
431    }
432}
433
434impl Drop for ElementArenaScope {
435    fn drop(&mut self) {
436        // Teardown lives here (rather than in `exit`) so it runs exactly once on
437        // every path: `exit` consumes and drops the guard on the normal path,
438        // and unwinding drops it on the panic path. Balancing `begin_scope` here
439        // keeps the arena's scope depth correct even when a draw panics; if this
440        // only happened in `exit`, a panic between `enter` and `exit` would leave
441        // the depth elevated and defer every future clear.
442        CURRENT_ELEMENT_ARENA.with(|current| {
443            current.set(self.previous);
444        });
445        // SAFETY: `entered` came from a `&RefCell<Arena>` in `enter`, and the
446        // arena (owned by the `App` being drawn) outlives this guard on both the
447        // normal and unwinding paths, since the guard is a local of the draw.
448        unsafe { &*self.entered }.borrow_mut().end_scope();
449        if !self.exited && !std::thread::panicking() {
450            debug_assert!(false, "ElementArenaScope dropped without calling exit()");
451            log::error!(
452                "ElementArenaScope dropped without calling exit(); \
453                 the arena clear for this draw was never requested"
454            );
455        }
456    }
457}
458
459/// Returned when the element arena has been used and so must be cleared before the next draw.
460#[must_use]
461pub struct ArenaClearNeeded {
462    /// Identity of the arena that was drawn into. Only ever compared against
463    /// another pointer in `clear`; never dereferenced.
464    arena: *const RefCell<Arena>,
465}
466
467impl ArenaClearNeeded {
468    /// Create a new ArenaClearNeeded token for the App whose arena was drawn
469    /// into. Private: the only way to obtain one is [`ElementArenaScope::exit`].
470    fn new(arena: &RefCell<Arena>) -> Self {
471        Self {
472            arena: arena as *const RefCell<Arena>,
473        }
474    }
475
476    /// Clear the element arena of the App the draw ran against. If an enclosing
477    /// draw is still in progress (this draw was nested inside it), the clear is
478    /// deferred to the enclosing draw's own `ArenaClearNeeded` so that its live
479    /// allocations aren't freed.
480    ///
481    /// Panics if passed a different App than the draw ran against, since
482    /// clearing another App's arena could free memory its draws still
483    /// reference.
484    pub fn clear(self, cx: &mut App) {
485        assert!(
486            std::ptr::eq(self.arena, &cx.element_arena),
487            "ArenaClearNeeded::clear called with a different App than the draw ran against"
488        );
489        cx.element_arena.borrow_mut().clear();
490    }
491}
492
493#[derive(Default)]
494pub(crate) struct FocusMap {
495    pub(crate) handles: SlotMap<FocusId, FocusRef>,
496    pub(crate) dropped_handles: Vec<FocusId>,
497}
498
499pub(crate) struct FocusRef {
500    pub(crate) ref_count: AtomicUsize,
501    pub(crate) tab_index: isize,
502    pub(crate) tab_stop: bool,
503}
504
505impl FocusId {
506    /// Obtains whether the element associated with this handle is currently focused.
507    pub fn is_focused(&self, window: &Window) -> bool {
508        window.focus == Some(*self)
509    }
510
511    /// Obtains whether the element associated with this handle contains the focused
512    /// element or is itself focused.
513    pub fn contains_focused(&self, window: &Window, cx: &App) -> bool {
514        window
515            .focused(cx)
516            .is_some_and(|focused| self.contains(focused.id, window))
517    }
518
519    /// Obtains whether the element associated with this handle is contained within the
520    /// focused element or is itself focused.
521    pub fn within_focused(&self, window: &Window, cx: &App) -> bool {
522        let focused = window.focused(cx);
523        focused.is_some_and(|focused| focused.id.contains(*self, window))
524    }
525
526    /// Obtains whether this handle contains the given handle in the most recently rendered frame.
527    pub(crate) fn contains(&self, other: Self, window: &Window) -> bool {
528        window
529            .rendered_frame
530            .dispatch_tree
531            .focus_contains(*self, other)
532    }
533}
534
535/// A handle which can be used to track and manipulate the focused element in a window.
536pub struct FocusHandle {
537    pub(crate) id: FocusId,
538    handles: Arc<RwLock<FocusMap>>,
539    /// The index of this element in the tab order.
540    pub tab_index: isize,
541    /// Whether this element can be focused by tab navigation.
542    pub tab_stop: bool,
543}
544
545impl std::fmt::Debug for FocusHandle {
546    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
547        f.write_fmt(format_args!("FocusHandle({:?})", self.id))
548    }
549}
550
551impl FocusHandle {
552    pub(crate) fn new(handles: &Arc<RwLock<FocusMap>>) -> Self {
553        let id = handles.write().handles.insert(FocusRef {
554            ref_count: AtomicUsize::new(1),
555            tab_index: 0,
556            tab_stop: false,
557        });
558
559        Self {
560            id,
561            tab_index: 0,
562            tab_stop: false,
563            handles: handles.clone(),
564        }
565    }
566
567    pub(crate) fn for_id(id: FocusId, handles: &Arc<RwLock<FocusMap>>) -> Option<Self> {
568        let lock = handles.read();
569        let focus = lock.handles.get(id)?;
570        if atomic_incr_if_not_zero(&focus.ref_count) == 0 {
571            return None;
572        }
573        Some(Self {
574            id,
575            tab_index: focus.tab_index,
576            tab_stop: focus.tab_stop,
577            handles: handles.clone(),
578        })
579    }
580
581    /// Sets the tab index of the element associated with this handle.
582    pub fn tab_index(mut self, index: isize) -> Self {
583        self.tab_index = index;
584        if let Some(focus) = self.handles.write().handles.get_mut(self.id) {
585            focus.tab_index = index;
586        }
587        self
588    }
589
590    /// Sets whether the element associated with this handle is a tab stop.
591    ///
592    /// When `false`, the element will not be included in the tab order.
593    pub fn tab_stop(mut self, tab_stop: bool) -> Self {
594        self.tab_stop = tab_stop;
595        if let Some(focus) = self.handles.write().handles.get_mut(self.id) {
596            focus.tab_stop = tab_stop;
597        }
598        self
599    }
600
601    /// Converts this focus handle into a weak variant, which does not prevent it from being released.
602    pub fn downgrade(&self) -> WeakFocusHandle {
603        WeakFocusHandle {
604            id: self.id,
605            handles: Arc::downgrade(&self.handles),
606        }
607    }
608
609    /// Moves the focus to the element associated with this handle.
610    pub fn focus(&self, window: &mut Window, cx: &mut App) {
611        window.focus(self, cx)
612    }
613
614    /// Obtains whether the element associated with this handle is currently focused.
615    pub fn is_focused(&self, window: &Window) -> bool {
616        self.id.is_focused(window)
617    }
618
619    /// Obtains whether the element associated with this handle contains the focused
620    /// element or is itself focused.
621    pub fn contains_focused(&self, window: &Window, cx: &App) -> bool {
622        self.id.contains_focused(window, cx)
623    }
624
625    /// Obtains whether the element associated with this handle is contained within the
626    /// focused element or is itself focused.
627    pub fn within_focused(&self, window: &Window, cx: &mut App) -> bool {
628        self.id.within_focused(window, cx)
629    }
630
631    /// Obtains whether this handle contains the given handle in the most recently rendered frame.
632    pub fn contains(&self, other: &Self, window: &Window) -> bool {
633        self.id.contains(other.id, window)
634    }
635
636    /// Dispatch an action on the element that rendered this focus handle
637    pub fn dispatch_action(&self, action: &dyn Action, window: &mut Window, cx: &mut App) {
638        if let Some(node_id) = window
639            .rendered_frame
640            .dispatch_tree
641            .focusable_node_id(self.id)
642        {
643            window.dispatch_action_on_node(node_id, action, cx)
644        }
645    }
646}
647
648impl Clone for FocusHandle {
649    fn clone(&self) -> Self {
650        Self::for_id(self.id, &self.handles).unwrap()
651    }
652}
653
654impl PartialEq for FocusHandle {
655    fn eq(&self, other: &Self) -> bool {
656        self.id == other.id
657    }
658}
659
660impl Eq for FocusHandle {}
661
662impl Drop for FocusHandle {
663    fn drop(&mut self) {
664        let handles = self.handles.upgradable_read();
665        let focus = handles.handles.get(self.id).expect("focus handle missing");
666        let previous_count = focus.ref_count.fetch_sub(1, SeqCst);
667        assert_ne!(previous_count, 0, "over-released focus handle");
668        if previous_count == 1 {
669            RwLockUpgradableReadGuard::upgrade(handles)
670                .dropped_handles
671                .push(self.id);
672        }
673    }
674}
675
676/// A weak reference to a focus handle.
677#[derive(Clone, Debug)]
678pub struct WeakFocusHandle {
679    pub(crate) id: FocusId,
680    pub(crate) handles: Weak<RwLock<FocusMap>>,
681}
682
683impl WeakFocusHandle {
684    /// Attempts to upgrade the [WeakFocusHandle] to a [FocusHandle].
685    pub fn upgrade(&self) -> Option<FocusHandle> {
686        let handles = self.handles.upgrade()?;
687        FocusHandle::for_id(self.id, &handles)
688    }
689}
690
691impl PartialEq for WeakFocusHandle {
692    fn eq(&self, other: &WeakFocusHandle) -> bool {
693        self.id == other.id
694    }
695}
696
697impl Eq for WeakFocusHandle {}
698
699impl PartialEq<FocusHandle> for WeakFocusHandle {
700    fn eq(&self, other: &FocusHandle) -> bool {
701        self.id == other.id
702    }
703}
704
705impl PartialEq<WeakFocusHandle> for FocusHandle {
706    fn eq(&self, other: &WeakFocusHandle) -> bool {
707        self.id == other.id
708    }
709}
710
711/// Focusable allows users of your view to easily
712/// focus it (using window.focus_view(cx, view))
713pub trait Focusable: 'static {
714    /// Returns the focus handle associated with this view.
715    fn focus_handle(&self, cx: &App) -> FocusHandle;
716}
717
718impl<V: Focusable> Focusable for Entity<V> {
719    fn focus_handle(&self, cx: &App) -> FocusHandle {
720        self.read(cx).focus_handle(cx)
721    }
722}
723
724/// ManagedView is a view (like a Modal, Popover, Menu, etc.)
725/// where the lifecycle of the view is handled by another view.
726pub trait ManagedView: Focusable + EventEmitter<DismissEvent> + Render {}
727
728impl<M: Focusable + EventEmitter<DismissEvent> + Render> ManagedView for M {}
729
730/// Emitted by implementers of [`ManagedView`] to indicate the view should be dismissed, such as when a view is presented as a modal.
731pub struct DismissEvent;
732
733type FrameCallback = Box<dyn FnOnce(&mut Window, &mut App)>;
734
735pub(crate) type AnyMouseListener =
736    Box<dyn FnMut(&dyn Any, DispatchPhase, &mut Window, &mut App) + 'static>;
737
738#[derive(Clone)]
739pub(crate) struct CursorStyleRequest {
740    pub(crate) hitbox_id: Option<HitboxId>,
741    pub(crate) style: CursorStyle,
742}
743
744#[derive(Default, Eq, PartialEq)]
745pub(crate) struct HitTest {
746    pub(crate) ids: SmallVec<[HitboxId; 8]>,
747    pub(crate) hover_hitbox_count: usize,
748}
749
750/// A type of window control area that corresponds to the platform window.
751#[derive(Clone, Copy, Debug, Eq, PartialEq)]
752pub enum WindowControlArea {
753    /// An area that allows dragging of the platform window.
754    Drag,
755    /// An area that allows closing of the platform window.
756    Close,
757    /// An area that allows maximizing of the platform window.
758    Max,
759    /// An area that allows minimizing of the platform window.
760    Min,
761}
762
763/// An identifier for a [Hitbox] which also includes [HitboxBehavior].
764#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
765pub struct HitboxId(u64);
766
767#[cfg(feature = "test-support")]
768impl HitboxId {
769    /// A placeholder HitboxId exclusively for integration testing API's that
770    /// need a hitbox but where the value of the hitbox does not matter. The
771    /// alternative is to make the Hitbox optional but that complicates the
772    /// implementation.
773    pub const fn placeholder() -> Self {
774        Self(0)
775    }
776}
777
778impl HitboxId {
779    /// Checks if the hitbox with this ID is currently hovered. Returns `false` during keyboard
780    /// input modality so that keyboard navigation suppresses hover highlights. Except when handling
781    /// `ScrollEvent`, this is typically what you want when determining whether to handle mouse
782    /// events or paint hover styles.
783    ///
784    /// See [`Hitbox::is_hovered`] for details.
785    pub fn is_hovered(self, window: &Window) -> bool {
786        // If this hitbox has captured the pointer, it's always considered hovered
787        if window.captured_hitbox == Some(self) {
788            return true;
789        }
790        if window.last_input_was_keyboard() {
791            return false;
792        }
793        self.hit_test(window)
794    }
795
796    /// Checks if the hitbox with this ID is currently hovered, regardless of the last
797    /// input modality used.
798    ///
799    /// See [`HitboxId::is_hovered`] for more details.
800    pub(crate) fn is_hovered_ignoring_last_input(self, window: &Window) -> bool {
801        // If this hitbox has captured the pointer, it's always considered hovered
802        if window.captured_hitbox == Some(self) {
803            return true;
804        }
805        self.hit_test(window)
806    }
807
808    fn hit_test(self, window: &Window) -> bool {
809        let hit_test = &window.mouse_hit_test;
810        for id in hit_test.ids.iter().take(hit_test.hover_hitbox_count) {
811            if self == *id {
812                return true;
813            }
814        }
815        false
816    }
817
818    /// Checks if the hitbox with this ID contains the mouse and should handle scroll events.
819    /// Typically this should only be used when handling `ScrollEvent`, and otherwise
820    /// `is_hovered` should be used. See the documentation of `Hitbox::is_hovered` for details about
821    /// this distinction.
822    pub fn should_handle_scroll(self, window: &Window) -> bool {
823        window.mouse_hit_test.ids.contains(&self)
824    }
825
826    fn next(self) -> HitboxId {
827        HitboxId(self.0.wrapping_add(1))
828    }
829}
830
831/// A rectangular region that potentially blocks hitboxes inserted prior.
832/// See [Window::insert_hitbox] for more details.
833#[derive(Clone, Debug, Deref)]
834pub struct Hitbox {
835    /// A unique identifier for the hitbox.
836    pub id: HitboxId,
837    /// The bounds of the hitbox.
838    #[deref]
839    pub bounds: Bounds<Pixels>,
840    /// The content mask when the hitbox was inserted.
841    pub content_mask: ContentMask<Pixels>,
842    /// Flags that specify hitbox behavior.
843    pub behavior: HitboxBehavior,
844}
845
846impl Hitbox {
847    /// Checks if the hitbox is currently hovered. Returns `false` during keyboard input modality
848    /// so that keyboard navigation suppresses hover highlights. Except when handling
849    /// `ScrollEvent`, this is typically what you want when determining whether to handle mouse
850    /// events or paint hover styles.
851    ///
852    /// This can return `false` even when the hitbox contains the mouse, if a hitbox in front of
853    /// this sets `HitboxBehavior::BlockMouse` (`InteractiveElement::occlude`) or
854    /// `HitboxBehavior::BlockMouseExceptScroll` (`InteractiveElement::block_mouse_except_scroll`),
855    /// or if the current input modality is keyboard (see [`Window::last_input_was_keyboard`]).
856    ///
857    /// Handling of `ScrollEvent` should typically use `should_handle_scroll` instead.
858    /// Concretely, this is due to use-cases like overlays that cause the elements under to be
859    /// non-interactive while still allowing scrolling. More abstractly, this is because
860    /// `is_hovered` is about element interactions directly under the mouse - mouse moves, clicks,
861    /// hover styling, etc. In contrast, scrolling is about finding the current outer scrollable
862    /// container.
863    pub fn is_hovered(&self, window: &Window) -> bool {
864        self.id.is_hovered(window)
865    }
866
867    /// Checks whether this hitbox would be hovered at `position`, regardless of the current input
868    /// modality or mouse position.
869    pub fn is_hovered_at(&self, position: Point<Pixels>, window: &Window) -> bool {
870        let hit_test = window.rendered_frame.hit_test(position);
871        hit_test
872            .ids
873            .iter()
874            .take(hit_test.hover_hitbox_count)
875            .any(|id| self.id == *id)
876    }
877
878    /// Checks if the hitbox contains the mouse and should handle scroll events. Typically this
879    /// should only be used when handling `ScrollEvent`, and otherwise `is_hovered` should be
880    /// used. See the documentation of `Hitbox::is_hovered` for details about this distinction.
881    ///
882    /// This can return `false` even when the hitbox contains the mouse, if a hitbox in front of
883    /// this sets `HitboxBehavior::BlockMouse` (`InteractiveElement::occlude`).
884    pub fn should_handle_scroll(&self, window: &Window) -> bool {
885        self.id.should_handle_scroll(window)
886    }
887}
888
889/// How the hitbox affects mouse behavior.
890#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
891pub enum HitboxBehavior {
892    /// Normal hitbox mouse behavior, doesn't affect mouse handling for other hitboxes.
893    #[default]
894    Normal,
895
896    /// All hitboxes behind this hitbox will be ignored and so will have `hitbox.is_hovered() ==
897    /// false` and `hitbox.should_handle_scroll() == false`. Typically for elements this causes
898    /// skipping of all mouse events, hover styles, and tooltips. This flag is set by
899    /// [`InteractiveElement::occlude`].
900    ///
901    /// For mouse handlers that check those hitboxes, this behaves the same as registering a
902    /// bubble-phase handler for every mouse event type:
903    ///
904    /// ```ignore
905    /// window.on_mouse_event(move |_: &EveryMouseEventTypeHere, phase, window, cx| {
906    ///     if phase == DispatchPhase::Capture && hitbox.is_hovered(window) {
907    ///         cx.stop_propagation();
908    ///     }
909    /// })
910    /// ```
911    ///
912    /// This has effects beyond event handling - any use of hitbox checking, such as hover
913    /// styles and tooltips. These other behaviors are the main point of this mechanism. An
914    /// alternative might be to not affect mouse event handling - but this would allow
915    /// inconsistent UI where clicks and moves interact with elements that are not considered to
916    /// be hovered.
917    BlockMouse,
918
919    /// All hitboxes behind this hitbox will have `hitbox.is_hovered() == false`, even when
920    /// `hitbox.should_handle_scroll() == true`. Typically for elements this causes all mouse
921    /// interaction except scroll events to be ignored - see the documentation of
922    /// [`Hitbox::is_hovered`] for details. This flag is set by
923    /// [`InteractiveElement::block_mouse_except_scroll`].
924    ///
925    /// For mouse handlers that check those hitboxes, this behaves the same as registering a
926    /// bubble-phase handler for every mouse event type **except** `ScrollEvent`:
927    ///
928    /// ```ignore
929    /// window.on_mouse_event(move |_: &EveryMouseEventTypeExceptScroll, phase, window, cx| {
930    ///     if phase == DispatchPhase::Bubble && hitbox.should_handle_scroll(window) {
931    ///         cx.stop_propagation();
932    ///     }
933    /// })
934    /// ```
935    ///
936    /// See the documentation of [`Hitbox::is_hovered`] for details of why `ScrollEvent` is
937    /// handled differently than other mouse events. If also blocking these scroll events is
938    /// desired, then a `cx.stop_propagation()` handler like the one above can be used.
939    ///
940    /// This has effects beyond event handling - this affects any use of `is_hovered`, such as
941    /// hover styles and tooltips. These other behaviors are the main point of this mechanism.
942    /// An alternative might be to not affect mouse event handling - but this would allow
943    /// inconsistent UI where clicks and moves interact with elements that are not considered to
944    /// be hovered.
945    BlockMouseExceptScroll,
946}
947
948/// An identifier for a tooltip.
949#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
950pub struct TooltipId(usize);
951
952impl TooltipId {
953    /// Checks if the tooltip is currently hovered.
954    pub fn is_hovered(&self, window: &Window) -> bool {
955        window
956            .tooltip_bounds
957            .as_ref()
958            .is_some_and(|tooltip_bounds| {
959                tooltip_bounds.id == *self
960                    && tooltip_bounds.bounds.contains(&window.mouse_position())
961            })
962    }
963}
964
965pub(crate) struct TooltipBounds {
966    id: TooltipId,
967    bounds: Bounds<Pixels>,
968}
969
970#[derive(Clone)]
971pub(crate) struct TooltipRequest {
972    id: TooltipId,
973    tooltip: AnyTooltip,
974}
975
976/// The ids of the elements being drawn, root first, with the hash of every
977/// prefix alongside: a [`GlobalElementId`] for the current element is then
978/// the ids cloned out and the hash on top of the stack, without walking the
979/// path — the ids of every ancestor, string names byte by byte — for each
980/// element on every frame.
981#[derive(Clone, Default)]
982pub(crate) struct ElementIdStack {
983    ids: SmallVec<[ElementId; 32]>,
984    hashes: SmallVec<[u64; 32]>,
985}
986
987impl ElementIdStack {
988    pub(crate) fn push(&mut self, id: ElementId) {
989        self.hashes.push(crate::extend_path_hash(self.hash(), &id));
990        self.ids.push(id);
991    }
992
993    pub(crate) fn pop(&mut self) -> Option<ElementId> {
994        self.hashes.pop();
995        self.ids.pop()
996    }
997
998    pub(crate) fn clear(&mut self) {
999        self.ids.clear();
1000        self.hashes.clear();
1001    }
1002
1003    /// The hash of the whole path on the stack.
1004    fn hash(&self) -> u64 {
1005        self.hashes
1006            .last()
1007            .copied()
1008            .unwrap_or(crate::EMPTY_PATH_HASH)
1009    }
1010
1011    pub(crate) fn global_id(&self) -> GlobalElementId {
1012        GlobalElementId::with_hash(&self.ids, self.hash())
1013    }
1014}
1015
1016impl std::ops::Deref for ElementIdStack {
1017    type Target = [ElementId];
1018
1019    fn deref(&self) -> &Self::Target {
1020        &self.ids
1021    }
1022}
1023
1024#[derive(Clone)]
1025pub(crate) struct GlyphBrushCacheKey {
1026    identity: Arc<()>,
1027    bounds: Bounds<Pixels>,
1028}
1029impl PartialEq for GlyphBrushCacheKey {
1030    fn eq(&self, other: &Self) -> bool {
1031        Arc::ptr_eq(&self.identity, &other.identity) && self.bounds == other.bounds
1032    }
1033}
1034
1035pub(crate) struct DeferredDraw {
1036    current_view: EntityId,
1037    priority: usize,
1038    parent_node: DispatchNodeId,
1039    element_id_stack: ElementIdStack,
1040    text_style_stack: Vec<TextStyleRefinement>,
1041    glyph_brush_stack: Vec<(Arc<dyn crate::GlyphBrush>, Bounds<Pixels>)>,
1042    content_mask: Option<ContentMask<Pixels>>,
1043    rem_size: Pixels,
1044    element: Option<AnyElement>,
1045    absolute_offset: Point<Pixels>,
1046    prepaint_range: Range<PrepaintStateIndex>,
1047    paint_range: Range<PaintIndex>,
1048}
1049
1050pub(crate) struct Frame {
1051    pub(crate) focus: Option<FocusId>,
1052    pub(crate) window_active: bool,
1053    pub(crate) element_states: FxHashMap<(GlobalElementId, TypeId), ElementStateBox>,
1054    accessed_element_states: Vec<(GlobalElementId, TypeId)>,
1055    pub(crate) mouse_listeners: Vec<Option<AnyMouseListener>>,
1056    pub(crate) dispatch_tree: DispatchTree,
1057    pub(crate) scene: Scene,
1058    pub(crate) hitboxes: Vec<Hitbox>,
1059    pub(crate) window_control_hitboxes: Vec<(WindowControlArea, Hitbox)>,
1060    pub(crate) deferred_draws: Vec<DeferredDraw>,
1061    pub(crate) input_handlers: Vec<Option<PlatformInputHandler>>,
1062    pub(crate) tooltip_requests: Vec<Option<TooltipRequest>>,
1063    pub(crate) cursor_styles: Vec<CursorStyleRequest>,
1064    #[cfg(any(test, feature = "test-support"))]
1065    pub(crate) debug_bounds: FxHashMap<String, Bounds<Pixels>>,
1066    #[cfg(any(test, feature = "test-support"))]
1067    debug_bounds_records: Vec<(String, Bounds<Pixels>)>,
1068    #[cfg(debug_assertions)]
1069    pub(crate) next_inspector_instance_ids: FxHashMap<Rc<crate::InspectorElementPath>, usize>,
1070    #[cfg(debug_assertions)]
1071    pub(crate) inspector_hitboxes: FxHashMap<HitboxId, crate::InspectorElementId>,
1072    pub(crate) tab_stops: TabStopMap,
1073}
1074
1075#[derive(Clone, Default)]
1076pub(crate) struct PrepaintStateIndex {
1077    hitboxes_index: usize,
1078    tooltips_index: usize,
1079    deferred_draws_index: usize,
1080    dispatch_tree_index: usize,
1081    accessed_element_states_index: usize,
1082    line_layout_index: LineLayoutIndex,
1083}
1084
1085#[derive(Clone, Default)]
1086pub(crate) struct PaintIndex {
1087    scene_index: usize,
1088    #[cfg(any(test, feature = "test-support"))]
1089    debug_bounds_index: usize,
1090    mouse_listeners_index: usize,
1091    input_handlers_index: usize,
1092    cursor_styles_index: usize,
1093    accessed_element_states_index: usize,
1094    tab_handle_index: usize,
1095    line_layout_index: LineLayoutIndex,
1096}
1097
1098impl Frame {
1099    #[cfg(any(test, feature = "test-support"))]
1100    pub(crate) fn record_debug_bounds(&mut self, selector: String, bounds: Bounds<Pixels>) {
1101        self.debug_bounds.insert(selector.clone(), bounds);
1102        self.debug_bounds_records.push((selector, bounds));
1103    }
1104
1105    pub(crate) fn new(dispatch_tree: DispatchTree) -> Self {
1106        Frame {
1107            focus: None,
1108            window_active: false,
1109            element_states: FxHashMap::default(),
1110            accessed_element_states: Vec::new(),
1111            mouse_listeners: Vec::new(),
1112            dispatch_tree,
1113            scene: Scene::default(),
1114            hitboxes: Vec::new(),
1115            window_control_hitboxes: Vec::new(),
1116            deferred_draws: Vec::new(),
1117            input_handlers: Vec::new(),
1118            tooltip_requests: Vec::new(),
1119            cursor_styles: Vec::new(),
1120
1121            #[cfg(any(test, feature = "test-support"))]
1122            debug_bounds: FxHashMap::default(),
1123            #[cfg(any(test, feature = "test-support"))]
1124            debug_bounds_records: Vec::new(),
1125
1126            #[cfg(debug_assertions)]
1127            next_inspector_instance_ids: FxHashMap::default(),
1128
1129            #[cfg(debug_assertions)]
1130            inspector_hitboxes: FxHashMap::default(),
1131            tab_stops: TabStopMap::default(),
1132        }
1133    }
1134
1135    pub(crate) fn clear(&mut self) {
1136        self.element_states.clear();
1137        self.accessed_element_states.clear();
1138        self.mouse_listeners.clear();
1139        self.dispatch_tree.clear();
1140        self.scene.clear();
1141        self.input_handlers.clear();
1142        self.tooltip_requests.clear();
1143        self.cursor_styles.clear();
1144        self.hitboxes.clear();
1145        self.window_control_hitboxes.clear();
1146        self.deferred_draws.clear();
1147        self.tab_stops.clear();
1148        self.focus = None;
1149
1150        #[cfg(any(test, feature = "test-support"))]
1151        {
1152            self.debug_bounds.clear();
1153            self.debug_bounds_records.clear();
1154        }
1155
1156        #[cfg(debug_assertions)]
1157        {
1158            self.next_inspector_instance_ids.clear();
1159            self.inspector_hitboxes.clear();
1160        }
1161    }
1162
1163    pub(crate) fn cursor_style(&self, window: &Window) -> Option<CursorStyle> {
1164        self.cursor_styles
1165            .iter()
1166            .rev()
1167            .fold_while(None, |style, request| match request.hitbox_id {
1168                None => Done(Some(request.style)),
1169                Some(hitbox_id) => Continue(style.or_else(|| {
1170                    hitbox_id
1171                        .is_hovered_ignoring_last_input(window)
1172                        .then_some(request.style)
1173                })),
1174            })
1175            .into_inner()
1176    }
1177
1178    pub(crate) fn hit_test(&self, position: Point<Pixels>) -> HitTest {
1179        let mut set_hover_hitbox_count = false;
1180        let mut hit_test = HitTest::default();
1181        for hitbox in self.hitboxes.iter().rev() {
1182            let bounds = hitbox.bounds.intersect(&hitbox.content_mask.bounds);
1183            if bounds.contains(&position) {
1184                hit_test.ids.push(hitbox.id);
1185                if !set_hover_hitbox_count
1186                    && hitbox.behavior == HitboxBehavior::BlockMouseExceptScroll
1187                {
1188                    hit_test.hover_hitbox_count = hit_test.ids.len();
1189                    set_hover_hitbox_count = true;
1190                }
1191                if hitbox.behavior == HitboxBehavior::BlockMouse {
1192                    break;
1193                }
1194            }
1195        }
1196        if !set_hover_hitbox_count {
1197            hit_test.hover_hitbox_count = hit_test.ids.len();
1198        }
1199        hit_test
1200    }
1201
1202    pub(crate) fn focus_path(&self) -> SmallVec<[FocusId; 8]> {
1203        self.focus
1204            .map(|focus_id| self.dispatch_tree.focus_path(focus_id))
1205            .unwrap_or_default()
1206    }
1207
1208    pub(crate) fn finish(&mut self, prev_frame: &mut Self) {
1209        for element_state_key in &self.accessed_element_states {
1210            if let Some((element_state_key, element_state)) =
1211                prev_frame.element_states.remove_entry(element_state_key)
1212            {
1213                self.element_states.insert(element_state_key, element_state);
1214            }
1215        }
1216
1217        self.scene.finish();
1218    }
1219}
1220
1221#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
1222enum InputModality {
1223    Mouse,
1224    Keyboard,
1225    Touch,
1226}
1227
1228/// Holds the state for a specific window.
1229pub struct Window {
1230    pub(crate) handle: AnyWindowHandle,
1231    pub(crate) invalidator: WindowInvalidator,
1232    pub(crate) removed: bool,
1233    pub(crate) platform_window: Box<dyn PlatformWindow>,
1234    pub(crate) display_id: Option<DisplayId>,
1235    pub(crate) display_observers: SingleSubscriberSet<AnyObserver>,
1236    is_resizable: bool,
1237    is_minimizable: bool,
1238    sprite_atlas: Arc<dyn PlatformAtlas>,
1239    text_system: Rc<WindowTextSystem>,
1240    text_rendering_mode: Rc<Cell<TextRenderingMode>>,
1241    rem_size: Pixels,
1242    /// The stack of override values for the window's rem size.
1243    ///
1244    /// This is used by `with_rem_size` to allow rendering an element tree with
1245    /// a given rem size.
1246    rem_size_override_stack: SmallVec<[Pixels; 8]>,
1247    pub(crate) viewport_size: Size<Pixels>,
1248    layout_engine: Option<TaffyLayoutEngine>,
1249    pub(crate) root: Option<AnyView>,
1250    pub(crate) element_id_stack: ElementIdStack,
1251    pub(crate) text_style_stack: Vec<TextStyleRefinement>,
1252    glyph_brush_stack: Vec<(Arc<dyn crate::GlyphBrush>, Bounds<Pixels>)>,
1253    pub(crate) rendered_entity_stack: Vec<EntityId>,
1254    pub(crate) element_offset_stack: Vec<Point<Pixels>>,
1255    pub(crate) element_opacity: f32,
1256    layer_capture_depth: usize,
1257    layer_capture_sources: Vec<Bounds<Pixels>>,
1258    layer_capture_clips: Vec<Bounds<Pixels>>,
1259    pub(crate) content_mask_stack: Vec<ContentMask<Pixels>>,
1260    pub(crate) requested_autoscroll: Option<Bounds<Pixels>>,
1261    /// The [`TextInputConfiguration`] most recently forwarded to the platform
1262    /// window, so that only actual changes are forwarded (reconfiguring a live
1263    /// input session can restart the IME connection).
1264    last_text_input_configuration: Option<TextInputConfiguration>,
1265    focused_text_input: Option<FocusId>,
1266    pub(crate) image_cache_stack: Vec<AnyImageCache>,
1267    pub(crate) rendered_frame: Frame,
1268    pub(crate) next_frame: Frame,
1269    next_hitbox_id: HitboxId,
1270    pub(crate) next_tooltip_id: TooltipId,
1271    pub(crate) tooltip_bounds: Option<TooltipBounds>,
1272    pub(crate) next_frame_callbacks: Rc<RefCell<Vec<FrameCallback>>>,
1273    pub(crate) dirty_views: FxHashSet<EntityId>,
1274    focus_listeners: SingleSubscriberSet<AnyWindowFocusListener>,
1275    pub(crate) focus_lost_listeners: SingleSubscriberSet<AnyObserver>,
1276    focus_lost_path: SmallVec<[FocusId; 8]>,
1277    default_prevented: bool,
1278    mouse_position: Point<Pixels>,
1279    mouse_hit_test: HitTest,
1280    modifiers: Modifiers,
1281    capslock: Capslock,
1282    scale_factor: f32,
1283    pub(crate) bounds_observers: SingleSubscriberSet<AnyObserver>,
1284    appearance: WindowAppearance,
1285    pub(crate) appearance_observers: SingleSubscriberSet<AnyObserver>,
1286    pub(crate) button_layout_observers: SingleSubscriberSet<AnyObserver>,
1287    active: Rc<Cell<bool>>,
1288    visibility: WindowVisibility,
1289    pub(crate) visibility_observers:
1290        SingleSubscriberSet<Box<dyn FnMut(WindowVisibility, &mut Window, &mut App) -> bool>>,
1291    hovered: Rc<Cell<bool>>,
1292    pub(crate) needs_present: Rc<Cell<bool>>,
1293    /// Tracks recent input event timestamps to determine if input is arriving at a high rate.
1294    /// Used to selectively enable VRR optimization only when input rate exceeds 60fps.
1295    pub(crate) input_rate_tracker: Rc<RefCell<InputRateTracker>>,
1296    #[cfg(feature = "profiler")]
1297    pub(crate) window_profiler: profiler::WindowProfiler,
1298    last_input_modality: InputModality,
1299    touch_gestures: TouchGestureRecognizer,
1300    touch_prediction_enabled: bool,
1301    long_press_timer: Option<Task<()>>,
1302    long_press_capture: Option<EntityId>,
1303    pub(crate) refreshing: bool,
1304    pub(crate) activation_observers: SingleSubscriberSet<AnyObserver>,
1305    pub(crate) focus: Option<FocusId>,
1306    focus_enabled: bool,
1307    /// Incremented every time focus moves. Used to invalidate a
1308    /// pending keyboard activation state when focus changes.
1309    pub(crate) focus_generation: u64,
1310    pending_input: Option<PendingInput>,
1311    pending_modifier: ModifierState,
1312    pub(crate) pending_input_observers: SingleSubscriberSet<AnyObserver>,
1313    prompt: Option<RenderablePromptHandle>,
1314    pub(crate) client_inset: Option<Pixels>,
1315    /// The hitbox that has captured the pointer, if any.
1316    /// While captured, mouse events route to this hitbox regardless of hit testing.
1317    captured_hitbox: Option<HitboxId>,
1318    #[cfg(debug_assertions)]
1319    inspector: Option<Entity<Inspector>>,
1320    #[cfg(feature = "profiler")]
1321    debug_frame_overlay: crate::debug_overlay::DebugFrameOverlay,
1322    pub(crate) a11y: A11y,
1323}
1324
1325#[derive(Clone, Debug, Default)]
1326struct ModifierState {
1327    modifiers: Modifiers,
1328    saw_other_input: bool,
1329}
1330
1331/// Tracks input event timestamps to determine if input is arriving at a high rate.
1332/// Used for selective VRR (Variable Refresh Rate) optimization.
1333#[derive(Clone, Debug)]
1334pub(crate) struct InputRateTracker {
1335    timestamps: Vec<Instant>,
1336    window: Duration,
1337    inputs_per_second: u32,
1338    sustain_until: Instant,
1339    sustain_duration: Duration,
1340}
1341
1342const THIRTY_FPS_INTERVAL: Duration = Duration::from_micros(33333);
1343const SIXTY_FPS_INTERVAL: Duration = Duration::from_micros(16667);
1344const FRAME_INTERVAL_TOLERANCE: Duration = Duration::from_millis(1);
1345
1346/// Display-link timestamps can straddle a target interval by fractions of a
1347/// millisecond. Accepting that callback preserves an even display-frame divisor
1348/// instead of occasionally waiting for an additional refresh.
1349fn frame_request_arrived_too_early(elapsed: Duration, minimum_interval: Duration) -> bool {
1350    elapsed < minimum_interval.saturating_sub(FRAME_INTERVAL_TOLERANCE)
1351}
1352
1353fn minimum_frame_interval(
1354    should_throttle: bool,
1355    inactive_without_high_rate_input: bool,
1356    inactive_frame_interval: Option<Duration>,
1357    thermal_state: ThermalState,
1358    power_mode: crate::PowerMode,
1359) -> Option<Duration> {
1360    let low_power_mode_enabled = power_mode == crate::PowerMode::LowPower;
1361    if !should_throttle {
1362        None
1363    } else if inactive_without_high_rate_input {
1364        match (inactive_frame_interval, low_power_mode_enabled) {
1365            (Some(inactive_frame_interval), true) => {
1366                Some(inactive_frame_interval.max(THIRTY_FPS_INTERVAL))
1367            }
1368            (inactive_frame_interval, false) => inactive_frame_interval,
1369            (None, true) => Some(THIRTY_FPS_INTERVAL),
1370        }
1371    } else if low_power_mode_enabled {
1372        Some(THIRTY_FPS_INTERVAL)
1373    } else if matches!(
1374        thermal_state,
1375        ThermalState::Critical | ThermalState::Serious
1376    ) {
1377        Some(SIXTY_FPS_INTERVAL)
1378    } else {
1379        None
1380    }
1381}
1382
1383impl Default for InputRateTracker {
1384    fn default() -> Self {
1385        Self {
1386            timestamps: Vec::new(),
1387            window: Duration::from_millis(100),
1388            inputs_per_second: 60,
1389            sustain_until: Instant::now(),
1390            sustain_duration: Duration::from_secs(1),
1391        }
1392    }
1393}
1394
1395impl InputRateTracker {
1396    pub fn record_input(&mut self) {
1397        let now = Instant::now();
1398        self.timestamps.push(now);
1399        self.prune_old_timestamps(now);
1400
1401        let min_events = self.inputs_per_second as u128 * self.window.as_millis() / 1000;
1402        if self.timestamps.len() as u128 >= min_events {
1403            self.sustain_until = now + self.sustain_duration;
1404        }
1405    }
1406
1407    pub fn is_high_rate(&self) -> bool {
1408        Instant::now() < self.sustain_until
1409    }
1410
1411    fn prune_old_timestamps(&mut self, now: Instant) {
1412        self.timestamps
1413            .retain(|&t| now.duration_since(t) <= self.window);
1414    }
1415}
1416
1417#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1418pub(crate) enum DrawPhase {
1419    None,
1420    Prepaint,
1421    Paint,
1422    Focus,
1423}
1424
1425pub(crate) const PENDING_INPUT_TIMEOUT: Duration = Duration::from_secs(1);
1426
1427/// Pending input for a potential multi-stroke key binding.
1428pub struct PendingInputStatus<'a> {
1429    keystrokes: &'a [Keystroke],
1430    timeout: Option<PendingInputTimeoutStatus>,
1431}
1432
1433impl<'a> PendingInputStatus<'a> {
1434    /// Returns the keystrokes entered so far.
1435    pub fn keystrokes(&self) -> &'a [Keystroke] {
1436        self.keystrokes
1437    }
1438
1439    /// Returns the timeout state for flushing this input, if it needs a timeout.
1440    pub fn timeout(&self) -> Option<PendingInputTimeoutStatus> {
1441        self.timeout
1442    }
1443}
1444
1445/// The timeout state for pending input.
1446#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1447pub struct PendingInputTimeoutStatus {
1448    duration: Duration,
1449    remaining: Duration,
1450    started_at: Option<Instant>,
1451    paused: bool,
1452}
1453
1454impl PendingInputTimeoutStatus {
1455    /// Returns the full timeout duration.
1456    pub fn duration(&self) -> Duration {
1457        self.duration
1458    }
1459
1460    /// Returns the duration remaining before pending input is flushed.
1461    pub fn remaining(&self, cx: &App) -> Duration {
1462        self.started_at
1463            .map(|started_at| {
1464                self.remaining
1465                    .saturating_sub(cx.background_executor().now() - started_at)
1466            })
1467            .unwrap_or(self.remaining)
1468    }
1469
1470    /// Returns whether the timeout is paused.
1471    pub fn is_paused(&self) -> bool {
1472        self.paused
1473    }
1474}
1475
1476#[derive(Debug)]
1477struct PendingInputTimeout {
1478    duration: Duration,
1479    remaining: Duration,
1480    state: PendingInputTimeoutState,
1481}
1482
1483#[derive(Debug)]
1484enum PendingInputTimeoutState {
1485    Running { started_at: Instant, task: Task<()> },
1486    Paused { pause: PendingInputTimeoutPause },
1487}
1488
1489#[derive(Debug)]
1490struct PendingInputTimeoutPause {
1491    owner_id: EntityId,
1492    _release_subscription: Subscription,
1493}
1494
1495impl PendingInputTimeout {
1496    fn is_paused(&self) -> bool {
1497        matches!(&self.state, PendingInputTimeoutState::Paused { .. })
1498    }
1499
1500    fn pause(&mut self, pause: PendingInputTimeoutPause, now: Instant) -> bool {
1501        match std::mem::replace(&mut self.state, PendingInputTimeoutState::Paused { pause }) {
1502            PendingInputTimeoutState::Running { started_at, task } => {
1503                self.remaining = self.remaining.saturating_sub(now - started_at);
1504                drop(task);
1505                true
1506            }
1507            previous_state @ PendingInputTimeoutState::Paused { .. } => {
1508                self.state = previous_state;
1509                false
1510            }
1511        }
1512    }
1513
1514    fn pause_owner_id(&self) -> Option<EntityId> {
1515        match &self.state {
1516            PendingInputTimeoutState::Running { .. } => None,
1517            PendingInputTimeoutState::Paused { pause } => Some(pause.owner_id),
1518        }
1519    }
1520
1521    fn resume(&mut self, owner_id: EntityId, started_at: Instant, task: Task<()>) -> bool {
1522        match std::mem::replace(
1523            &mut self.state,
1524            PendingInputTimeoutState::Running { started_at, task },
1525        ) {
1526            PendingInputTimeoutState::Paused { pause } if pause.owner_id == owner_id => true,
1527            previous_state => {
1528                self.state = previous_state;
1529                false
1530            }
1531        }
1532    }
1533
1534    fn reset_duration(&mut self, duration: Duration) {
1535        self.duration = duration;
1536        self.remaining = duration;
1537    }
1538
1539    fn status(&self) -> PendingInputTimeoutStatus {
1540        let (started_at, paused) = match &self.state {
1541            PendingInputTimeoutState::Running { started_at, .. } => (Some(*started_at), false),
1542            PendingInputTimeoutState::Paused { .. } => (None, true),
1543        };
1544        PendingInputTimeoutStatus {
1545            duration: self.duration,
1546            remaining: self.remaining,
1547            started_at,
1548            paused,
1549        }
1550    }
1551}
1552
1553#[derive(Default, Debug)]
1554struct PendingInput {
1555    keystrokes: SmallVec<[Keystroke; 1]>,
1556    focus: Option<FocusId>,
1557    timeout: Option<PendingInputTimeout>,
1558}
1559
1560pub(crate) struct ElementStateBox {
1561    pub(crate) inner: Box<dyn Any>,
1562    #[cfg(debug_assertions)]
1563    pub(crate) type_name: &'static str,
1564}
1565
1566fn default_bounds(display_id: Option<DisplayId>, cx: &mut App) -> WindowBounds {
1567    // TODO, BUG: if you open a window with the currently active window
1568    // on the stack, this will erroneously fallback to `None`
1569    //
1570    // TODO these should be the initial window bounds not considering maximized/fullscreen
1571    let active_window_bounds = cx
1572        .active_window()
1573        .and_then(|w| w.update(cx, |_, window, _| window.window_bounds()).ok());
1574
1575    const CASCADE_OFFSET: f32 = 25.0;
1576
1577    let display = display_id
1578        .map(|id| cx.find_display(id))
1579        .unwrap_or_else(|| cx.primary_display());
1580
1581    let default_placement = || Bounds::new(point(px(0.), px(0.)), DEFAULT_WINDOW_SIZE);
1582
1583    // Use visible_bounds to exclude taskbar/dock areas
1584    let display_bounds = display
1585        .as_ref()
1586        .map(|d| d.visible_bounds())
1587        .unwrap_or_else(default_placement);
1588
1589    let (
1590        Bounds {
1591            origin: base_origin,
1592            size: base_size,
1593        },
1594        window_bounds_ctor,
1595    ): (_, fn(Bounds<Pixels>) -> WindowBounds) = match active_window_bounds {
1596        Some(bounds) => match bounds {
1597            WindowBounds::Windowed(bounds) => (bounds, WindowBounds::Windowed),
1598            WindowBounds::Maximized(bounds) => (bounds, WindowBounds::Maximized),
1599            WindowBounds::Fullscreen(bounds) => (bounds, WindowBounds::Fullscreen),
1600        },
1601        None => (
1602            display
1603                .as_ref()
1604                .map(|d| d.default_bounds())
1605                .unwrap_or_else(default_placement),
1606            WindowBounds::Windowed,
1607        ),
1608    };
1609
1610    let cascade_offset = point(px(CASCADE_OFFSET), px(CASCADE_OFFSET));
1611    let proposed_origin = base_origin + cascade_offset;
1612    let proposed_bounds = Bounds::new(proposed_origin, base_size);
1613
1614    let display_right = display_bounds.origin.x + display_bounds.size.width;
1615    let display_bottom = display_bounds.origin.y + display_bounds.size.height;
1616    let window_right = proposed_bounds.origin.x + proposed_bounds.size.width;
1617    let window_bottom = proposed_bounds.origin.y + proposed_bounds.size.height;
1618
1619    let fits_horizontally = window_right <= display_right;
1620    let fits_vertically = window_bottom <= display_bottom;
1621
1622    let final_origin = match (fits_horizontally, fits_vertically) {
1623        (true, true) => proposed_origin,
1624        (false, true) => point(display_bounds.origin.x, base_origin.y),
1625        (true, false) => point(base_origin.x, display_bounds.origin.y),
1626        (false, false) => display_bounds.origin,
1627    };
1628    window_bounds_ctor(Bounds::new(final_origin, base_size))
1629}
1630
1631impl Window {
1632    pub(crate) fn new(
1633        handle: AnyWindowHandle,
1634        options: WindowOptions,
1635        cx: &mut App,
1636    ) -> Result<Self> {
1637        let WindowOptions {
1638            window_bounds,
1639            titlebar,
1640            focus,
1641            show,
1642            kind,
1643            is_movable,
1644            app_owns_titlebar_drag,
1645            inactive_frame_interval,
1646            is_resizable,
1647            is_minimizable,
1648            display_id,
1649            window_background,
1650            app_id,
1651            window_min_size,
1652            window_decorations,
1653            #[cfg_attr(
1654                not(any(target_os = "linux", target_os = "freebsd")),
1655                allow(unused_variables)
1656            )]
1657            icon,
1658            #[cfg_attr(not(target_os = "macos"), allow(unused_variables))]
1659            tabbing_identifier,
1660            #[cfg_attr(not(target_os = "macos"), allow(unused_variables))]
1661            use_display_p3,
1662        } = options;
1663
1664        let initial_window_title = titlebar
1665            .as_ref()
1666            .and_then(|titlebar| titlebar.title.clone());
1667
1668        let window_bounds = window_bounds.unwrap_or_else(|| default_bounds(display_id, cx));
1669        let mut platform_window = cx.platform.open_window(
1670            handle,
1671            WindowParams {
1672                bounds: window_bounds.get_bounds(),
1673                titlebar,
1674                kind,
1675                is_movable,
1676                app_owns_titlebar_drag,
1677                is_resizable,
1678                is_minimizable,
1679                focus,
1680                show,
1681                display_id,
1682                window_min_size,
1683                app_id: app_id.clone(),
1684                icon,
1685                #[cfg(target_os = "macos")]
1686                tabbing_identifier,
1687                #[cfg(target_os = "macos")]
1688                use_display_p3,
1689            },
1690        )?;
1691
1692        let tab_bar_visible = platform_window.tab_bar_visible();
1693        SystemWindowTabController::init_visible(cx, tab_bar_visible);
1694        if let Some(tabs) = platform_window.tabbed_windows() {
1695            SystemWindowTabController::add_tab(cx, handle.window_id(), tabs);
1696        }
1697
1698        let display_id = platform_window.display().map(|display| display.id());
1699        let sprite_atlas = platform_window.sprite_atlas();
1700        let mouse_position = platform_window.mouse_position();
1701        let modifiers = platform_window.modifiers();
1702        let capslock = platform_window.capslock();
1703        let content_size = platform_window.content_size();
1704        let scale_factor = platform_window.scale_factor();
1705        let appearance = platform_window.appearance();
1706        let text_system = Rc::new(WindowTextSystem::new(cx.text_system().clone()));
1707        let invalidator = WindowInvalidator::new(handle.window_id());
1708        let active = Rc::new(Cell::new(platform_window.is_active()));
1709        let visibility = platform_window.visibility();
1710        #[cfg(feature = "profiler")]
1711        profiler::journal::record_window_visibility(handle.window_id(), visibility);
1712        let hovered = Rc::new(Cell::new(platform_window.is_hovered()));
1713        let needs_present = Rc::new(Cell::new(false));
1714        let next_frame_callbacks: Rc<RefCell<Vec<FrameCallback>>> = Default::default();
1715        let input_rate_tracker = Rc::new(RefCell::new(InputRateTracker::default()));
1716        let last_frame_time = Rc::new(Cell::new(None));
1717
1718        platform_window
1719            .request_decorations(window_decorations.unwrap_or(WindowDecorations::Server));
1720        platform_window.set_background_appearance(window_background);
1721
1722        match window_bounds {
1723            WindowBounds::Fullscreen(_) => platform_window.toggle_fullscreen(),
1724            WindowBounds::Maximized(_) => platform_window.zoom(),
1725            WindowBounds::Windowed(_) => {}
1726        }
1727
1728        let accessibility_force_disabled = cx.accessibility_force_disabled;
1729        let a11y_active_flag = Arc::new(AtomicBool::new(false));
1730
1731        #[cfg(not(target_family = "wasm"))]
1732        if !accessibility_force_disabled {
1733            let mut initial_root_node = accesskit::Node::new(accesskit::Role::Window);
1734            if let Some(title) = &initial_window_title {
1735                initial_root_node.set_label(title.to_string());
1736            }
1737            let initial_tree = accesskit::TreeUpdate {
1738                nodes: vec![(ROOT_NODE_ID, initial_root_node)],
1739                tree: Some(accesskit::Tree::new(ROOT_NODE_ID)),
1740                tree_id: accesskit::TreeId::ROOT,
1741                focus: ROOT_NODE_ID,
1742            };
1743            let (activation_sender, activation_receiver) = async_channel::unbounded::<()>();
1744            let (deactivation_sender, deactivation_receiver) = async_channel::unbounded::<()>();
1745            let (action_sender, action_receiver) =
1746                async_channel::unbounded::<accesskit::ActionRequest>();
1747
1748            platform_window.a11y_init(crate::A11yCallbacks {
1749                activation: {
1750                    let active_flag = a11y_active_flag.clone();
1751                    Box::new(move || {
1752                        log::info!("Accessibility activated");
1753                        active_flag.store(true, SeqCst);
1754                        activation_sender.send_blocking(()).log_err();
1755                        Some(initial_tree.clone())
1756                    })
1757                },
1758                action: Box::new(move |request| {
1759                    action_sender.send_blocking(request).log_err();
1760                }),
1761                deactivation: {
1762                    let active_flag = a11y_active_flag.clone();
1763                    Box::new(move || {
1764                        log::info!("Accessibility deactivated");
1765                        active_flag.store(false, SeqCst);
1766                        deactivation_sender.send_blocking(()).log_err();
1767                    })
1768                },
1769            });
1770
1771            // A11y can be activated at any time, and so we cannot compute a
1772            // correct `TreeUpdate` on-demand. When this happens, we return a
1773            // default empty `TreeUpdate`.
1774            //
1775            // So we force a new frame, which will then send a correct `TreeUpdate`.
1776            let mut async_cx = cx.to_async();
1777            cx.foreground_executor()
1778                .spawn(async move {
1779                    while activation_receiver.recv().await.is_ok() {
1780                        handle
1781                            .update(&mut async_cx, |_, window, _| window.refresh())
1782                            .log_err();
1783                    }
1784                })
1785                .detach();
1786
1787            let mut async_cx = cx.to_async();
1788            cx.foreground_executor()
1789                .spawn(async move {
1790                    while deactivation_receiver.recv().await.is_ok() {
1791                        handle
1792                            .update(&mut async_cx, |_, window, _| window.refresh())
1793                            .log_err();
1794                    }
1795                })
1796                .detach();
1797
1798            let mut async_cx = cx.to_async();
1799            cx.foreground_executor()
1800                .spawn(async move {
1801                    while let Ok(request) = action_receiver.recv().await {
1802                        handle
1803                            .update(&mut async_cx, |_, window, cx| {
1804                                window.handle_a11y_action(request, cx);
1805                            })
1806                            .log_err();
1807                    }
1808                })
1809                .detach();
1810        }
1811
1812        platform_window.on_close(Box::new({
1813            let window_id = handle.window_id();
1814            let cx = cx.to_async();
1815            move || {
1816                // Native destruction can re-enter while the app is borrowed.
1817                // Schedule both operations without borrowing the app here.
1818                cx.spawn(async move |cx| {
1819                    cx.update(|cx| {
1820                        // App-driven closure may already have removed the window.
1821                        if cx.windows.contains_key(window_id) {
1822                            handle
1823                                .update(cx, |_, window, _| window.remove_window())
1824                                .log_err();
1825                        }
1826                        SystemWindowTabController::remove_tab(cx, window_id);
1827                    });
1828                })
1829                .detach();
1830            }
1831        }));
1832        platform_window.on_request_frame(Box::new({
1833            let mut cx = cx.to_async();
1834            let invalidator = invalidator.clone();
1835            let active = active.clone();
1836            let needs_present = needs_present.clone();
1837            let next_frame_callbacks = next_frame_callbacks.clone();
1838            let input_rate_tracker = input_rate_tracker.clone();
1839            let mut deferred_force_render = false;
1840            move |request_frame_options| {
1841                #[cfg(feature = "profiler")]
1842                let (_foreground_turn, window_id) = {
1843                    let foreground_turn = profiler::journal::foreground_turn();
1844                    let window_id = handle.window_id();
1845                    profiler::journal::record_platform_signal(profiler::journal::PlatformSignal {
1846                        window_id,
1847                        signal_at: request_frame_options.signal_at,
1848                        handled_at: Instant::now(),
1849                        source: request_frame_options.signal_source,
1850                    });
1851                    (foreground_turn, window_id)
1852                };
1853                // This must be checked before accessing App: if this request
1854                // arrived re-entrantly while a draw is on this thread's stack
1855                // (e.g. via a nested message pump in the Windows window
1856                // procedure), drawing would nest draws, and even touching the
1857                // App would panic on its already-mutable borrow. Skip instead;
1858                // the platform leaves the window invalidated (or re-invalidates
1859                // it), so a fresh request arrives once the in-progress draw
1860                // unwinds. Remember force_render so the deferred frame still
1861                // bypasses the view cache.
1862                //
1863                // Returning here skips `complete_frame`, which on Wayland would
1864                // stall the window's frame callbacks (no `surface.commit()`) —
1865                // but calling it would hit the App borrow panic above, and this
1866                // branch is unreachable there in practice: only Windows pumps
1867                // platform events (and thus requests frames) mid-draw.
1868                if draw_in_progress() {
1869                    log::debug!("deferring re-entrant window draw request");
1870                    deferred_force_render |= request_frame_options.force_render;
1871                    #[cfg(feature = "profiler")]
1872                    profiler::journal::record_reentrant_frame_skipped(window_id, Instant::now());
1873                    return;
1874                }
1875                // Take the deferred flag first: `||` short-circuits, and leaving
1876                // the flag set when this request already forces a render would
1877                // force a second, redundant render on the next frame.
1878                let force_render =
1879                    mem::take(&mut deferred_force_render) || request_frame_options.force_render;
1880
1881                let power_state = handle
1882                    .update(&mut cx, |_, _, cx| (cx.thermal_state(), cx.power_mode()))
1883                    .log_err();
1884
1885                // Throttle frame rate based on conditions:
1886                // - Thermal pressure (Serious/Critical): cap to ~60fps
1887                // - Low power mode: cap to ~30fps
1888                // - Inactive window (not focused): use its configured frame interval
1889                let should_throttle = !request_frame_options.require_presentation
1890                    && (request_frame_options.force_render
1891                        || !next_frame_callbacks.borrow().is_empty());
1892                let inactive_without_high_rate_input = should_throttle
1893                    && !active.get()
1894                    && !input_rate_tracker.borrow_mut().is_high_rate();
1895                let (thermal_state, power_mode) =
1896                    power_state.unwrap_or((ThermalState::Nominal, crate::PowerMode::Unknown));
1897                let min_frame_interval = minimum_frame_interval(
1898                    should_throttle,
1899                    inactive_without_high_rate_input,
1900                    inactive_frame_interval,
1901                    thermal_state,
1902                    power_mode,
1903                );
1904
1905                let now = Instant::now();
1906                if let Some(min_interval) = min_frame_interval {
1907                    if let Some(last_frame) = last_frame_time.get()
1908                        && frame_request_arrived_too_early(
1909                            now.duration_since(last_frame),
1910                            min_interval,
1911                        )
1912                    {
1913                        // Don't lose a pending forced render to throttling.
1914                        deferred_force_render |= force_render;
1915                        // Deferred by throttling: ask demand-driven platforms to retry.
1916                        handle
1917                            .update(&mut cx, |_, window, _| {
1918                                window.platform_window.schedule_frame();
1919                            })
1920                            .log_err();
1921                        // The demand that entered this branch (a deferred forced
1922                        // render or pending next-frame callbacks) is still
1923                        // unserved; platforms that stop requesting frames for
1924                        // idle windows need a wakeup to deliver the retry.
1925                        invalidator.wake_platform();
1926                        #[cfg(feature = "profiler")]
1927                        profiler::journal::record_frame_skipped(
1928                            window_id,
1929                            Instant::now(),
1930                            if inactive_without_high_rate_input {
1931                                profiler::journal::FrameSkipReason::InactiveFrameRateLimit
1932                            } else if power_mode == crate::PowerMode::LowPower {
1933                                profiler::journal::FrameSkipReason::LowPowerFrameRateLimit
1934                            } else {
1935                                profiler::journal::FrameSkipReason::ThermalFrameRateLimit
1936                            },
1937                        );
1938                        return;
1939                    }
1940                }
1941                last_frame_time.set(Some(now));
1942
1943                let pending_next_frame_callbacks = next_frame_callbacks.take();
1944                if !pending_next_frame_callbacks.is_empty() {
1945                    handle
1946                        .update(&mut cx, |_, window, cx| {
1947                            for callback in pending_next_frame_callbacks {
1948                                callback(window, cx);
1949                            }
1950                        })
1951                        .log_err();
1952                }
1953
1954                // Keep presenting if input was recently arriving at a high rate (>= 60fps).
1955                // Once high-rate input is detected, we sustain presentation for 1 second
1956                // to prevent display underclocking during active input.
1957                let needs_present = request_frame_options.require_presentation
1958                    || needs_present.get()
1959                    || input_rate_tracker.borrow_mut().is_high_rate();
1960
1961                let should_draw = invalidator.is_dirty() || force_render;
1962                if should_draw {
1963                    measure("frame duration", || {
1964                        handle
1965                            .update(&mut cx, |_, window, cx| {
1966                                #[cfg(feature = "profiler")]
1967                                window
1968                                    .window_profiler
1969                                    .record_frame_signal(request_frame_options.signal_at);
1970                                if force_render {
1971                                    // Bypass cached view reuse so we don't replay stale
1972                                    // atlas tile references after a GPU device recovery.
1973                                    window.refresh();
1974                                }
1975                                let arena_clear_needed = window.draw(cx);
1976                                window.present();
1977                                arena_clear_needed.clear(cx);
1978                            })
1979                            .log_err();
1980                    })
1981                } else if needs_present {
1982                    handle
1983                        .update(&mut cx, |_, window, _| window.present())
1984                        .log_err();
1985                }
1986
1987                handle
1988                    .update(&mut cx, |_, window, _| {
1989                        if window.invalidator.is_dirty()
1990                            || !window.next_frame_callbacks.borrow().is_empty()
1991                        {
1992                            window.platform_window.schedule_frame();
1993                        }
1994                    })
1995                    .log_err();
1996
1997                // Platforms that stop requesting frames for idle windows only
1998                // deliver another request after a wakeup. If demand remains
1999                // after this frame (the window was re-invalidated mid-draw, or
2000                // animations scheduled next-frame callbacks), re-arm the frame
2001                // source explicitly.
2002                if invalidator.is_dirty() || !next_frame_callbacks.borrow().is_empty() {
2003                    invalidator.wake_platform();
2004                }
2005                #[cfg(feature = "profiler")]
2006                if !should_draw {
2007                    profiler::journal::record_frame_skipped(
2008                        window_id,
2009                        Instant::now(),
2010                        profiler::journal::FrameSkipReason::NoRenderNeeded,
2011                    );
2012                }
2013            }
2014        }));
2015        invalidator.set_platform_waker(platform_window.frame_waker());
2016        platform_window.on_visual_viewport_changed(Box::new({
2017            let mut cx = cx.to_async();
2018            move || {
2019                handle
2020                    .update(&mut cx, |_, window, _| window.refresh())
2021                    .log_err();
2022            }
2023        }));
2024        platform_window.on_insets_changed(Box::new({
2025            let mut cx = cx.to_async();
2026            move |_| {
2027                handle
2028                    .update(&mut cx, |_, window, _| window.refresh())
2029                    .log_err();
2030            }
2031        }));
2032        platform_window.on_resize(Box::new({
2033            let mut cx = cx.to_async();
2034            move |_, _| {
2035                handle
2036                    .update(&mut cx, |_, window, cx| window.bounds_changed(cx))
2037                    .log_err();
2038            }
2039        }));
2040        platform_window.on_moved(Box::new({
2041            let mut cx = cx.to_async();
2042            move || {
2043                handle
2044                    .update(&mut cx, |_, window, cx| window.bounds_changed(cx))
2045                    .log_err();
2046            }
2047        }));
2048        platform_window.on_display_changed(Box::new({
2049            let cx = cx.to_async();
2050            move || cx.update(|cx| Window::display_changed(handle, cx))
2051        }));
2052        platform_window.on_appearance_changed(Box::new({
2053            let cx = cx.to_async();
2054            let foreground_executor = cx.foreground_executor().clone();
2055            move || {
2056                let mut cx = cx.clone();
2057                // Defer the update because changing the AppKit appearance may
2058                // synchronously invoke this callback while App is already borrowed.
2059                foreground_executor
2060                    .spawn(async move {
2061                        handle
2062                            .update(&mut cx, |_, window, cx| window.appearance_changed(cx))
2063                            .log_err();
2064                    })
2065                    .detach();
2066            }
2067        }));
2068        platform_window.on_button_layout_changed(Box::new({
2069            let mut cx = cx.to_async();
2070            move || {
2071                handle
2072                    .update(&mut cx, |_, window, cx| window.button_layout_changed(cx))
2073                    .log_err();
2074            }
2075        }));
2076        platform_window.on_active_status_change(Box::new({
2077            let mut cx = cx.to_async();
2078            move |active| {
2079                handle
2080                    .update(&mut cx, |_, window, cx| {
2081                        window.active.set(active);
2082                        window.modifiers = window.platform_window.modifiers();
2083                        window.capslock = window.platform_window.capslock();
2084                        window
2085                            .activation_observers
2086                            .clone()
2087                            .retain(|callback| callback(window, cx));
2088
2089                        window.bounds_changed(cx);
2090                        window.refresh();
2091
2092                        SystemWindowTabController::update_last_active(cx, window.handle.id);
2093                    })
2094                    .log_err();
2095            }
2096        }));
2097        platform_window.on_visibility_change(Box::new({
2098            let mut cx = cx.to_async();
2099            move |_| {
2100                handle
2101                    .update(&mut cx, |_, window, cx| {
2102                        window.refresh_visibility(cx);
2103                    })
2104                    .log_err();
2105            }
2106        }));
2107        platform_window.on_hover_status_change(Box::new({
2108            let mut cx = cx.to_async();
2109            move |active| {
2110                handle
2111                    .update(&mut cx, |_, window, _| {
2112                        window.hovered.set(active);
2113                        window.refresh();
2114                    })
2115                    .log_err();
2116            }
2117        }));
2118        platform_window.on_input({
2119            let mut cx = cx.to_async();
2120            Box::new(move |event| {
2121                handle
2122                    .update(&mut cx, |_, window, cx| window.dispatch_event(event, cx))
2123                    .log_err()
2124                    .unwrap_or(DispatchEventResult::default())
2125            })
2126        });
2127        platform_window.on_hit_test_window_control({
2128            let mut cx = cx.to_async();
2129            Box::new(move || {
2130                handle
2131                    .update(&mut cx, |_, window, _cx| {
2132                        for (area, hitbox) in &window.rendered_frame.window_control_hitboxes {
2133                            if window.mouse_hit_test.ids.contains(&hitbox.id) {
2134                                return Some(*area);
2135                            }
2136                        }
2137                        None
2138                    })
2139                    .log_err()
2140                    .unwrap_or(None)
2141            })
2142        });
2143        platform_window.on_move_tab_to_new_window({
2144            let mut cx = cx.to_async();
2145            Box::new(move || {
2146                handle
2147                    .update(&mut cx, |_, _window, cx| {
2148                        SystemWindowTabController::move_tab_to_new_window(cx, handle.window_id());
2149                    })
2150                    .log_err();
2151            })
2152        });
2153        platform_window.on_merge_all_windows({
2154            let mut cx = cx.to_async();
2155            Box::new(move || {
2156                handle
2157                    .update(&mut cx, |_, _window, cx| {
2158                        SystemWindowTabController::merge_all_windows(cx, handle.window_id());
2159                    })
2160                    .log_err();
2161            })
2162        });
2163        platform_window.on_select_next_tab({
2164            let mut cx = cx.to_async();
2165            Box::new(move || {
2166                handle
2167                    .update(&mut cx, |_, _window, cx| {
2168                        SystemWindowTabController::select_next_tab(cx, handle.window_id());
2169                    })
2170                    .log_err();
2171            })
2172        });
2173        platform_window.on_select_previous_tab({
2174            let mut cx = cx.to_async();
2175            Box::new(move || {
2176                handle
2177                    .update(&mut cx, |_, _window, cx| {
2178                        SystemWindowTabController::select_previous_tab(cx, handle.window_id())
2179                    })
2180                    .log_err();
2181            })
2182        });
2183        platform_window.on_toggle_tab_bar({
2184            let mut cx = cx.to_async();
2185            Box::new(move || {
2186                handle
2187                    .update(&mut cx, |_, window, cx| {
2188                        let tab_bar_visible = window.platform_window.tab_bar_visible();
2189                        SystemWindowTabController::set_visible(cx, tab_bar_visible);
2190                    })
2191                    .log_err();
2192            })
2193        });
2194
2195        if let Some(app_id) = app_id {
2196            platform_window.set_app_id(&app_id);
2197        }
2198
2199        platform_window.map_window().unwrap();
2200
2201        Ok(Window {
2202            handle,
2203            invalidator,
2204            removed: false,
2205            platform_window,
2206            display_id,
2207            display_observers: SingleSubscriberSet::new(),
2208            is_resizable,
2209            is_minimizable,
2210            sprite_atlas,
2211            text_system,
2212            text_rendering_mode: cx.text_rendering_mode.clone(),
2213            rem_size: px(16.),
2214            rem_size_override_stack: SmallVec::new(),
2215            viewport_size: content_size,
2216            layout_engine: Some(TaffyLayoutEngine::new()),
2217            root: None,
2218            element_id_stack: ElementIdStack::default(),
2219            text_style_stack: Vec::new(),
2220            glyph_brush_stack: Vec::new(),
2221            rendered_entity_stack: Vec::new(),
2222            element_offset_stack: Vec::new(),
2223            content_mask_stack: Vec::new(),
2224            element_opacity: 1.0,
2225            layer_capture_depth: 0,
2226            layer_capture_sources: Vec::new(),
2227            layer_capture_clips: Vec::new(),
2228            requested_autoscroll: None,
2229            last_text_input_configuration: None,
2230            focused_text_input: None,
2231            rendered_frame: Frame::new(DispatchTree::new(cx.keymap.clone(), cx.actions.clone())),
2232            next_frame: Frame::new(DispatchTree::new(cx.keymap.clone(), cx.actions.clone())),
2233            next_frame_callbacks,
2234            next_hitbox_id: HitboxId(0),
2235            next_tooltip_id: TooltipId::default(),
2236            tooltip_bounds: None,
2237            dirty_views: FxHashSet::default(),
2238            focus_listeners: SingleSubscriberSet::new(),
2239            focus_lost_listeners: SingleSubscriberSet::new(),
2240            focus_lost_path: SmallVec::new(),
2241            default_prevented: true,
2242            mouse_position,
2243            mouse_hit_test: HitTest::default(),
2244            modifiers,
2245            capslock,
2246            scale_factor,
2247            bounds_observers: SingleSubscriberSet::new(),
2248            appearance,
2249            appearance_observers: SingleSubscriberSet::new(),
2250            button_layout_observers: SingleSubscriberSet::new(),
2251            active,
2252            visibility,
2253            visibility_observers: SingleSubscriberSet::new(),
2254            hovered,
2255            needs_present,
2256            input_rate_tracker,
2257            #[cfg(feature = "profiler")]
2258            window_profiler: profiler::WindowProfiler::new(handle.window_id())?,
2259            last_input_modality: InputModality::Mouse,
2260            touch_gestures: TouchGestureRecognizer::new(
2261                cx.platform
2262                    .gestures()
2263                    .map_or_else(GestureTuning::default, |gestures| gestures.tuning()),
2264            ),
2265            touch_prediction_enabled: true,
2266            long_press_timer: None,
2267            long_press_capture: None,
2268            refreshing: false,
2269            activation_observers: SingleSubscriberSet::new(),
2270            focus: None,
2271            focus_enabled: true,
2272            focus_generation: 0,
2273            pending_input: None,
2274            pending_modifier: ModifierState::default(),
2275            pending_input_observers: SingleSubscriberSet::new(),
2276            prompt: None,
2277            client_inset: None,
2278            image_cache_stack: Vec::new(),
2279            captured_hitbox: None,
2280            #[cfg(debug_assertions)]
2281            inspector: None,
2282            #[cfg(feature = "profiler")]
2283            debug_frame_overlay: crate::debug_overlay::DebugFrameOverlay::new(),
2284            a11y: A11y::new(
2285                a11y_active_flag,
2286                accessibility_force_disabled,
2287                initial_window_title,
2288            ),
2289        })
2290    }
2291
2292    pub(crate) fn new_focus_listener(
2293        &self,
2294        value: AnyWindowFocusListener,
2295    ) -> (Subscription, impl FnOnce() + use<>) {
2296        self.focus_listeners.insert_pending(value)
2297    }
2298}
2299
2300#[derive(Clone, Debug, Default, PartialEq, Eq)]
2301#[expect(missing_docs)]
2302pub struct DispatchEventResult {
2303    pub propagate: bool,
2304    pub default_prevented: bool,
2305}
2306
2307/// Indicates which region of the window is visible. Content falling outside of this mask will not be
2308/// rendered. Currently, only rectangular content masks are supported, but we give the mask its own type
2309/// to leave room to support more complex shapes in the future.
2310#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
2311#[repr(C)]
2312pub struct ContentMask<P: Clone + Debug + Default + PartialEq> {
2313    /// The bounds
2314    pub bounds: Bounds<P>,
2315}
2316
2317impl ContentMask<Pixels> {
2318    /// Scale the content mask's pixel units by the given scaling factor.
2319    pub fn scale(&self, factor: f32) -> ContentMask<ScaledPixels> {
2320        ContentMask {
2321            bounds: self.bounds.scale(factor),
2322        }
2323    }
2324
2325    /// Intersect the content mask with the given content mask.
2326    pub fn intersect(&self, other: &Self) -> Self {
2327        let bounds = self.bounds.intersect(&other.bounds);
2328        ContentMask { bounds }
2329    }
2330}
2331
2332impl Window {
2333    fn mark_view_dirty(&mut self, view_id: EntityId) {
2334        // Mark ancestor views as dirty. If already in the `dirty_views` set, then all its ancestors
2335        // should already be dirty.
2336        for view_id in self
2337            .rendered_frame
2338            .dispatch_tree
2339            .view_path_reversed(view_id)
2340        {
2341            if !self.dirty_views.insert(view_id) {
2342                break;
2343            }
2344        }
2345    }
2346
2347    pub(crate) fn refresh_visibility(&mut self, cx: &mut App) {
2348        let visibility = self.platform_window.visibility();
2349        if self.visibility != visibility {
2350            self.visibility = visibility;
2351            #[cfg(feature = "profiler")]
2352            profiler::journal::record_window_visibility(self.handle.window_id(), visibility);
2353            self.visibility_observers
2354                .clone()
2355                .retain(|callback| callback(visibility, self, cx));
2356        }
2357        #[cfg(feature = "profiler")]
2358        if self.invalidator.is_dirty() || self.needs_present.get() {
2359            profiler::journal::record_frame_pending(self.handle.window_id(), Instant::now());
2360        }
2361    }
2362
2363    /// Whether the platform is presenting this window's frames (see
2364    /// [`WindowVisibility`]).
2365    pub fn visibility(&self) -> WindowVisibility {
2366        self.visibility
2367    }
2368
2369    /// Whether frames drawn for this window will be shown.
2370    ///
2371    /// This is not the window's shown/hidden state: a shown window that is
2372    /// fully behind another window, minimized, or on a sleeping display is not
2373    /// visible here.
2374    pub fn is_visible(&self) -> bool {
2375        self.visibility.is_visible()
2376    }
2377
2378    /// Registers a callback to be invoked when the window's visibility changes.
2379    pub fn observe_window_visibility(
2380        &self,
2381        mut callback: impl FnMut(WindowVisibility, &mut Window, &mut App) + 'static,
2382    ) -> Subscription {
2383        self.visibility_observers
2384            .insert(Box::new(move |visibility, window, cx| {
2385                callback(visibility, window, cx);
2386                true
2387            }))
2388    }
2389
2390    /// Registers a callback to be invoked when the window appearance changes.
2391    pub fn observe_window_appearance(
2392        &self,
2393        mut callback: impl FnMut(&mut Window, &mut App) + 'static,
2394    ) -> Subscription {
2395        self.appearance_observers
2396            .insert(Box::new(move |window, cx| {
2397                callback(window, cx);
2398                true
2399            }))
2400    }
2401
2402    /// Registers a callback to be invoked when the window button layout changes.
2403    pub fn observe_button_layout_changed(
2404        &self,
2405        mut callback: impl FnMut(&mut Window, &mut App) + 'static,
2406    ) -> Subscription {
2407        self.button_layout_observers
2408            .insert(Box::new(move |window, cx| {
2409                callback(window, cx);
2410                true
2411            }))
2412    }
2413
2414    /// Replaces the root entity of the window with a new one.
2415    pub fn replace_root<E>(
2416        &mut self,
2417        cx: &mut App,
2418        build_view: impl FnOnce(&mut Window, &mut Context<E>) -> E,
2419    ) -> Entity<E>
2420    where
2421        E: 'static + Render,
2422    {
2423        let view = cx.new(|cx| build_view(self, cx));
2424        self.root = Some(view.clone().into());
2425        self.refresh();
2426        view
2427    }
2428
2429    /// Returns the root entity of the window, if it has one.
2430    pub fn root<E>(&self) -> Option<Option<Entity<E>>>
2431    where
2432        E: 'static + Render,
2433    {
2434        self.root
2435            .as_ref()
2436            .map(|view| view.clone().downcast::<E>().ok())
2437    }
2438
2439    /// Obtain a handle to the window that belongs to this context.
2440    pub fn window_handle(&self) -> AnyWindowHandle {
2441        self.handle
2442    }
2443
2444    /// Mark the window as dirty, scheduling it to be redrawn on the next frame.
2445    pub fn refresh(&mut self) {
2446        if self.invalidator.not_drawing() {
2447            self.refreshing = true;
2448            self.invalidator.set_dirty(true);
2449        }
2450    }
2451
2452    /// Close this window.
2453    pub fn remove_window(&mut self) {
2454        self.removed = true;
2455    }
2456
2457    /// Obtain the currently focused [`FocusHandle`]. If no elements are focused, returns `None`.
2458    pub fn focused(&self, cx: &App) -> Option<FocusHandle> {
2459        self.focus
2460            .and_then(|id| FocusHandle::for_id(id, &cx.focus_handles))
2461    }
2462
2463    /// While focus-lost listeners are being dispatched, returns the closest ancestor of the
2464    /// previously focused element that can still receive focus, making it a suitable target
2465    /// for focus restoration. Returns `None` at all other times, or when no such ancestor exists.
2466    pub fn focus_lost_restore_target(&self, cx: &App) -> Option<FocusHandle> {
2467        let (_leaf, ancestors) = self.focus_lost_path.split_last()?;
2468        ancestors.iter().rev().find_map(|id| {
2469            self.rendered_frame.dispatch_tree.focusable_node_id(*id)?;
2470            FocusHandle::for_id(*id, &cx.focus_handles)
2471        })
2472    }
2473
2474    /// Move focus to the element associated with the given [`FocusHandle`].
2475    pub fn focus(&mut self, handle: &FocusHandle, cx: &mut App) {
2476        if !self.focus_enabled || self.focus == Some(handle.id) {
2477            return;
2478        }
2479
2480        self.focus = Some(handle.id);
2481        self.focus_generation = self.focus_generation.wrapping_add(1);
2482        self.clear_pending_keystrokes(cx);
2483
2484        self.refresh();
2485    }
2486
2487    /// Remove focus from all elements within this context's window.
2488    pub fn blur(&mut self, cx: &mut App) {
2489        self.clear_pending_keystrokes(cx);
2490
2491        if !self.focus_enabled {
2492            return;
2493        }
2494
2495        if self.focus.is_some() {
2496            self.focus_generation = self.focus_generation.wrapping_add(1);
2497        }
2498        self.focus = None;
2499        self.refresh();
2500    }
2501
2502    /// Blur the window and don't allow anything in it to be focused again.
2503    pub fn disable_focus(&mut self, cx: &mut App) {
2504        self.blur(cx);
2505        self.focus_enabled = false;
2506    }
2507
2508    /// Move focus to next tab stop.
2509    pub fn focus_next(&mut self, cx: &mut App) {
2510        if !self.focus_enabled {
2511            return;
2512        }
2513
2514        if let Some(handle) = self.rendered_frame.tab_stops.next(self.focus.as_ref()) {
2515            self.focus(&handle, cx)
2516        }
2517    }
2518
2519    /// Move focus to previous tab stop.
2520    pub fn focus_prev(&mut self, cx: &mut App) {
2521        if !self.focus_enabled {
2522            return;
2523        }
2524
2525        if let Some(handle) = self.rendered_frame.tab_stops.prev(self.focus.as_ref()) {
2526            self.focus(&handle, cx)
2527        }
2528    }
2529
2530    /// Accessor for the text system.
2531    pub fn text_system(&self) -> &Rc<WindowTextSystem> {
2532        &self.text_system
2533    }
2534
2535    /// The current text style. Which is composed of all the style refinements provided to `with_text_style`.
2536    pub fn text_style(&self) -> TextStyle {
2537        let mut style = TextStyle::default();
2538        for refinement in &self.text_style_stack {
2539            style.refine(refinement);
2540        }
2541        style
2542    }
2543
2544    /// Check if the platform window is maximized.
2545    ///
2546    /// On some platforms (namely Windows) this is different than the bounds being the size of the display
2547    pub fn is_maximized(&self) -> bool {
2548        self.platform_window.is_maximized()
2549    }
2550
2551    /// request a certain window decoration (Wayland)
2552    pub fn request_decorations(&self, decorations: WindowDecorations) {
2553        self.platform_window.request_decorations(decorations);
2554    }
2555
2556    /// Set the exclusive zone for a layer-shell surface: how much screen space it
2557    /// reserves so other surfaces avoid occluding it (e.g. a panel reserving space).
2558    /// Positive values reserve that distance from the anchored edge, 0 lets the
2559    /// surface be moved out of others' exclusive zones, and -1 ignores reserved
2560    /// space and may extend under other surfaces. (Wayland layer-shell windows only)
2561    pub fn set_exclusive_zone(&self, zone: Pixels) {
2562        self.platform_window.set_exclusive_zone(zone);
2563    }
2564
2565    /// Set which anchored edge a layer-shell surface's exclusive zone applies to.
2566    /// This is only needed to disambiguate a corner-anchored surface; otherwise the
2567    /// edge is deduced from the anchor. The edge must be a single edge the surface
2568    /// is anchored to, or it is ignored. (Wayland layer-shell windows only)
2569    #[cfg(all(target_os = "linux", feature = "wayland"))]
2570    pub fn set_exclusive_edge(&self, edge: crate::layer_shell::Anchor) {
2571        self.platform_window.set_exclusive_edge(edge);
2572    }
2573
2574    /// Start an interactive window resize operation if this window is resizable.
2575    pub fn start_window_resize(&self, edge: ResizeEdge) {
2576        if self.is_resizable {
2577            self.platform_window.start_window_resize(edge);
2578        }
2579    }
2580
2581    /// Linux (wayland) only: Set the window's input region, the area that receives pointer
2582    /// and touch input. Events outside it pass through to whatever is below the window.
2583    ///
2584    /// - `Some(rects)` restricts input to the union of `rects`, in window coordinates.
2585    /// - `Some(&[])` is an empty region, so the window receives no pointer or touch input.
2586    /// - `None` resets the region to the default, so the whole window receives input again.
2587    pub fn set_input_region(&self, region: Option<&[Bounds<Pixels>]>) {
2588        self.platform_window.set_input_region(region);
2589    }
2590
2591    /// Return the `WindowBounds` to indicate that how a window should be opened
2592    /// after it has been closed
2593    pub fn window_bounds(&self) -> WindowBounds {
2594        self.platform_window.window_bounds()
2595    }
2596
2597    /// Return the `WindowBounds` excluding insets (Wayland and X11)
2598    pub fn inner_window_bounds(&self) -> WindowBounds {
2599        self.platform_window.inner_window_bounds()
2600    }
2601
2602    /// Encode the window's native restorable state into an opaque blob.
2603    /// Returns `None` on platforms without native state restoration or if encoding fails.
2604    pub fn native_window_state(&self) -> Option<Vec<u8>> {
2605        self.platform_window.native_window_state()
2606    }
2607
2608    /// Restore the window's native state from a blob previously produced
2609    /// by [`Window::native_window_state`]. A no-op on platforms without native state restoration.
2610    pub fn restore_native_window_state(&self, state: &[u8]) {
2611        self.platform_window.restore_native_window_state(state);
2612    }
2613
2614    /// Dispatch the given action on the currently focused element.
2615    pub fn dispatch_action(&mut self, action: Box<dyn Action>, cx: &mut App) {
2616        let focus_id = self.focused(cx).map(|handle| handle.id);
2617
2618        let window = self.handle;
2619        cx.defer(move |cx| {
2620            window
2621                .update(cx, |_, window, cx| {
2622                    let node_id = window.focus_node_id_in_rendered_frame(focus_id);
2623                    window.dispatch_action_on_node(node_id, action.as_ref(), cx);
2624                })
2625                .log_err();
2626        })
2627    }
2628
2629    pub(crate) fn dispatch_keystroke_observers(
2630        &mut self,
2631        keystroke: &Keystroke,
2632        input_preference: InputPreference,
2633        action: Option<&dyn Action>,
2634        context_stack: Vec<KeyContext>,
2635        cx: &mut App,
2636    ) {
2637        cx.keystroke_observers.clone().retain(move |callback| {
2638            (callback)(
2639                &KeystrokeEvent {
2640                    keystroke: keystroke.clone(),
2641                    input_preference,
2642                    action: action.map(|action| action.boxed_clone()),
2643                    context_stack: context_stack.clone(),
2644                },
2645                self,
2646                cx,
2647            )
2648        });
2649    }
2650
2651    pub(crate) fn dispatch_keystroke_interceptors(
2652        &mut self,
2653        keystroke: &Keystroke,
2654        input_preference: InputPreference,
2655        context_stack: Vec<KeyContext>,
2656        cx: &mut App,
2657    ) {
2658        cx.keystroke_interceptors.clone().retain(move |callback| {
2659            (callback)(
2660                &KeystrokeEvent {
2661                    keystroke: keystroke.clone(),
2662                    input_preference,
2663                    action: None,
2664                    context_stack: context_stack.clone(),
2665                },
2666                self,
2667                cx,
2668            )
2669        });
2670    }
2671
2672    /// Schedules the given function to be run at the end of the current effect cycle, allowing entities
2673    /// that are currently on the stack to be returned to the app.
2674    pub fn defer(&self, cx: &mut App, f: impl FnOnce(&mut Window, &mut App) + 'static) {
2675        let handle = self.handle;
2676        cx.defer(move |cx| {
2677            handle.update(cx, |_, window, cx| f(window, cx)).ok();
2678        });
2679    }
2680
2681    /// Subscribe to events emitted by a entity.
2682    /// The entity to which you're subscribing must implement the [`EventEmitter`] trait.
2683    /// The callback will be invoked a handle to the emitting entity, the event, and a window context for the current window.
2684    pub fn observe<T: 'static>(
2685        &mut self,
2686        observed: &Entity<T>,
2687        cx: &mut App,
2688        mut on_notify: impl FnMut(Entity<T>, &mut Window, &mut App) + 'static,
2689    ) -> Subscription {
2690        let entity_id = observed.entity_id();
2691        let observed = observed.downgrade();
2692        let window_handle = self.handle;
2693        cx.new_observer(
2694            entity_id,
2695            Box::new(move |cx| {
2696                window_handle
2697                    .update(cx, |_, window, cx| {
2698                        if let Some(handle) = observed.upgrade() {
2699                            on_notify(handle, window, cx);
2700                            true
2701                        } else {
2702                            false
2703                        }
2704                    })
2705                    .unwrap_or(false)
2706            }),
2707        )
2708    }
2709
2710    /// Subscribe to events emitted by a entity.
2711    /// The entity to which you're subscribing must implement the [`EventEmitter`] trait.
2712    /// The callback will be invoked a handle to the emitting entity, the event, and a window context for the current window.
2713    pub fn subscribe<Emitter, Evt>(
2714        &mut self,
2715        entity: &Entity<Emitter>,
2716        cx: &mut App,
2717        mut on_event: impl FnMut(Entity<Emitter>, &Evt, &mut Window, &mut App) + 'static,
2718    ) -> Subscription
2719    where
2720        Emitter: EventEmitter<Evt>,
2721        Evt: 'static,
2722    {
2723        let entity_id = entity.entity_id();
2724        let handle = entity.downgrade();
2725        let window_handle = self.handle;
2726        cx.new_subscription(
2727            entity_id,
2728            (
2729                TypeId::of::<Evt>(),
2730                Box::new(move |event, cx| {
2731                    window_handle
2732                        .update(cx, |_, window, cx| {
2733                            if let Some(entity) = handle.upgrade() {
2734                                let event = event.downcast_ref().expect("invalid event type");
2735                                on_event(entity, event, window, cx);
2736                                true
2737                            } else {
2738                                false
2739                            }
2740                        })
2741                        .unwrap_or(false)
2742                }),
2743            ),
2744        )
2745    }
2746
2747    /// Register a callback to be invoked when the given `Entity` is released.
2748    pub fn observe_release<T>(
2749        &self,
2750        entity: &Entity<T>,
2751        cx: &mut App,
2752        on_release: impl FnOnce(&mut T, &mut Window, &mut App) + 'static,
2753    ) -> Subscription
2754    where
2755        T: 'static,
2756    {
2757        let entity_id = entity.entity_id();
2758        let window_handle = self.handle;
2759        cx.release_listeners.insert(
2760            entity_id,
2761            Box::new(move |entity, cx| {
2762                let entity = entity.downcast_mut().expect("invalid entity type");
2763                let _ = window_handle.update(cx, |_, window, cx| on_release(entity, window, cx));
2764            }),
2765        )
2766    }
2767
2768    /// Creates an [`AsyncWindowContext`], which has a static lifetime and can be held across
2769    /// await points in async code.
2770    pub fn to_async(&self, cx: &App) -> AsyncWindowContext {
2771        AsyncWindowContext::new_context(cx.to_async(), self.handle)
2772    }
2773
2774    /// Schedule the given closure to be run directly after the current frame is rendered.
2775    pub fn on_next_frame(&self, callback: impl FnOnce(&mut Window, &mut App) + 'static) {
2776        RefCell::borrow_mut(&self.next_frame_callbacks).push(Box::new(callback));
2777        self.platform_window.schedule_frame();
2778        // Next-frame callbacks create frame demand without dirtying the
2779        // window, so the platform's frame source must be woken explicitly.
2780        self.invalidator.wake_platform();
2781    }
2782
2783    /// Schedule a frame to be drawn on the next animation frame.
2784    ///
2785    /// This is useful for elements that need to animate continuously, such as a video player or an animated GIF.
2786    /// It will cause the window to redraw on the next frame, even if no other changes have occurred.
2787    ///
2788    /// If called from within a view, it will notify that view on the next frame. Otherwise, it will refresh the entire window.
2789    ///
2790    /// Callers driving purely decorative animations (spinners, pulses, and the
2791    /// like) should prefer [`AnimationExt::with_animation`](crate::AnimationExt::with_animation),
2792    /// which automatically respects [`App::reduce_motion`]. When using this
2793    /// method directly for decorative motion, check [`App::reduce_motion`]
2794    /// and skip the frame request when it is set.
2795    ///
2796    /// Frames requested this way are rate-limited in inactive windows (about
2797    /// 30 fps by default), in low-power mode and under thermal pressure; see
2798    /// [`WindowOptions::inactive_frame_interval`]. Content that changes on its
2799    /// own schedule, such as frames from another thread, should call
2800    /// `cx.notify()` when new content arrives instead.
2801    pub fn request_animation_frame(&self) {
2802        let entity = self.current_view();
2803        self.on_next_frame(move |_, cx| cx.notify(entity));
2804    }
2805
2806    /// Runs all callbacks scheduled via [`Self::on_next_frame`], returning how many ran.
2807    ///
2808    /// Tests have no platform frame loop, so this simulates the delivery of the
2809    /// next frame.
2810    #[cfg(any(test, feature = "test-support"))]
2811    pub fn simulate_next_frame(&mut self, cx: &mut App) -> usize {
2812        let callbacks = self.next_frame_callbacks.take();
2813        let count = callbacks.len();
2814        for callback in callbacks {
2815            callback(self, cx);
2816        }
2817        count
2818    }
2819
2820    /// Spawn the future returned by the given closure on the application thread pool.
2821    /// The closure is provided a handle to the current window and an `AsyncWindowContext` for
2822    /// use within your future.
2823    #[track_caller]
2824    pub fn spawn<AsyncFn, R>(&self, cx: &App, f: AsyncFn) -> Task<R>
2825    where
2826        R: 'static,
2827        AsyncFn: AsyncFnOnce(&mut AsyncWindowContext) -> R + 'static,
2828    {
2829        let handle = self.handle;
2830        cx.spawn(async move |app| {
2831            let mut async_window_cx = AsyncWindowContext::new_context(app.clone(), handle);
2832            f(&mut async_window_cx).await
2833        })
2834    }
2835
2836    /// Spawn the future returned by the given closure on the application thread
2837    /// pool, with the given priority. The closure is provided a handle to the
2838    /// current window and an `AsyncWindowContext` for use within your future.
2839    #[track_caller]
2840    pub fn spawn_with_priority<AsyncFn, R>(
2841        &self,
2842        priority: Priority,
2843        cx: &App,
2844        f: AsyncFn,
2845    ) -> Task<R>
2846    where
2847        R: 'static,
2848        AsyncFn: AsyncFnOnce(&mut AsyncWindowContext) -> R + 'static,
2849    {
2850        let handle = self.handle;
2851        cx.spawn_with_priority(priority, async move |app| {
2852            let mut async_window_cx = AsyncWindowContext::new_context(app.clone(), handle);
2853            f(&mut async_window_cx).await
2854        })
2855    }
2856
2857    /// Notify the window that its bounds have changed.
2858    ///
2859    /// This updates internal state like `viewport_size` and `scale_factor` from
2860    /// the platform window, then notifies observers. Normally called automatically
2861    /// by the platform's resize callback, but exposed publicly for test infrastructure.
2862    pub fn bounds_changed(&mut self, cx: &mut App) {
2863        self.scale_factor = self.platform_window.scale_factor();
2864        self.viewport_size = self.platform_window.content_size();
2865        self.mouse_position = self.platform_window.mouse_position();
2866
2867        self.refresh();
2868
2869        self.bounds_observers
2870            .clone()
2871            .retain(|callback| callback(self, cx));
2872    }
2873
2874    fn display_changed(handle: AnyWindowHandle, cx: &mut App) {
2875        let moved_to = handle
2876            .update(cx, |_, window, _| {
2877                let display_id = window.platform_window.display().map(|display| display.id());
2878                let moved = display_id != window.display_id;
2879                window.display_id = display_id;
2880                moved.then_some(display_id)
2881            })
2882            .log_err()
2883            .flatten();
2884        let Some(display_id) = moved_to else {
2885            return;
2886        };
2887        // The platform's notifications about the window and about displays
2888        // arrive in no guaranteed order, so make sure App knows the display
2889        // before the window's observers read its state.
2890        if let Some(display_id) = display_id
2891            && !cx.knows_display(display_id)
2892        {
2893            cx.displays_changed();
2894        }
2895        handle
2896            .update(cx, |_, window, cx| window.notify_display_observers(cx))
2897            .log_err();
2898    }
2899
2900    pub(crate) fn notify_display_observers(&mut self, cx: &mut App) {
2901        self.display_observers
2902            .clone()
2903            .retain(|callback| callback(self, cx));
2904    }
2905
2906    /// The time between refreshes of the display the window is on, as of the
2907    /// platform's last display change notification. Variable refresh rate
2908    /// displays report their maximum rate. Returns `None` when the platform
2909    /// doesn't report it.
2910    pub fn refresh_interval(&self, cx: &App) -> Option<Duration> {
2911        cx.display_refresh_interval(self.display_id?)
2912    }
2913
2914    /// Registers a callback invoked when the window moves to another display
2915    /// or its display's properties change, for example its refresh
2916    /// interval. [`Self::refresh_interval`] already returns the new value
2917    /// when the callback runs.
2918    pub fn observe_window_display(
2919        &self,
2920        mut callback: impl FnMut(&mut Window, &mut App) + 'static,
2921    ) -> Subscription {
2922        self.display_observers.insert(Box::new(move |window, cx| {
2923            callback(window, cx);
2924            true
2925        }))
2926    }
2927
2928    /// Returns the bounds of the current window in the global coordinate space, which could span across multiple displays.
2929    pub fn bounds(&self) -> Bounds<Pixels> {
2930        self.platform_window.bounds()
2931    }
2932
2933    /// Returns the regions of this window obscured by system UI and the keyboard.
2934    pub fn insets(&self) -> WindowInsets {
2935        self.platform_window.insets()
2936    }
2937
2938    /// Renders the current frame's scene to a texture and returns the pixel data as an RGBA image.
2939    /// This does not present the frame to screen - useful for visual testing where we want
2940    /// to capture what would be rendered without displaying it or requiring the window to be visible.
2941    #[cfg(any(test, feature = "test-support"))]
2942    pub fn render_to_image(&self) -> anyhow::Result<image::RgbaImage> {
2943        self.platform_window
2944            .render_to_image(&self.rendered_frame.scene)
2945    }
2946
2947    /// Synchronously re-render the last painted scene and read its associated
2948    /// extended linear-P3 FP16 composition, before display color management.
2949    /// Metal WideGamutSdr only. This waits for GPU completion; use on demand.
2950    #[cfg(any(test, feature = "test-support"))]
2951    pub fn render_to_linear_p3(&self) -> anyhow::Result<crate::LinearP3Image> {
2952        self.platform_window
2953            .render_to_linear_p3(&self.rendered_frame.scene)
2954    }
2955
2956    /// Returns the quads in the most recently rendered frame's scene, so tests can assert on
2957    /// painted output without rasterizing the frame. Quad bounds are in scaled pixels and are
2958    /// not clipped; each quad carries the content mask it will be clipped to when drawn. Quads
2959    /// whose bounds don't intersect their content mask are culled at paint time and won't appear.
2960    #[cfg(any(test, feature = "test-support"))]
2961    pub fn painted_quads(&self) -> Vec<Quad> {
2962        self.rendered_frame.scene.quads.clone()
2963    }
2964
2965    /// Returns the underlines in the most recently rendered frame's scene.
2966    #[cfg(any(test, feature = "test-support"))]
2967    pub fn painted_underlines(&self) -> Vec<Underline> {
2968        self.rendered_frame.scene.underlines.clone()
2969    }
2970
2971    /// Set the content size of the window.
2972    pub fn resize(&mut self, size: Size<Pixels>) {
2973        self.platform_window.resize(size);
2974    }
2975
2976    /// Returns whether or not the window is currently fullscreen
2977    pub fn is_fullscreen(&self) -> bool {
2978        self.platform_window.is_fullscreen()
2979    }
2980
2981    /// Returns whether the window is currently in simple (borderless) fullscreen,
2982    /// where it covers the entire screen including the menu bar and notch area.
2983    /// Always `false` on platforms other than macOS.
2984    pub fn is_simple_fullscreen(&self) -> bool {
2985        self.platform_window.is_simple_fullscreen()
2986    }
2987
2988    pub(crate) fn appearance_changed(&mut self, cx: &mut App) {
2989        self.appearance = self.platform_window.appearance();
2990
2991        self.appearance_observers
2992            .clone()
2993            .retain(|callback| callback(self, cx));
2994    }
2995
2996    pub(crate) fn button_layout_changed(&mut self, cx: &mut App) {
2997        self.button_layout_observers
2998            .clone()
2999            .retain(|callback| callback(self, cx));
3000    }
3001
3002    /// Returns the appearance of the current window.
3003    pub fn appearance(&self) -> WindowAppearance {
3004        self.appearance
3005    }
3006
3007    /// Returns the size of the drawable area within the window.
3008    pub fn viewport_size(&self) -> Size<Pixels> {
3009        self.viewport_size
3010    }
3011
3012    /// Returns the platform's visible viewport in window-local logical pixels.
3013    ///
3014    /// Unlike `viewport_size`, this can shrink or move when the keyboard opens.
3015    /// During drawing this is a consistent frame snapshot. Outside drawing it
3016    /// reflects the latest platform sample, not a synchronous geometry query.
3017    pub fn visual_viewport_bounds(&self) -> Bounds<Pixels> {
3018        self.platform_window.visual_viewport_bounds()
3019    }
3020
3021    /// Returns a conservative rectangle avoiding platform-known obscured content.
3022    ///
3023    /// Intersects the visual viewport with the full layout area inset by system
3024    /// safe areas and keyboard occlusion. Unknown overlays cannot be excluded.
3025    pub fn fully_visible_bounds(&self) -> Bounds<Pixels> {
3026        let insets = self.platform_window.insets().effective();
3027        let viewport = self.viewport_size();
3028        let left = insets.left.max(Pixels::ZERO).min(viewport.width);
3029        let top = insets.top.max(Pixels::ZERO).min(viewport.height);
3030        let right = (viewport.width - insets.right.max(Pixels::ZERO)).max(left);
3031        let bottom = (viewport.height - insets.bottom.max(Pixels::ZERO)).max(top);
3032        let safe_bounds = Bounds::from_corners(point(left, top), point(right, bottom));
3033        let mut visible = safe_bounds.intersect(&self.visual_viewport_bounds());
3034        visible.size.width = visible.size.width.max(Pixels::ZERO);
3035        visible.size.height = visible.size.height.max(Pixels::ZERO);
3036        visible
3037    }
3038
3039    /// Requests the virtual keyboard for the currently focused text input.
3040    ///
3041    /// Call from a user gesture on platforms that require one. The platform may
3042    /// decline the request; this does not change focus or the layout viewport.
3043    pub fn request_virtual_keyboard(&self) {
3044        self.platform_window.show_soft_keyboard();
3045    }
3046
3047    /// Requests dismissal of the virtual keyboard without changing GPUI focus.
3048    pub fn dismiss_virtual_keyboard(&self) {
3049        self.platform_window.hide_soft_keyboard();
3050    }
3051
3052    /// Returns whether this window is focused by the operating system (receiving key events).
3053    pub fn is_window_active(&self) -> bool {
3054        self.active.get()
3055    }
3056
3057    /// Returns whether this window is considered to be the window
3058    /// that currently owns the mouse cursor.
3059    /// On mac, this is equivalent to `is_window_active`.
3060    pub fn is_window_hovered(&self) -> bool {
3061        if cfg!(any(
3062            target_os = "windows",
3063            target_os = "linux",
3064            target_os = "freebsd"
3065        )) {
3066            self.hovered.get()
3067        } else {
3068            self.is_window_active()
3069        }
3070    }
3071
3072    /// Toggle zoom on the window.
3073    pub fn zoom_window(&self) {
3074        self.platform_window.zoom();
3075    }
3076
3077    /// Opens the native title bar context menu, useful when implementing client side decorations (Wayland and X11)
3078    pub fn show_window_menu(&self, position: Point<Pixels>) {
3079        self.platform_window.show_window_menu(position)
3080    }
3081
3082    /// Handle window movement for Linux and macOS.
3083    /// Tells the compositor to take control of window movement (Wayland and X11)
3084    ///
3085    /// Events may not be received during a move operation.
3086    pub fn start_window_move(&self) {
3087        self.platform_window.start_window_move()
3088    }
3089
3090    /// When using client side decorations, set this to the width of the invisible decorations (Wayland and X11)
3091    pub fn set_client_inset(&mut self, inset: Pixels) {
3092        self.client_inset = Some(inset);
3093        self.platform_window.set_client_inset(inset);
3094    }
3095
3096    /// Returns the client_inset value by [`Self::set_client_inset`].
3097    pub fn client_inset(&self) -> Option<Pixels> {
3098        self.client_inset
3099    }
3100
3101    /// Returns whether the title bar window controls need to be rendered by the application (Wayland and X11)
3102    pub fn window_decorations(&self) -> Decorations {
3103        self.platform_window.window_decorations()
3104    }
3105
3106    /// Returns whether this window is resizable.
3107    pub fn is_resizable(&self) -> bool {
3108        self.is_resizable
3109    }
3110
3111    /// Returns whether this window is minimizable.
3112    pub fn is_minimizable(&self) -> bool {
3113        self.is_minimizable
3114    }
3115
3116    /// Returns the controls supported by the platform.
3117    pub fn window_controls(&self) -> WindowControls {
3118        self.platform_window.window_controls()
3119    }
3120
3121    /// Updates the window's title at the platform level.
3122    pub fn set_window_title(&mut self, title: &str) {
3123        self.platform_window.set_title(title);
3124        self.a11y.set_window_title(title.to_string());
3125    }
3126
3127    /// Sets the position of the macOS traffic light buttons.
3128    #[cfg(target_os = "macos")]
3129    pub fn set_traffic_light_position(&self, position: Point<Pixels>) {
3130        self.platform_window.set_traffic_light_position(position);
3131    }
3132
3133    /// Sets the application identifier.
3134    pub fn set_app_id(&mut self, app_id: &str) {
3135        self.platform_window.set_app_id(app_id);
3136    }
3137
3138    /// Negotiate this window's color presentation without reinterpreting UI colors.
3139    /// Call during construction or an event update, outside layout/prepaint/paint.
3140    /// Unsupported requests and negotiation failures leave the previous state intact.
3141    pub fn set_color_mode(
3142        &mut self,
3143        mode: crate::WindowColorMode,
3144    ) -> anyhow::Result<crate::WindowColorStatus> {
3145        anyhow::ensure!(
3146            self.invalidator.not_drawing(),
3147            "cannot change color presentation during drawing"
3148        );
3149        let status = self.platform_window.set_color_mode(mode)?;
3150        self.refresh();
3151        Ok(status)
3152    }
3153
3154    /// Inspect this window's last negotiated color configuration.
3155    pub fn color_status(&self) -> crate::WindowColorStatus {
3156        self.platform_window.color_status()
3157    }
3158
3159    /// Sets the window background appearance. Native Metal wide-SDR mode requires
3160    /// opacity: disable it before requesting transparency. While it is enabled,
3161    /// transparent requests preserve the opaque window and emit a warning.
3162    pub fn set_background_appearance(&self, background_appearance: WindowBackgroundAppearance) {
3163        self.platform_window
3164            .set_background_appearance(background_appearance);
3165    }
3166
3167    /// Mark the window as dirty at the platform level.
3168    pub fn set_window_edited(&mut self, edited: bool) {
3169        self.platform_window.set_edited(edited);
3170    }
3171
3172    /// Set the path of the file this window represents.
3173    /// On macOS, this sets the window's accessibility document property (AXDocument).
3174    pub fn set_document_path(&self, path: Option<&std::path::Path>) {
3175        self.platform_window.set_document_path(path);
3176    }
3177
3178    /// Determine the display on which the window is visible.
3179    pub fn display(&self, cx: &App) -> Option<Rc<dyn PlatformDisplay>> {
3180        cx.platform
3181            .displays()
3182            .into_iter()
3183            .find(|display| Some(display.id()) == self.display_id)
3184    }
3185
3186    /// Show the platform character palette.
3187    pub fn show_character_palette(&self) {
3188        self.platform_window.show_character_palette();
3189    }
3190
3191    /// The scale factor of the display associated with the window. For example, it could
3192    /// return 2.0 for a "retina" display, indicating that each logical pixel should actually
3193    /// be rendered as two pixels on screen.
3194    pub fn scale_factor(&self) -> f32 {
3195        self.scale_factor
3196    }
3197
3198    /// Overrides the display scale factor for tests.
3199    #[cfg(any(test, feature = "test-support"))]
3200    pub fn set_scale_factor(&mut self, scale_factor: f32) {
3201        self.scale_factor = scale_factor;
3202        self.refresh();
3203    }
3204
3205    /// The size of an em for the base font of the application. Adjusting this value allows the
3206    /// UI to scale, just like zooming a web page.
3207    pub fn rem_size(&self) -> Pixels {
3208        self.rem_size_override_stack
3209            .last()
3210            .copied()
3211            .unwrap_or(self.rem_size)
3212    }
3213
3214    /// Sets the size of an em for the base font of the application. Adjusting this value allows the
3215    /// UI to scale, just like zooming a web page.
3216    pub fn set_rem_size(&mut self, rem_size: impl Into<Pixels>) {
3217        self.rem_size = rem_size.into();
3218    }
3219
3220    /// Acquire a globally unique identifier for the given ElementId.
3221    /// Only valid for the duration of the provided closure.
3222    pub fn with_global_id<R>(
3223        &mut self,
3224        element_id: ElementId,
3225        f: impl FnOnce(&GlobalElementId, &mut Self) -> R,
3226    ) -> R {
3227        self.with_id(element_id, |this| {
3228            let global_id = this.element_id_stack.global_id();
3229
3230            f(&global_id, this)
3231        })
3232    }
3233
3234    /// Calls the provided closure with the element ID pushed on the stack.
3235    #[inline]
3236    pub fn with_id<R>(
3237        &mut self,
3238        element_id: impl Into<ElementId>,
3239        f: impl FnOnce(&mut Self) -> R,
3240    ) -> R {
3241        self.element_id_stack.push(element_id.into());
3242        let result = f(self);
3243        self.element_id_stack.pop();
3244        result
3245    }
3246
3247    /// Executes the provided function with the specified rem size.
3248    ///
3249    /// This method must only be called as part of element drawing.
3250    // This function is called in a highly recursive manner in editor
3251    // prepainting, make sure its inlined to reduce the stack burden
3252    #[inline]
3253    pub fn with_rem_size<F, R>(&mut self, rem_size: Option<impl Into<Pixels>>, f: F) -> R
3254    where
3255        F: FnOnce(&mut Self) -> R,
3256    {
3257        self.invalidator.debug_assert_paint_or_prepaint();
3258
3259        if let Some(rem_size) = rem_size {
3260            self.rem_size_override_stack.push(rem_size.into());
3261            let result = f(self);
3262            self.rem_size_override_stack.pop();
3263            result
3264        } else {
3265            f(self)
3266        }
3267    }
3268
3269    /// The line height associated with the current text style.
3270    pub fn line_height(&self) -> Pixels {
3271        self.text_style().line_height_in_pixels(self.rem_size())
3272    }
3273
3274    /// Rounds a logical value to the nearest device pixel.
3275    #[inline]
3276    pub fn pixel_snap(&self, value: Pixels) -> Pixels {
3277        px(round_to_device_pixel(value.0, self.scale_factor()) / self.scale_factor())
3278    }
3279
3280    /// f64 variant of [`Self::pixel_snap`].
3281    #[inline]
3282    pub fn pixel_snap_f64(&self, value: f64) -> f64 {
3283        let scale_factor = f64::from(self.scale_factor());
3284        round_half_toward_zero_f64(value * scale_factor) / scale_factor
3285    }
3286
3287    /// Snaps a bounds' origin and size to the nearest device pixel.
3288    #[inline]
3289    pub fn pixel_snap_bounds(&self, bounds: Bounds<Pixels>) -> Bounds<Pixels> {
3290        bounds.map(|c| self.pixel_snap(c))
3291    }
3292
3293    /// Snaps a point's coordinates to the nearest device pixel.
3294    #[inline]
3295    pub fn pixel_snap_point(&self, position: Point<Pixels>) -> Point<Pixels> {
3296        position.map(|c| self.pixel_snap(c))
3297    }
3298
3299    /// Returns the snapped device-space bounds used to paint an underline.
3300    pub fn underline_bounds(
3301        &self,
3302        origin: Point<Pixels>,
3303        width: Pixels,
3304        style: &UnderlineStyle,
3305    ) -> Bounds<ScaledPixels> {
3306        let scale_factor = self.scale_factor();
3307        let thickness = self.snap_stroke(style.thickness);
3308        let height = if style.wavy {
3309            ScaledPixels(thickness.0 * 3.)
3310        } else {
3311            thickness
3312        };
3313        Bounds {
3314            origin: origin.map(|c| ScaledPixels(round_to_device_pixel(c.0, scale_factor))),
3315            size: size(self.snap_stroke(width), height),
3316        }
3317    }
3318
3319    /// Paints an underline excluding absolute device-space horizontal spans.
3320    pub fn paint_underline_with_exclusions(
3321        &mut self,
3322        origin: Point<Pixels>,
3323        width: Pixels,
3324        style: &UnderlineStyle,
3325        exclusions: &[Range<ScaledPixels>],
3326    ) {
3327        self.invalidator.debug_assert_paint();
3328        let underline = self.underline(origin, width, style);
3329        if exclusions.is_empty() {
3330            self.next_frame.scene.insert_primitive(underline);
3331            return;
3332        }
3333
3334        let bounds = underline.bounds.intersect(&underline.content_mask.bounds);
3335        if bounds.is_empty() {
3336            return;
3337        }
3338
3339        let mut exclusions = exclusions
3340            .iter()
3341            .filter_map(|span| {
3342                let start = span.start.max(bounds.left());
3343                let end = span.end.min(bounds.right());
3344                (start < end).then_some(start..end)
3345            })
3346            .collect::<SmallVec<[_; 4]>>();
3347        if exclusions.is_empty() {
3348            self.next_frame.scene.insert_primitive(underline);
3349            return;
3350        }
3351        exclusions.sort_unstable_by_key(|span| span.start);
3352
3353        let mut paint_span = |start, end| {
3354            self.next_frame.scene.insert_primitive(Underline {
3355                content_mask: ContentMask {
3356                    bounds: Bounds::from_corners(
3357                        point(start, bounds.top()),
3358                        point(end, bounds.bottom()),
3359                    ),
3360                },
3361                ..underline
3362            });
3363        };
3364        let mut start = bounds.left();
3365        for exclusion in exclusions {
3366            if start < exclusion.start {
3367                paint_span(start, exclusion.start);
3368            }
3369            start = start.max(exclusion.end);
3370        }
3371        if start < bounds.right() {
3372            paint_span(start, bounds.right());
3373        }
3374    }
3375
3376    fn underline(&self, origin: Point<Pixels>, width: Pixels, style: &UnderlineStyle) -> Underline {
3377        Underline {
3378            order: 0,
3379            pad: 0,
3380            bounds: self.underline_bounds(origin, width, style),
3381            content_mask: self.snapped_content_mask(),
3382            color: style
3383                .color
3384                .unwrap_or_default()
3385                .opacity(self.element_opacity()),
3386            thickness: self.snap_stroke(style.thickness),
3387            wavy: style.wavy.into(),
3388        }
3389    }
3390
3391    #[inline]
3392    fn snap_bounds(&self, bounds: Bounds<Pixels>) -> Bounds<ScaledPixels> {
3393        let scale_factor = self.scale_factor();
3394        let left = round_to_device_pixel(bounds.left().0, scale_factor);
3395        let top = round_to_device_pixel(bounds.top().0, scale_factor);
3396        let right = round_to_device_pixel(bounds.right().0, scale_factor).max(left);
3397        let bottom = round_to_device_pixel(bounds.bottom().0, scale_factor).max(top);
3398        Bounds::from_corners(
3399            point(ScaledPixels(left), ScaledPixels(top)),
3400            point(ScaledPixels(right), ScaledPixels(bottom)),
3401        )
3402    }
3403
3404    /// Rounds half-to-zero but clamps any non-zero input up to 1 dp so thin strokes do not disappear.
3405    #[inline]
3406    fn snap_stroke(&self, value: Pixels) -> ScaledPixels {
3407        ScaledPixels(round_stroke_to_device_pixel(value.0, self.scale_factor()))
3408    }
3409
3410    #[inline]
3411    fn snap_border_widths(&self, edges: Edges<Pixels>) -> Edges<ScaledPixels> {
3412        edges.map(|e| self.snap_stroke(*e))
3413    }
3414
3415    /// Floors the near edge and ceils the far edge, producing a strict superset of the raw region.
3416    #[inline]
3417    fn cover_bounds(&self, bounds: Bounds<Pixels>) -> Bounds<ScaledPixels> {
3418        let scale_factor = self.scale_factor();
3419        // Rounding a zero-width fractional clip outward can invent a pixel
3420        // outside a layer capture when the clipped glyph lies beyond its tile.
3421        if bounds.is_empty() {
3422            return Bounds::new(bounds.origin.scale(scale_factor), Size::default());
3423        }
3424        let left = floor_to_device_pixel(bounds.left().0, scale_factor);
3425        let top = floor_to_device_pixel(bounds.top().0, scale_factor);
3426        let right = ceil_to_device_pixel(bounds.right().0, scale_factor).max(left);
3427        let bottom = ceil_to_device_pixel(bounds.bottom().0, scale_factor).max(top);
3428        Bounds::from_corners(
3429            point(ScaledPixels(left), ScaledPixels(top)),
3430            point(ScaledPixels(right), ScaledPixels(bottom)),
3431        )
3432    }
3433
3434    #[inline]
3435    fn snapped_content_mask(&self) -> ContentMask<ScaledPixels> {
3436        ContentMask {
3437            bounds: self.cover_bounds(self.content_mask().bounds),
3438        }
3439    }
3440
3441    /// Call to prevent the default action of an event. Currently only used to prevent
3442    /// parent elements from becoming focused on mouse down.
3443    pub fn prevent_default(&mut self) {
3444        self.default_prevented = true;
3445    }
3446
3447    /// Obtain whether default has been prevented for the event currently being dispatched.
3448    pub fn default_prevented(&self) -> bool {
3449        self.default_prevented
3450    }
3451
3452    /// Determine whether the given action is available along the dispatch path to the currently focused element.
3453    pub fn is_action_available(&self, action: &dyn Action, cx: &App) -> bool {
3454        let node_id =
3455            self.focus_node_id_in_rendered_frame(self.focused(cx).map(|handle| handle.id));
3456        self.rendered_frame
3457            .dispatch_tree
3458            .is_action_available(action, node_id)
3459    }
3460
3461    /// Determine whether the given action is available along the dispatch path to the given focus_handle.
3462    pub fn is_action_available_in(&self, action: &dyn Action, focus_handle: &FocusHandle) -> bool {
3463        let node_id = self.focus_node_id_in_rendered_frame(Some(focus_handle.id));
3464        self.rendered_frame
3465            .dispatch_tree
3466            .is_action_available(action, node_id)
3467    }
3468
3469    /// The position of the mouse relative to the window.
3470    pub fn mouse_position(&self) -> Point<Pixels> {
3471        self.mouse_position
3472    }
3473
3474    /// Captures the pointer for the given hitbox. While captured, all mouse move and mouse up
3475    /// events will be routed to listeners that check this hitbox's `is_hovered` status,
3476    /// regardless of actual hit testing. This enables drag operations that continue
3477    /// even when the pointer moves outside the element's bounds.
3478    ///
3479    /// The capture is automatically released on mouse up.
3480    pub fn capture_pointer(&mut self, hitbox_id: HitboxId) {
3481        self.captured_hitbox = Some(hitbox_id);
3482    }
3483
3484    /// Releases any active pointer capture.
3485    pub fn release_pointer(&mut self) {
3486        self.captured_hitbox = None;
3487    }
3488
3489    /// Returns the hitbox that has captured the pointer, if any.
3490    pub fn captured_hitbox(&self) -> Option<HitboxId> {
3491        self.captured_hitbox
3492    }
3493
3494    /// Captures the current long press for the given entity.
3495    ///
3496    /// The capture is released when the gesture ends or is cancelled, or when
3497    /// a replacement touch begins. A listener must also call
3498    /// [`Self::prevent_default`] on the started event to claim the gesture.
3499    pub fn capture_long_press<T: 'static>(&mut self, entity: &Entity<T>) {
3500        self.long_press_capture = Some(entity.entity_id());
3501    }
3502
3503    /// Returns whether the given entity has captured the current long press.
3504    pub fn has_long_press_capture<T: 'static>(&self, entity: &Entity<T>) -> bool {
3505        self.long_press_capture == Some(entity.entity_id())
3506    }
3507
3508    /// The current state of the keyboard's modifiers
3509    pub fn modifiers(&self) -> Modifiers {
3510        self.modifiers
3511    }
3512
3513    /// Returns true if the last input event was keyboard-based (key press, tab navigation, etc.)
3514    /// This is used for focus-visible styling to show focus indicators only for keyboard navigation.
3515    pub fn last_input_was_keyboard(&self) -> bool {
3516        self.last_input_modality == InputModality::Keyboard
3517    }
3518
3519    /// Returns whether the last input event came from a touch screen.
3520    pub fn last_input_was_touch(&self) -> bool {
3521        self.last_input_modality == InputModality::Touch
3522    }
3523
3524    /// The current state of the keyboard's capslock
3525    pub fn capslock(&self) -> Capslock {
3526        self.capslock
3527    }
3528
3529    /// Produces a new frame and assigns it to `rendered_frame`. To actually show
3530    /// the contents of the new [`Scene`], use [`Self::present`].
3531    #[profiling::function]
3532    pub fn draw(&mut self, cx: &mut App) -> ArenaClearNeeded {
3533        // Drain every draw in profiler builds so a previous frame's
3534        // first-invalidation timestamp can't be attributed to this one.
3535        #[cfg(feature = "profiler")]
3536        let frame_dirty = self.invalidator.take_frame_dirty();
3537        #[cfg(feature = "profiler")]
3538        self.window_profiler.begin_draw();
3539
3540        // Set up the per-App arena for element allocation during this draw.
3541        // This ensures that multiple test Apps have isolated arenas.
3542        let arena_scope = ElementArenaScope::enter(&cx.element_arena);
3543
3544        if self.platform_window.prepare_frame() {
3545            self.refresh();
3546        }
3547        self.invalidate_entities();
3548        cx.entities.clear_accessed();
3549        debug_assert!(self.rendered_entity_stack.is_empty());
3550        self.invalidator.set_dirty(false);
3551        self.requested_autoscroll = None;
3552
3553        // Restore the previously-used input handler.
3554        // Place it back into a None slot (left by a previous .take()) so that
3555        // cached paint_range indices in reuse_paint find the handler at the
3556        // expected position.
3557        if let Some(input_handler) = self.platform_window.take_input_handler() {
3558            if let Some(slot) = self
3559                .rendered_frame
3560                .input_handlers
3561                .iter_mut()
3562                .rev()
3563                .find(|h| h.is_none())
3564            {
3565                *slot = Some(input_handler);
3566            } else {
3567                self.rendered_frame.input_handlers.push(Some(input_handler));
3568            }
3569        }
3570        if !cx.mode.skip_drawing() {
3571            self.draw_roots(cx);
3572            #[cfg(feature = "profiler")]
3573            {
3574                let viewport_size = self.viewport_size;
3575                let scale_factor = self.scale_factor();
3576                self.debug_frame_overlay.paint(
3577                    &mut self.next_frame.scene,
3578                    viewport_size,
3579                    scale_factor,
3580                );
3581            }
3582        }
3583        self.dirty_views.clear();
3584        self.next_frame.window_active = self.active.get();
3585
3586        // Register requested input handler with the platform window.
3587        // Use .take() instead of .pop() to preserve Vec length, so that cached
3588        // paint_range indices remain valid for reuse_paint on the next frame.
3589        // Search backwards to find the last Some entry, since reuse_paint may
3590        // have copied None slots from the previous frame. (Fixes #50456)
3591        let focused_text_input = if let Some(mut input_handler) = self
3592            .next_frame
3593            .input_handlers
3594            .iter_mut()
3595            .rev()
3596            .find_map(|h| h.take())
3597        {
3598            let accepts_text_input = input_handler.accepts_text_input(self, cx);
3599            self.platform_window.set_input_handler(input_handler);
3600            self.focus.filter(|_| accepts_text_input)
3601        } else {
3602            None
3603        };
3604        self.apply_text_input_configuration(cx);
3605        let previous = mem::replace(&mut self.focused_text_input, focused_text_input);
3606        if previous.is_some() != focused_text_input.is_some() {
3607            self.platform_window
3608                .text_input_state_changed(if focused_text_input.is_some() {
3609                    TextInputStateChange::FocusGained
3610                } else {
3611                    TextInputStateChange::FocusLost
3612                });
3613        }
3614
3615        self.layout_engine.as_mut().unwrap().clear();
3616        self.text_system().finish_frame();
3617        self.next_frame.finish(&mut self.rendered_frame);
3618
3619        self.invalidator.set_phase(DrawPhase::Focus);
3620        let previous_focus_path = self.rendered_frame.focus_path();
3621        let previous_window_active = self.rendered_frame.window_active;
3622        mem::swap(&mut self.rendered_frame, &mut self.next_frame);
3623        self.next_frame.clear();
3624        let current_focus_path = self.rendered_frame.focus_path();
3625        let current_window_active = self.rendered_frame.window_active;
3626        let mut focus_before_listeners = self.focus;
3627
3628        if previous_focus_path != current_focus_path
3629            || previous_window_active != current_window_active
3630        {
3631            if !previous_focus_path.is_empty() && current_focus_path.is_empty() {
3632                self.focus_lost_path = previous_focus_path.clone();
3633                self.focus_lost_listeners
3634                    .clone()
3635                    .retain(|listener| listener(self, cx));
3636                self.focus_lost_path = SmallVec::new();
3637                // The focus-lost fallback (e.g. a workspace refocusing itself) may target
3638                // an element that isn't part of the element tree, in which case scheduling
3639                // a redraw below would dispatch focus-lost again, looping forever. Only
3640                // track focus movement caused by the focus listeners.
3641                focus_before_listeners = self.focus;
3642            }
3643
3644            let event = WindowFocusEvent {
3645                previous_focus_path: if previous_window_active {
3646                    previous_focus_path
3647                } else {
3648                    Default::default()
3649                },
3650                current_focus_path: if current_window_active {
3651                    current_focus_path
3652                } else {
3653                    Default::default()
3654                },
3655            };
3656            self.focus_listeners
3657                .clone()
3658                .retain(|listener| listener(&event, self, cx));
3659        }
3660
3661        debug_assert!(self.rendered_entity_stack.is_empty());
3662        self.record_entities_accessed(cx);
3663        self.reset_cursor_style(cx);
3664        self.refreshing = false;
3665        self.invalidator.set_phase(DrawPhase::None);
3666        // Focus listeners may move focus (e.g. a dock forwarding focus to its active
3667        // panel). `Window::focus` suppresses `refresh` while a draw is in progress, so
3668        // schedule another frame here to render the new focus state and dispatch the
3669        // resulting focus events.
3670        if self.focus != focus_before_listeners {
3671            self.refresh();
3672        }
3673        self.needs_present.set(true);
3674
3675        #[cfg(feature = "profiler")]
3676        {
3677            self.window_profiler
3678                .set_refresh_interval(self.refresh_interval(cx));
3679            let draw_duration = self
3680                .window_profiler
3681                .end_draw(frame_dirty.dirty_at, frame_dirty.invalidations);
3682            self.debug_frame_overlay.record_frame(draw_duration);
3683        }
3684
3685        // Exit the scope to obtain the arena-clear token this draw owes; the
3686        // scope's teardown itself happens in `ElementArenaScope::drop`.
3687        arena_scope.exit(&cx.element_arena)
3688    }
3689
3690    fn record_entities_accessed(&mut self, cx: &mut App) {
3691        let mut entities_ref = cx.entities.accessed_entities.get_mut();
3692        let mut entities = mem::take(entities_ref.deref_mut());
3693        let handle = self.handle;
3694        cx.record_entities_accessed(
3695            handle,
3696            // Try moving window invalidator into the Window
3697            self.invalidator.clone(),
3698            &entities,
3699        );
3700        let mut entities_ref = cx.entities.accessed_entities.get_mut();
3701        mem::swap(&mut entities, entities_ref.deref_mut());
3702    }
3703
3704    fn invalidate_entities(&mut self) {
3705        let mut views = self.invalidator.take_views();
3706        for entity in views.drain() {
3707            self.mark_view_dirty(entity);
3708        }
3709        self.invalidator.replace_views(views);
3710    }
3711
3712    /// Submit the recorded scene on this window's actual native renderer.
3713    /// Native lifecycle tests use this instead of presentation/readback waits.
3714    #[cfg(any(test, feature = "test-support"))]
3715    pub fn submit_frame_for_validation(&self) -> anyhow::Result<()> {
3716        self.platform_window
3717            .submit_scene_for_validation(&self.rendered_frame.scene)
3718    }
3719
3720    #[profiling::function]
3721    fn present(&mut self) {
3722        #[cfg(feature = "profiler")]
3723        let _foreground_turn = profiler::journal::foreground_turn();
3724        #[cfg(feature = "profiler")]
3725        let present_start = Instant::now();
3726        self.platform_window.draw(&self.rendered_frame.scene);
3727        #[cfg(feature = "profiler")]
3728        self.window_profiler.record_present(
3729            present_start,
3730            Instant::now(),
3731            self.active.get(),
3732            !self.next_frame_callbacks.borrow().is_empty(),
3733        );
3734        self.needs_present.set(false);
3735        profiling::finish_frame!();
3736    }
3737
3738    /// Presents the most recently drawn frame if it hasn't been presented yet.
3739    #[cfg(all(test, feature = "profiler"))]
3740    pub fn present_if_needed(&mut self) {
3741        if self.needs_present.get() {
3742            self.present();
3743        }
3744    }
3745
3746    /// Returns a snapshot of the current input-latency histograms.
3747    #[cfg(feature = "profiler")]
3748    pub fn input_latency_snapshot(&self) -> profiler::InputLatencySnapshot {
3749        self.window_profiler.input_latency_snapshot()
3750    }
3751
3752    /// Returns a snapshot of the current frame-duration histograms.
3753    #[cfg(feature = "profiler")]
3754    pub fn frame_duration_snapshot(&self) -> profiler::FrameDurationSnapshot {
3755        self.window_profiler.frame_duration_snapshot()
3756    }
3757
3758    /// Returns the current mode of the debug frame overlay.
3759    #[cfg(feature = "profiler")]
3760    pub fn debug_frame_overlay_mode(&self) -> DebugFrameOverlayMode {
3761        self.debug_frame_overlay.mode()
3762    }
3763
3764    /// Sets the mode of the debug frame overlay and schedules a redraw.
3765    #[cfg(feature = "profiler")]
3766    pub fn set_debug_frame_overlay_mode(&mut self, mode: DebugFrameOverlayMode) {
3767        self.debug_frame_overlay.set_mode(mode);
3768        self.refresh();
3769    }
3770
3771    /// Advances the debug frame overlay through its hidden, frame-time-only,
3772    /// and detailed modes.
3773    #[cfg(feature = "profiler")]
3774    pub fn cycle_debug_frame_overlay_mode(&mut self) {
3775        self.set_debug_frame_overlay_mode(self.debug_frame_overlay.mode().next());
3776    }
3777
3778    /// Clears the debug frame overlay's frame-time statistics, except for the
3779    /// total frame count, and schedules a redraw.
3780    #[cfg(feature = "profiler")]
3781    pub fn reset_debug_frame_overlay_stats(&mut self) {
3782        self.debug_frame_overlay.reset_stats();
3783        self.refresh();
3784    }
3785
3786    fn draw_roots(&mut self, cx: &mut App) {
3787        self.invalidator.set_phase(DrawPhase::Prepaint);
3788        self.tooltip_bounds.take();
3789
3790        self.a11y.sync_active_flag();
3791        if self.a11y.is_active() {
3792            self.a11y.begin_frame();
3793        }
3794
3795        let _inspector_width: Pixels = rems(30.0).to_pixels(self.rem_size());
3796        let root_size = {
3797            #[cfg(debug_assertions)]
3798            {
3799                if self.inspector.is_some() {
3800                    let mut size = self.viewport_size;
3801                    size.width = (size.width - _inspector_width).max(px(0.0));
3802                    size
3803                } else {
3804                    self.viewport_size
3805                }
3806            }
3807            #[cfg(not(debug_assertions))]
3808            {
3809                self.viewport_size
3810            }
3811        };
3812
3813        // Layout all root elements. Like the root element on the web, which
3814        // stretches to fill the viewport unless explicitly sized, window roots
3815        // fill the window when their size is `auto`.
3816        let scale_factor = self.scale_factor();
3817        #[cfg(feature = "profiler")]
3818        let request_layout_start = Instant::now();
3819        let mut root_element = self.root.as_ref().unwrap().clone().into_any_element();
3820        let root_layout_id = root_element.request_layout(self, cx);
3821        #[cfg(feature = "profiler")]
3822        let prepaint_start = Instant::now();
3823        self.layout_engine
3824            .as_mut()
3825            .unwrap()
3826            .stretch_auto_size_to_fill(root_layout_id, root_size, scale_factor);
3827        root_element.prepaint_as_root(Point::default(), root_size.into(), self, cx);
3828
3829        #[cfg(debug_assertions)]
3830        let inspector_element = self.prepaint_inspector(_inspector_width, cx);
3831
3832        self.prepaint_deferred_draws(cx);
3833
3834        let mut prompt_element = None;
3835        let mut active_drag_element = None;
3836        let mut tooltip_element = None;
3837        if let Some(prompt) = self.prompt.take() {
3838            let mut element = prompt.view.any_view().into_any_element();
3839            let prompt_layout_id = element.request_layout(self, cx);
3840            self.layout_engine
3841                .as_mut()
3842                .unwrap()
3843                .stretch_auto_size_to_fill(prompt_layout_id, root_size, scale_factor);
3844            element.prepaint_as_root(Point::default(), root_size.into(), self, cx);
3845            prompt_element = Some(element);
3846            self.prompt = Some(prompt);
3847        } else if let Some(active_drag) = cx.active_drag.take() {
3848            let mut element = active_drag.view.clone().into_any_element();
3849            let offset = self.mouse_position() - active_drag.cursor_offset;
3850            element.prepaint_as_root(offset, AvailableSpace::min_size(), self, cx);
3851            active_drag_element = Some(element);
3852            cx.active_drag = Some(active_drag);
3853        } else {
3854            tooltip_element = self.prepaint_tooltip(cx);
3855        }
3856
3857        self.mouse_hit_test = self.next_frame.hit_test(self.mouse_position);
3858
3859        // Now actually paint the elements.
3860        #[cfg(feature = "profiler")]
3861        let paint_start = Instant::now();
3862        self.invalidator.set_phase(DrawPhase::Paint);
3863        root_element.paint(self, cx);
3864
3865        #[cfg(debug_assertions)]
3866        self.paint_inspector(inspector_element, cx);
3867
3868        self.paint_deferred_draws(cx);
3869
3870        if let Some(mut prompt_element) = prompt_element {
3871            prompt_element.paint(self, cx);
3872        } else if let Some(mut drag_element) = active_drag_element {
3873            drag_element.paint(self, cx);
3874        } else if let Some(mut tooltip_element) = tooltip_element {
3875            tooltip_element.paint(self, cx);
3876        }
3877
3878        #[cfg(debug_assertions)]
3879        self.paint_inspector_hitbox(cx);
3880
3881        #[cfg(feature = "profiler")]
3882        self.window_profiler
3883            .record_draw_phases(profiler::DrawPhases {
3884                request_layout: prepaint_start.duration_since(request_layout_start),
3885                prepaint: paint_start.duration_since(prepaint_start),
3886                paint: Instant::now().duration_since(paint_start),
3887            });
3888
3889        // a11y may have been activated/deactivated halfway through the frame
3890        let a11y_active_start_of_frame = self.a11y.is_active();
3891        self.a11y.sync_active_flag();
3892        let a11y_active_end_of_frame = self.a11y.is_active();
3893
3894        let should_send_a11y_update = a11y_active_start_of_frame && a11y_active_end_of_frame;
3895
3896        if a11y_active_start_of_frame {
3897            // Harvest frame metadata for the debug dump while the live window
3898            // and frame are still in scope.
3899            let frame_info = crate::window::a11y::debug::FrameDebugInfo {
3900                viewport_size: self.viewport_size,
3901                scale_factor: self.scale_factor,
3902                tab_stop_count: self.next_frame.tab_stops.tab_stop_count(),
3903            };
3904            // clear the builder state regardless
3905            let tree_update = self.a11y.end_frame(frame_info);
3906
3907            if should_send_a11y_update {
3908                log::debug!(
3909                    "Sending a11y tree update: {} nodes",
3910                    tree_update.nodes.len()
3911                );
3912                self.platform_window.a11y_tree_update(tree_update);
3913            }
3914        }
3915    }
3916
3917    fn prepaint_tooltip(&mut self, cx: &mut App) -> Option<AnyElement> {
3918        // Use indexing instead of iteration to avoid borrowing self for the duration of the loop.
3919        for tooltip_request_index in (0..self.next_frame.tooltip_requests.len()).rev() {
3920            let Some(Some(tooltip_request)) = self
3921                .next_frame
3922                .tooltip_requests
3923                .get(tooltip_request_index)
3924                .cloned()
3925            else {
3926                log::error!("Unexpectedly absent TooltipRequest");
3927                continue;
3928            };
3929            let mut element = tooltip_request.tooltip.view.clone().into_any_element();
3930            let mouse_position = tooltip_request.tooltip.mouse_position;
3931            let tooltip_size = element.layout_as_root(AvailableSpace::min_size(), self, cx);
3932
3933            let mut tooltip_bounds =
3934                Bounds::new(mouse_position + point(px(1.), px(1.)), tooltip_size);
3935            let window_bounds = Bounds {
3936                origin: Point::default(),
3937                size: self.viewport_size(),
3938            };
3939
3940            if tooltip_bounds.right() > window_bounds.right() {
3941                let new_x = mouse_position.x - tooltip_bounds.size.width - px(1.);
3942                if new_x >= Pixels::ZERO {
3943                    tooltip_bounds.origin.x = new_x;
3944                } else {
3945                    tooltip_bounds.origin.x = cmp::max(
3946                        Pixels::ZERO,
3947                        tooltip_bounds.origin.x - tooltip_bounds.right() - window_bounds.right(),
3948                    );
3949                }
3950            }
3951
3952            if tooltip_bounds.bottom() > window_bounds.bottom() {
3953                let new_y = mouse_position.y - tooltip_bounds.size.height - px(1.);
3954                if new_y >= Pixels::ZERO {
3955                    tooltip_bounds.origin.y = new_y;
3956                } else {
3957                    tooltip_bounds.origin.y = cmp::max(
3958                        Pixels::ZERO,
3959                        tooltip_bounds.origin.y - tooltip_bounds.bottom() - window_bounds.bottom(),
3960                    );
3961                }
3962            }
3963
3964            // It's possible for an element to have an active tooltip while not being painted (e.g.
3965            // via the `visible_on_hover` method). Since mouse listeners are not active in this
3966            // case, instead update the tooltip's visibility here.
3967            let is_visible =
3968                (tooltip_request.tooltip.check_visible_and_update)(tooltip_bounds, self, cx);
3969            if !is_visible {
3970                continue;
3971            }
3972
3973            self.with_absolute_element_offset(tooltip_bounds.origin, |window| {
3974                element.prepaint(window, cx)
3975            });
3976
3977            self.tooltip_bounds = Some(TooltipBounds {
3978                id: tooltip_request.id,
3979                bounds: tooltip_bounds,
3980            });
3981            return Some(element);
3982        }
3983        None
3984    }
3985
3986    fn prepaint_deferred_draws(&mut self, cx: &mut App) {
3987        assert_eq!(self.element_id_stack.len(), 0);
3988
3989        // Process deferred draws in multiple rounds to support nesting.
3990        // Each round processes all current deferred draws, which may push new ones.
3991        //
3992        // The draws are processed in place rather than being moved out of
3993        // `next_frame.deferred_draws`: `prepaint_index` snapshots that vector's
3994        // length, so any prepaint range recorded during a round (view caches,
3995        // nested deferred draws) must index the same vector `reuse_prepaint`
3996        // slices on the next frame. Moving the draws out and re-appending them
3997        // shifts the indices of nested draws, causing reused subtrees to graft
3998        // the wrong deferred draws and panic in the dispatch tree.
3999        let mut round_start = 0;
4000        let mut depth = 0;
4001        loop {
4002            let round_end = self.next_frame.deferred_draws.len();
4003            if round_start == round_end {
4004                break;
4005            }
4006            // Limit maximum nesting depth to prevent infinite loops.
4007            assert!(depth < 10, "Exceeded maximum (10) deferred depth");
4008            depth += 1;
4009
4010            // Sort this round by priority.
4011            let mut traversal_order = (round_start..round_end).collect::<SmallVec<[usize; 8]>>();
4012            traversal_order.sort_by_key(|ix| self.next_frame.deferred_draws[*ix].priority);
4013
4014            for deferred_draw_ix in traversal_order {
4015                let (element, parent_node, current_view, rem_size, absolute_offset, prepaint_range) = {
4016                    let deferred_draw = &mut self.next_frame.deferred_draws[deferred_draw_ix];
4017                    self.element_id_stack
4018                        .clone_from(&deferred_draw.element_id_stack);
4019                    self.text_style_stack
4020                        .clone_from(&deferred_draw.text_style_stack);
4021                    self.glyph_brush_stack
4022                        .clone_from(&deferred_draw.glyph_brush_stack);
4023                    (
4024                        deferred_draw.element.take(),
4025                        deferred_draw.parent_node,
4026                        deferred_draw.current_view,
4027                        deferred_draw.rem_size,
4028                        deferred_draw.absolute_offset,
4029                        deferred_draw.prepaint_range.clone(),
4030                    )
4031                };
4032                self.next_frame.dispatch_tree.set_active_node(parent_node);
4033
4034                let prepaint_start = self.prepaint_index();
4035                if let Some(mut element) = element {
4036                    self.with_rendered_view(current_view, |window| {
4037                        window.with_rem_size(Some(rem_size), |window| {
4038                            window.with_absolute_element_offset(absolute_offset, |window| {
4039                                element.prepaint(window, cx);
4040                            });
4041                        });
4042                    });
4043                    self.next_frame.deferred_draws[deferred_draw_ix].element = Some(element);
4044                } else {
4045                    self.reuse_prepaint(prepaint_range);
4046                }
4047                let prepaint_end = self.prepaint_index();
4048                self.next_frame.deferred_draws[deferred_draw_ix].prepaint_range =
4049                    prepaint_start..prepaint_end;
4050            }
4051
4052            self.element_id_stack.clear();
4053            self.text_style_stack.clear();
4054            self.glyph_brush_stack.clear();
4055            round_start = round_end;
4056        }
4057    }
4058
4059    fn paint_deferred_draws(&mut self, cx: &mut App) {
4060        assert_eq!(self.element_id_stack.len(), 0);
4061
4062        // Paint all deferred draws in priority order.
4063        // Since prepaint has already processed nested deferreds, we just paint them all.
4064        if self.next_frame.deferred_draws.len() == 0 {
4065            return;
4066        }
4067
4068        let traversal_order = self.deferred_draw_traversal_order();
4069        let mut deferred_draws = mem::take(&mut self.next_frame.deferred_draws);
4070        for deferred_draw_ix in traversal_order {
4071            let deferred_draw = &mut deferred_draws[deferred_draw_ix];
4072            self.element_id_stack
4073                .clone_from(&deferred_draw.element_id_stack);
4074            self.glyph_brush_stack
4075                .clone_from(&deferred_draw.glyph_brush_stack);
4076            self.next_frame
4077                .dispatch_tree
4078                .set_active_node(deferred_draw.parent_node);
4079
4080            let paint_start = self.paint_index();
4081            let content_mask = deferred_draw.content_mask;
4082            if let Some(element) = deferred_draw.element.as_mut() {
4083                self.with_rendered_view(deferred_draw.current_view, |window| {
4084                    window.with_content_mask(content_mask, |window| {
4085                        window.with_rem_size(Some(deferred_draw.rem_size), |window| {
4086                            element.paint(window, cx);
4087                        });
4088                    })
4089                })
4090            } else {
4091                self.reuse_paint(deferred_draw.paint_range.clone());
4092            }
4093            let paint_end = self.paint_index();
4094            deferred_draw.paint_range = paint_start..paint_end;
4095        }
4096        self.next_frame.deferred_draws = deferred_draws;
4097        self.element_id_stack.clear();
4098        self.glyph_brush_stack.clear();
4099    }
4100
4101    fn deferred_draw_traversal_order(&mut self) -> SmallVec<[usize; 8]> {
4102        let deferred_count = self.next_frame.deferred_draws.len();
4103        let mut sorted_indices = (0..deferred_count).collect::<SmallVec<[_; 8]>>();
4104        sorted_indices.sort_by_key(|ix| self.next_frame.deferred_draws[*ix].priority);
4105        sorted_indices
4106    }
4107
4108    pub(crate) fn prepaint_index(&self) -> PrepaintStateIndex {
4109        PrepaintStateIndex {
4110            hitboxes_index: self.next_frame.hitboxes.len(),
4111            tooltips_index: self.next_frame.tooltip_requests.len(),
4112            deferred_draws_index: self.next_frame.deferred_draws.len(),
4113            dispatch_tree_index: self.next_frame.dispatch_tree.len(),
4114            accessed_element_states_index: self.next_frame.accessed_element_states.len(),
4115            line_layout_index: self.text_system.layout_index(),
4116        }
4117    }
4118
4119    pub(crate) fn reuse_prepaint(&mut self, range: Range<PrepaintStateIndex>) {
4120        self.next_frame.hitboxes.extend(
4121            self.rendered_frame.hitboxes[range.start.hitboxes_index..range.end.hitboxes_index]
4122                .iter()
4123                .cloned(),
4124        );
4125        self.next_frame.tooltip_requests.extend(
4126            self.rendered_frame.tooltip_requests
4127                [range.start.tooltips_index..range.end.tooltips_index]
4128                .iter_mut()
4129                .map(|request| request.take()),
4130        );
4131        self.next_frame.accessed_element_states.extend(
4132            self.rendered_frame.accessed_element_states[range.start.accessed_element_states_index
4133                ..range.end.accessed_element_states_index]
4134                .iter()
4135                .map(|(id, type_id)| (id.clone(), *type_id)),
4136        );
4137        self.text_system
4138            .reuse_layouts(range.start.line_layout_index..range.end.line_layout_index);
4139
4140        let reused_subtree = self.next_frame.dispatch_tree.reuse_subtree(
4141            range.start.dispatch_tree_index..range.end.dispatch_tree_index,
4142            &mut self.rendered_frame.dispatch_tree,
4143            self.focus,
4144        );
4145
4146        if reused_subtree.contains_focus() {
4147            self.next_frame.focus = self.focus;
4148        }
4149
4150        self.next_frame.deferred_draws.extend(
4151            self.rendered_frame.deferred_draws
4152                [range.start.deferred_draws_index..range.end.deferred_draws_index]
4153                .iter()
4154                .map(|deferred_draw| DeferredDraw {
4155                    current_view: deferred_draw.current_view,
4156                    parent_node: reused_subtree.refresh_node_id(deferred_draw.parent_node),
4157                    element_id_stack: deferred_draw.element_id_stack.clone(),
4158                    text_style_stack: deferred_draw.text_style_stack.clone(),
4159                    glyph_brush_stack: deferred_draw.glyph_brush_stack.clone(),
4160                    content_mask: deferred_draw.content_mask,
4161                    rem_size: deferred_draw.rem_size,
4162                    priority: deferred_draw.priority,
4163                    element: None,
4164                    absolute_offset: deferred_draw.absolute_offset,
4165                    prepaint_range: deferred_draw.prepaint_range.clone(),
4166                    paint_range: deferred_draw.paint_range.clone(),
4167                }),
4168        );
4169    }
4170
4171    pub(crate) fn paint_index(&self) -> PaintIndex {
4172        PaintIndex {
4173            scene_index: self.next_frame.scene.len(),
4174            #[cfg(any(test, feature = "test-support"))]
4175            debug_bounds_index: self.next_frame.debug_bounds_records.len(),
4176            mouse_listeners_index: self.next_frame.mouse_listeners.len(),
4177            input_handlers_index: self.next_frame.input_handlers.len(),
4178            cursor_styles_index: self.next_frame.cursor_styles.len(),
4179            accessed_element_states_index: self.next_frame.accessed_element_states.len(),
4180            tab_handle_index: self.next_frame.tab_stops.paint_index(),
4181            line_layout_index: self.text_system.layout_index(),
4182        }
4183    }
4184
4185    pub(crate) fn reuse_paint(&mut self, range: Range<PaintIndex>) {
4186        // Cached elements still exist in the frame even when their paint methods don't run.
4187        #[cfg(any(test, feature = "test-support"))]
4188        for (selector, bounds) in &self.rendered_frame.debug_bounds_records
4189            [range.start.debug_bounds_index..range.end.debug_bounds_index]
4190        {
4191            self.next_frame
4192                .record_debug_bounds(selector.clone(), *bounds);
4193        }
4194        self.next_frame.cursor_styles.extend(
4195            self.rendered_frame.cursor_styles
4196                [range.start.cursor_styles_index..range.end.cursor_styles_index]
4197                .iter()
4198                .cloned(),
4199        );
4200        self.next_frame.input_handlers.extend(
4201            self.rendered_frame.input_handlers
4202                [range.start.input_handlers_index..range.end.input_handlers_index]
4203                .iter_mut()
4204                .map(|handler| handler.take()),
4205        );
4206        self.next_frame.mouse_listeners.extend(
4207            self.rendered_frame.mouse_listeners
4208                [range.start.mouse_listeners_index..range.end.mouse_listeners_index]
4209                .iter_mut()
4210                .map(|listener| listener.take()),
4211        );
4212        self.next_frame.accessed_element_states.extend(
4213            self.rendered_frame.accessed_element_states[range.start.accessed_element_states_index
4214                ..range.end.accessed_element_states_index]
4215                .iter()
4216                .map(|(id, type_id)| (id.clone(), *type_id)),
4217        );
4218        self.next_frame.tab_stops.replay(
4219            &self.rendered_frame.tab_stops.insertion_history
4220                [range.start.tab_handle_index..range.end.tab_handle_index],
4221        );
4222
4223        self.text_system
4224            .reuse_layouts(range.start.line_layout_index..range.end.line_layout_index);
4225        self.next_frame.scene.replay(
4226            range.start.scene_index..range.end.scene_index,
4227            &self.rendered_frame.scene,
4228        );
4229    }
4230
4231    /// Push a text style onto the stack, and call a function with that style active.
4232    /// Use [`Window::text_style`] to get the current, combined text style. This method
4233    /// should only be called as part of element drawing.
4234    pub fn with_text_style<F, R>(&mut self, style: Option<TextStyleRefinement>, f: F) -> R
4235    where
4236        F: FnOnce(&mut Self) -> R,
4237    {
4238        self.invalidator.debug_assert_paint_or_prepaint();
4239        if let Some(style) = style {
4240            self.text_style_stack.push(style);
4241            let result = f(self);
4242            self.text_style_stack.pop();
4243            result
4244        } else {
4245            f(self)
4246        }
4247    }
4248
4249    /// Updates the cursor style at the platform level. This method should only be called
4250    /// during the paint phase of element drawing.
4251    pub fn set_cursor_style(&mut self, style: CursorStyle, hitbox: &Hitbox) {
4252        self.invalidator.debug_assert_paint();
4253        self.next_frame.cursor_styles.push(CursorStyleRequest {
4254            hitbox_id: Some(hitbox.id),
4255            style,
4256        });
4257    }
4258
4259    /// Updates the cursor style for the entire window at the platform level. A cursor
4260    /// style using this method will have precedence over any cursor style set using
4261    /// `set_cursor_style`. This method should only be called during the paint
4262    /// phase of element drawing.
4263    pub fn set_window_cursor_style(&mut self, style: CursorStyle) {
4264        self.invalidator.debug_assert_paint();
4265        self.next_frame.cursor_styles.push(CursorStyleRequest {
4266            hitbox_id: None,
4267            style,
4268        })
4269    }
4270
4271    /// Sets a tooltip to be rendered for the upcoming frame. This method should only be called
4272    /// during the paint phase of element drawing.
4273    pub fn set_tooltip(&mut self, tooltip: AnyTooltip) -> TooltipId {
4274        self.invalidator.debug_assert_prepaint();
4275        let id = TooltipId(post_inc(&mut self.next_tooltip_id.0));
4276        self.next_frame
4277            .tooltip_requests
4278            .push(Some(TooltipRequest { id, tooltip }));
4279        id
4280    }
4281
4282    /// Invoke the given function with the given content mask after intersecting it
4283    /// with the current mask. This method should only be called during element drawing.
4284    // This function is called in a highly recursive manner in editor
4285    // prepainting, make sure its inlined to reduce the stack burden
4286    #[inline]
4287    pub fn with_content_mask<R>(
4288        &mut self,
4289        mask: Option<ContentMask<Pixels>>,
4290        f: impl FnOnce(&mut Self) -> R,
4291    ) -> R {
4292        self.invalidator.debug_assert_paint_or_prepaint();
4293        if let Some(mask) = mask {
4294            let mask = mask.intersect(&self.content_mask());
4295            self.content_mask_stack.push(mask);
4296            let result = f(self);
4297            self.content_mask_stack.pop();
4298            result
4299        } else {
4300            f(self)
4301        }
4302    }
4303
4304    /// Updates the global element offset relative to the current offset. This is used to implement
4305    /// scrolling. This method should only be called during the prepaint phase of element drawing.
4306    pub fn with_element_offset<R>(
4307        &mut self,
4308        offset: Point<Pixels>,
4309        f: impl FnOnce(&mut Self) -> R,
4310    ) -> R {
4311        self.invalidator.debug_assert_prepaint();
4312
4313        if offset.is_zero() {
4314            return f(self);
4315        };
4316
4317        let abs_offset = self.element_offset() + offset;
4318        self.with_absolute_element_offset(abs_offset, f)
4319    }
4320
4321    /// Updates the global element offset based on the given offset. This is used to implement
4322    /// drag handles and other manual painting of elements. This method should only be called during
4323    /// the prepaint phase of element drawing.
4324    pub fn with_absolute_element_offset<R>(
4325        &mut self,
4326        offset: Point<Pixels>,
4327        f: impl FnOnce(&mut Self) -> R,
4328    ) -> R {
4329        self.invalidator.debug_assert_prepaint();
4330        self.element_offset_stack.push(offset);
4331        let result = f(self);
4332        self.element_offset_stack.pop();
4333        result
4334    }
4335
4336    /// Multiply inherited opacity while painting or prepainting a custom element.
4337    pub fn with_element_opacity<R>(
4338        &mut self,
4339        opacity: Option<f32>,
4340        f: impl FnOnce(&mut Self) -> R,
4341    ) -> R {
4342        self.invalidator.debug_assert_paint_or_prepaint();
4343
4344        let Some(opacity) = opacity else {
4345            return f(self);
4346        };
4347
4348        let previous_opacity = self.element_opacity;
4349        self.element_opacity = previous_opacity * opacity;
4350        let result = f(self);
4351        self.element_opacity = previous_opacity;
4352        result
4353    }
4354
4355    /// Perform prepaint on child elements in a "retryable" manner, so that any side effects
4356    /// of prepaints can be discarded before prepainting again. This is used to support autoscroll
4357    /// where we need to prepaint children to detect the autoscroll bounds, then adjust the
4358    /// element offset and prepaint again. See [`crate::List`] for an example. This method should only be
4359    /// called during the prepaint phase of element drawing.
4360    pub fn transact<T, U>(&mut self, f: impl FnOnce(&mut Self) -> Result<T, U>) -> Result<T, U> {
4361        self.invalidator.debug_assert_prepaint();
4362        let index = self.prepaint_index();
4363        let result = f(self);
4364        if result.is_err() {
4365            self.next_frame.hitboxes.truncate(index.hitboxes_index);
4366            self.next_frame
4367                .tooltip_requests
4368                .truncate(index.tooltips_index);
4369            self.next_frame
4370                .deferred_draws
4371                .truncate(index.deferred_draws_index);
4372            self.next_frame
4373                .dispatch_tree
4374                .truncate(index.dispatch_tree_index);
4375            self.next_frame
4376                .accessed_element_states
4377                .truncate(index.accessed_element_states_index);
4378            self.text_system.truncate_layouts(index.line_layout_index);
4379        }
4380        result
4381    }
4382
4383    /// When you call this method during [`Element::prepaint`], containing elements will attempt to
4384    /// scroll to cause the specified bounds to become visible. When they decide to autoscroll, they will call
4385    /// [`Element::prepaint`] again with a new set of bounds. See [`crate::List`] for an example of an element
4386    /// that supports this method being called on the elements it contains. This method should only be
4387    /// called during the prepaint phase of element drawing.
4388    pub fn request_autoscroll(&mut self, bounds: Bounds<Pixels>) {
4389        self.invalidator.debug_assert_prepaint();
4390        self.requested_autoscroll = Some(bounds);
4391    }
4392
4393    /// This method can be called from a containing element such as [`crate::List`] to support the autoscroll behavior
4394    /// described in [`Self::request_autoscroll`].
4395    pub fn take_autoscroll(&mut self) -> Option<Bounds<Pixels>> {
4396        self.invalidator.debug_assert_prepaint();
4397        self.requested_autoscroll.take()
4398    }
4399
4400    /// Asynchronously load an asset, if the asset hasn't finished loading this will return None.
4401    /// Your view will be re-drawn once the asset has finished loading.
4402    ///
4403    /// Note that the multiple calls to this method will only result in one `Asset::load` call at a
4404    /// time.
4405    pub fn use_asset<A: Asset>(&mut self, source: &A::Source, cx: &mut App) -> Option<A::Output> {
4406        cx.asset_entry::<A>(source).use_by(self.current_view())
4407    }
4408
4409    /// Asynchronously load an asset, if the asset hasn't finished loading or doesn't exist this will return None.
4410    /// Your view will not be re-drawn once the asset has finished loading.
4411    ///
4412    /// Note that the multiple calls to this method will only result in one `Asset::load` call at a
4413    /// time.
4414    pub fn get_asset<A: Asset>(&mut self, source: &A::Source, cx: &mut App) -> Option<A::Output> {
4415        cx.fetch_asset::<A>(source)
4416    }
4417    /// Obtain the current element offset. This method should only be called during the
4418    /// prepaint phase of element drawing.
4419    pub fn element_offset(&self) -> Point<Pixels> {
4420        self.invalidator.debug_assert_prepaint();
4421        self.element_offset_stack
4422            .last()
4423            .copied()
4424            .unwrap_or_default()
4425    }
4426
4427    /// Obtain the current inherited element opacity during element drawing.
4428    /// Asynchronous producers can avoid requesting frames for fully hidden content.
4429    #[inline]
4430    pub fn element_opacity(&self) -> f32 {
4431        self.invalidator.debug_assert_paint_or_prepaint();
4432        self.element_opacity
4433    }
4434
4435    /// Obtain the current content mask. This method should only be called during element drawing.
4436    pub fn content_mask(&self) -> ContentMask<Pixels> {
4437        self.invalidator.debug_assert_paint_or_prepaint();
4438        self.content_mask_stack
4439            .last()
4440            .cloned()
4441            .unwrap_or_else(|| ContentMask {
4442                bounds: Bounds {
4443                    origin: Point::default(),
4444                    size: self.viewport_size,
4445                },
4446            })
4447    }
4448
4449    /// Provide elements in the called function with a new namespace in which their identifiers must be unique.
4450    /// This can be used within a custom element to distinguish multiple sets of child elements.
4451    pub fn with_element_namespace<R>(
4452        &mut self,
4453        element_id: impl Into<ElementId>,
4454        f: impl FnOnce(&mut Self) -> R,
4455    ) -> R {
4456        self.element_id_stack.push(element_id.into());
4457        let result = f(self);
4458        self.element_id_stack.pop();
4459        result
4460    }
4461
4462    /// Use a piece of state that exists as long this element is being rendered in consecutive frames.
4463    pub fn use_keyed_state<S: 'static>(
4464        &mut self,
4465        key: impl Into<ElementId>,
4466        cx: &mut App,
4467        init: impl FnOnce(&mut Self, &mut Context<S>) -> S,
4468    ) -> Entity<S> {
4469        let current_view = self.current_view();
4470        self.with_global_id(key.into(), |global_id, window| {
4471            window.with_element_state(global_id, |state: Option<Entity<S>>, window| {
4472                if let Some(state) = state {
4473                    (state.clone(), state)
4474                } else {
4475                    let new_state = cx.new(|cx| init(window, cx));
4476                    Self::observe_keyed_state(&new_state, current_view, cx);
4477                    (new_state.clone(), new_state)
4478                }
4479            })
4480        })
4481    }
4482
4483    /// Use a piece of state that exists as long this element is being rendered in consecutive frames, without needing to specify a key
4484    ///
4485    /// NOTE: This method uses the location of the caller to generate an ID for this state.
4486    ///       If this is not sufficient to identify your state (e.g. you're rendering a list item),
4487    ///       you can provide a custom ElementID using the `use_keyed_state` method.
4488    #[track_caller]
4489    pub fn use_state<S: 'static>(
4490        &mut self,
4491        cx: &mut App,
4492        init: impl FnOnce(&mut Self, &mut Context<S>) -> S,
4493    ) -> Entity<S> {
4494        self.use_keyed_state(
4495            ElementId::CodeLocation(*core::panic::Location::caller()),
4496            cx,
4497            init,
4498        )
4499    }
4500
4501    /// Updates or initializes state for an element with the given id that lives across multiple
4502    /// frames. If an element with this ID existed in the rendered frame, its state will be passed
4503    /// to the given closure. The state returned by the closure will be stored so it can be referenced
4504    /// when drawing the next frame. This method should only be called as part of element drawing.
4505    #[inline(always)]
4506    pub fn with_element_state<S, R>(
4507        &mut self,
4508        global_id: &GlobalElementId,
4509        f: impl FnOnce(Option<S>, &mut Self) -> (R, S),
4510    ) -> R
4511    where
4512        S: 'static,
4513    {
4514        self.invalidator.debug_assert_paint_or_prepaint();
4515
4516        let (key, state) = self.take_element_state(global_id, TypeId::of::<S>());
4517
4518        if let Some(any) = state {
4519            let ElementStateBox {
4520                inner,
4521                #[cfg(debug_assertions)]
4522                type_name,
4523            } = any;
4524            // Using the extra inner option to avoid needing to reallocate a new box.
4525            let mut state_box = inner
4526                .downcast::<Option<S>>()
4527                .map_err(|_| {
4528                    #[cfg(debug_assertions)]
4529                    {
4530                        anyhow::anyhow!(
4531                            "invalid element state type for id, requested {:?}, actual: {:?}",
4532                            std::any::type_name::<S>(),
4533                            type_name
4534                        )
4535                    }
4536
4537                    #[cfg(not(debug_assertions))]
4538                    {
4539                        anyhow::anyhow!(
4540                            "invalid element state type for id, requested {:?}",
4541                            std::any::type_name::<S>(),
4542                        )
4543                    }
4544                })
4545                .unwrap();
4546
4547            let state = state_box.take().expect(
4548                "reentrant call to with_element_state for the same state type and element id",
4549            );
4550            let (result, state) = f(Some(state), self);
4551            state_box.replace(state);
4552            self.insert_element_state(
4553                key,
4554                ElementStateBox {
4555                    inner: state_box,
4556                    #[cfg(debug_assertions)]
4557                    type_name,
4558                },
4559            );
4560            result
4561        } else {
4562            let (result, state) = f(None, self);
4563            self.insert_element_state(
4564                key,
4565                ElementStateBox {
4566                    inner: Box::new(Some(state)),
4567                    #[cfg(debug_assertions)]
4568                    type_name: std::any::type_name::<S>(),
4569                },
4570            );
4571            result
4572        }
4573    }
4574
4575    /// A variant of `with_element_state` that allows the element's id to be optional. This is a convenience
4576    /// method for elements where the element id may or may not be assigned. Prefer using `with_element_state`
4577    /// when the element is guaranteed to have an id.
4578    ///
4579    /// The first option means 'no ID provided'
4580    /// The second option means 'not yet initialized'
4581    pub fn with_optional_element_state<S, R>(
4582        &mut self,
4583        global_id: Option<&GlobalElementId>,
4584        f: impl FnOnce(Option<Option<S>>, &mut Self) -> (R, Option<S>),
4585    ) -> R
4586    where
4587        S: 'static,
4588    {
4589        self.invalidator.debug_assert_paint_or_prepaint();
4590
4591        if let Some(global_id) = global_id {
4592            self.with_element_state(global_id, |state, cx| {
4593                let (result, state) = f(Some(state), cx);
4594                let state =
4595                    state.expect("you must return some state when you pass some element id");
4596                (result, state)
4597            })
4598        } else {
4599            let (result, state) = f(None, self);
4600            debug_assert!(
4601                state.is_none(),
4602                "you must not return an element state when passing None for the global id"
4603            );
4604            result
4605        }
4606    }
4607
4608    /// Executes the given closure within the context of a tab group.
4609    #[inline]
4610    pub fn with_tab_group<R>(&mut self, index: Option<isize>, f: impl FnOnce(&mut Self) -> R) -> R {
4611        if let Some(index) = index {
4612            self.next_frame.tab_stops.begin_group(index);
4613            let result = f(self);
4614            self.next_frame.tab_stops.end_group();
4615            result
4616        } else {
4617            f(self)
4618        }
4619    }
4620
4621    /// Defers the drawing of the given element, scheduling it to be painted on top of the currently-drawn tree
4622    /// at a later time. The `priority` parameter determines the drawing order relative to other deferred elements,
4623    /// with higher values being drawn on top.
4624    ///
4625    /// When `content_mask` is provided, the deferred element will be clipped to that region during
4626    /// both prepaint and paint. When `None`, no additional clipping is applied.
4627    ///
4628    /// This method should only be called as part of the prepaint phase of element drawing.
4629    pub fn defer_draw(
4630        &mut self,
4631        element: AnyElement,
4632        absolute_offset: Point<Pixels>,
4633        priority: usize,
4634        content_mask: Option<ContentMask<Pixels>>,
4635    ) {
4636        self.invalidator.debug_assert_prepaint();
4637        let parent_node = self.next_frame.dispatch_tree.active_node_id().unwrap();
4638        self.next_frame.deferred_draws.push(DeferredDraw {
4639            current_view: self.current_view(),
4640            parent_node,
4641            element_id_stack: self.element_id_stack.clone(),
4642            text_style_stack: self.text_style_stack.clone(),
4643            glyph_brush_stack: self.glyph_brush_stack.clone(),
4644            content_mask,
4645            rem_size: self.rem_size(),
4646            priority,
4647            element: Some(element),
4648            absolute_offset,
4649            prepaint_range: PrepaintStateIndex::default()..PrepaintStateIndex::default(),
4650            paint_range: PaintIndex::default()..PaintIndex::default(),
4651        });
4652    }
4653
4654    /// Creates a new painting layer for the specified bounds. A "layer" is a batch
4655    /// of geometry that are non-overlapping and have the same draw order. This is typically used
4656    /// for performance reasons.
4657    ///
4658    /// This method should only be called as part of the paint phase of element drawing.
4659    pub fn paint_layer<R>(&mut self, bounds: Bounds<Pixels>, f: impl FnOnce(&mut Self) -> R) -> R {
4660        self.invalidator.debug_assert_paint();
4661
4662        let content_mask = self.content_mask();
4663        let clipped_bounds = bounds.intersect(&content_mask.bounds);
4664        if !clipped_bounds.is_empty() {
4665            self.next_frame
4666                .scene
4667                .push_layer(self.cover_bounds(clipped_bounds));
4668        }
4669
4670        let result = f(self);
4671
4672        if !clipped_bounds.is_empty() {
4673            self.next_frame.scene.pop_layer();
4674        }
4675
4676        result
4677    }
4678
4679    /// Paint the drop (non-inset) shadows from `shadows` into the scene at the current
4680    /// z-index. Inset shadows are skipped; paint those with [`Self::paint_inset_shadows`]
4681    /// after the element's background so they layer on top of the fill.
4682    ///
4683    /// This method should only be called as part of the paint phase of element drawing.
4684    pub fn paint_drop_shadows(
4685        &mut self,
4686        bounds: Bounds<Pixels>,
4687        corner_radii: Corners<Pixels>,
4688        shadows: &[BoxShadow],
4689    ) {
4690        self.invalidator.debug_assert_paint();
4691
4692        let scale_factor = self.scale_factor();
4693        let content_mask = self.snapped_content_mask();
4694        let opacity = self.element_opacity();
4695        let element_bounds = self.cover_bounds(bounds);
4696        let element_corner_radii = corner_radii.scale(scale_factor);
4697        for shadow in shadows {
4698            if shadow.inset {
4699                continue;
4700            }
4701            let shadow_bounds = (bounds + shadow.offset).dilate(shadow.spread_radius);
4702            self.next_frame.scene.insert_primitive(Shadow {
4703                order: 0,
4704                blur_radius: shadow.blur_radius.scale(scale_factor),
4705                bounds: self.cover_bounds(shadow_bounds),
4706                content_mask,
4707                corner_radii: corner_radii.scale(scale_factor),
4708                color: shadow.color.opacity(opacity),
4709                element_bounds,
4710                element_corner_radii,
4711                inset: 0,
4712                pad: 0,
4713            });
4714        }
4715    }
4716
4717    /// Paint the inset shadows from `shadows` into the scene at the current z-index. Should
4718    /// be called after the element's background so the shadow layers on top of the fill.
4719    /// Drop shadows are skipped; paint those with [`Self::paint_drop_shadows`] before the background.
4720    pub fn paint_inset_shadows(
4721        &mut self,
4722        bounds: Bounds<Pixels>,
4723        corner_radii: Corners<Pixels>,
4724        shadows: &[BoxShadow],
4725    ) {
4726        self.invalidator.debug_assert_paint();
4727
4728        let scale_factor = self.scale_factor();
4729        let content_mask = self.snapped_content_mask();
4730        let opacity = self.element_opacity();
4731        let element_bounds = self.cover_bounds(bounds);
4732        let element_corner_radii = corner_radii.scale(scale_factor);
4733        for shadow in shadows {
4734            if !shadow.inset {
4735                continue;
4736            }
4737            let hole = (bounds + shadow.offset).dilate(-shadow.spread_radius);
4738            // Clamp at zero so a large spread can't produce negative radii, which would
4739            // break the SDF in the shader.
4740            let zero = Pixels::ZERO;
4741            let hole_corner_radii = Corners {
4742                top_left: (corner_radii.top_left - shadow.spread_radius).max(zero),
4743                top_right: (corner_radii.top_right - shadow.spread_radius).max(zero),
4744                bottom_right: (corner_radii.bottom_right - shadow.spread_radius).max(zero),
4745                bottom_left: (corner_radii.bottom_left - shadow.spread_radius).max(zero),
4746            };
4747            self.next_frame.scene.insert_primitive(Shadow {
4748                order: 0,
4749                blur_radius: shadow.blur_radius.scale(scale_factor),
4750                bounds: self.cover_bounds(hole),
4751                content_mask,
4752                corner_radii: hole_corner_radii.scale(scale_factor),
4753                color: shadow.color.opacity(opacity),
4754                element_bounds,
4755                element_corner_radii,
4756                inset: 1,
4757                pad: 0,
4758            });
4759        }
4760    }
4761
4762    fn largest_border_interior(quad: &Quad) -> Bounds<ScaledPixels> {
4763        let radii = &quad.corner_radii;
4764        let widths = &quad.border_widths;
4765        let edge_radii = Edges {
4766            top: radii.top_left.max(radii.top_right),
4767            right: radii.top_right.max(radii.bottom_right),
4768            bottom: radii.bottom_left.max(radii.bottom_right),
4769            left: radii.top_left.max(radii.bottom_left),
4770        };
4771
4772        let antialias_inset = point(ScaledPixels(1.0), ScaledPixels(1.0));
4773        let inset_bounds = |top_left_inset, bottom_right_inset| {
4774            Bounds::from_corners(
4775                quad.bounds.origin + top_left_inset + antialias_inset,
4776                quad.bounds.bottom_right() - bottom_right_inset - antialias_inset,
4777            )
4778        };
4779
4780        // Rounded corners need only be excluded on one axis. Either candidate
4781        // is empty of border pixels, so use the larger interior.
4782        let horizontal_band = inset_bounds(
4783            point(widths.left, widths.top.max(edge_radii.top)),
4784            point(widths.right, widths.bottom.max(edge_radii.bottom)),
4785        );
4786        let vertical_band = inset_bounds(
4787            point(widths.left.max(edge_radii.left), widths.top),
4788            point(widths.right.max(edge_radii.right), widths.bottom),
4789        );
4790
4791        let area = |bounds: &Bounds<ScaledPixels>| {
4792            bounds.size.width.0.max(0.) * bounds.size.height.0.max(0.)
4793        };
4794        if area(&horizontal_band) >= area(&vertical_band) {
4795            horizontal_band
4796        } else {
4797            vertical_band
4798        }
4799    }
4800
4801    /// Paint one or more quads into the scene for the next frame at the current stacking context.
4802    /// Quads are colored rectangular regions with an optional background, border, and corner radius.
4803    /// see [`fill`], [`outline`], and [`quad`] to construct this type.
4804    ///
4805    /// This method should only be called as part of the paint phase of element drawing.
4806    ///
4807    /// Note that the `quad.corner_radii` are allowed to exceed the bounds, creating sharp corners
4808    /// where the circular arcs meet. This will not display well when combined with dashed borders.
4809    /// Use `Corners::clamp_radii_for_quad_size` if the radii should fit within the bounds.
4810    pub fn paint_quad(&mut self, quad: PaintQuad) {
4811        self.invalidator.debug_assert_paint();
4812
4813        let opacity = self.element_opacity();
4814        let snapped_bounds = self.snap_bounds(quad.bounds);
4815        let snapped_border_widths = self.snap_border_widths(quad.border_widths);
4816        let quad = Quad {
4817            order: 0,
4818            bounds: snapped_bounds,
4819            content_mask: self.snapped_content_mask(),
4820            background: quad.background.opacity(opacity),
4821            border_color: quad.border_color.opacity(opacity),
4822            corner_radii: quad.corner_radii.scale(self.scale_factor()),
4823            border_widths: snapped_border_widths,
4824            border_style: quad.border_style,
4825        };
4826
4827        if !quad.background.is_transparent() {
4828            self.next_frame.scene.insert_primitive(quad);
4829            return;
4830        }
4831
4832        // Splitting a border-only quad around its empty interior avoids shading
4833        // every transparent pixel inside large outlines.
4834        let outer_bounds = quad.bounds;
4835        let inner_bounds = Self::largest_border_interior(&quad);
4836
4837        if inner_bounds.is_empty() {
4838            self.next_frame.scene.insert_primitive(quad);
4839            return;
4840        }
4841
4842        let strips = [
4843            // Top
4844            Bounds::from_corners(
4845                outer_bounds.origin,
4846                point(outer_bounds.right(), inner_bounds.top()),
4847            ),
4848            // Bottom
4849            Bounds::from_corners(
4850                point(outer_bounds.left(), inner_bounds.bottom()),
4851                outer_bounds.bottom_right(),
4852            ),
4853            // Left
4854            Bounds::from_corners(
4855                point(outer_bounds.left(), inner_bounds.top()),
4856                inner_bounds.bottom_left(),
4857            ),
4858            // Right
4859            Bounds::from_corners(
4860                inner_bounds.top_right(),
4861                point(outer_bounds.right(), inner_bounds.bottom()),
4862            ),
4863        ];
4864
4865        for strip in strips {
4866            let content_mask_bounds = quad.content_mask.bounds.intersect(&strip);
4867            if !content_mask_bounds.is_empty() {
4868                self.next_frame.scene.insert_primitive(Quad {
4869                    content_mask: ContentMask {
4870                        bounds: content_mask_bounds,
4871                    },
4872                    ..quad
4873                });
4874            }
4875        }
4876    }
4877
4878    /// Paint the given `Path` into the scene for the next frame at the current z-index.
4879    ///
4880    /// This method should only be called as part of the paint phase of element drawing.
4881    pub fn paint_path(&mut self, mut path: Path<Pixels>, color: impl Into<Background>) {
4882        self.invalidator.debug_assert_paint();
4883
4884        let scale_factor = self.scale_factor();
4885        let content_mask = self.content_mask();
4886        let opacity = self.element_opacity();
4887        path.content_mask = content_mask;
4888        let color: Background = color.into();
4889        path.color = color.opacity(opacity);
4890        self.next_frame
4891            .scene
4892            .insert_primitive(path.scale(scale_factor));
4893    }
4894
4895    /// Record a validated path brush. The host applies inherited opacity once.
4896    /// Programs may evaluate direct coverage or use retained native geometry.
4897    pub fn paint_brushed_path(&mut self, mut draw: crate::ShaderDraw) {
4898        self.invalidator.debug_assert_paint();
4899        draw.opacity *= self.element_opacity();
4900        draw.content_mask.bounds = draw
4901            .content_mask
4902            .bounds
4903            .intersect(&self.content_mask().scale(self.scale_factor()).bounds);
4904        if draw.opacity <= 0. || draw.bounds.intersect(&draw.content_mask.bounds).is_empty() {
4905            return;
4906        }
4907        self.next_frame
4908            .scene
4909            .insert_primitive(crate::Primitive::Shader(draw));
4910    }
4911
4912    /// Paint an underline into the scene for the next frame at the current z-index.
4913    ///
4914    /// This method should only be called as part of the paint phase of element drawing.
4915    pub fn paint_underline(
4916        &mut self,
4917        origin: Point<Pixels>,
4918        width: Pixels,
4919        style: &UnderlineStyle,
4920    ) {
4921        self.invalidator.debug_assert_paint();
4922        let underline = self.underline(origin, width, style);
4923        self.next_frame.scene.insert_primitive(underline);
4924    }
4925
4926    /// Paint a strikethrough into the scene for the next frame at the current z-index.
4927    ///
4928    /// This method should only be called as part of the paint phase of element drawing.
4929    pub fn paint_strikethrough(
4930        &mut self,
4931        origin: Point<Pixels>,
4932        width: Pixels,
4933        style: &StrikethroughStyle,
4934    ) {
4935        self.invalidator.debug_assert_paint();
4936
4937        let scale_factor = self.scale_factor();
4938        let height = style.thickness;
4939        let bounds = Bounds {
4940            origin: origin.map(|c| ScaledPixels(round_to_device_pixel(c.0, scale_factor))),
4941            size: size(self.snap_stroke(width), self.snap_stroke(height)),
4942        };
4943        let opacity = self.element_opacity();
4944
4945        self.next_frame.scene.insert_primitive(Underline {
4946            order: 0,
4947            pad: 0,
4948            bounds,
4949            content_mask: self.snapped_content_mask(),
4950            thickness: self.snap_stroke(style.thickness),
4951            color: style.color.unwrap_or_default().opacity(opacity),
4952            wavy: false.into(),
4953        });
4954    }
4955
4956    /// Paints a monochrome (non-emoji) glyph into the scene for the next frame at the current z-index.
4957    ///
4958    /// The y component of the origin is the baseline of the glyph.
4959    /// You should generally prefer to use the [`ShapedLine::paint`](crate::ShapedLine::paint) or
4960    /// [`WrappedLine::paint`](crate::WrappedLine::paint) methods in the [`TextSystem`](crate::TextSystem).
4961    /// This method is only useful if you need to paint a single glyph that has already been shaped.
4962    ///
4963    /// This method should only be called as part of the paint phase of element drawing.
4964    pub fn paint_glyph(
4965        &mut self,
4966        origin: Point<Pixels>,
4967        font_id: FontId,
4968        glyph_id: GlyphId,
4969        font_size: Pixels,
4970        color: Hsla,
4971    ) -> Result<()> {
4972        self.invalidator.debug_assert_paint();
4973
4974        let element_opacity = self.element_opacity();
4975        let scale_factor = self.scale_factor();
4976        let glyph_origin = origin.scale(scale_factor);
4977
4978        let quantized_origin = Point::new(
4979            round_half_toward_zero(glyph_origin.x.0 * SUBPIXEL_VARIANTS_X as f32)
4980                / SUBPIXEL_VARIANTS_X as f32,
4981            round_half_toward_zero(glyph_origin.y.0 * SUBPIXEL_VARIANTS_Y as f32)
4982                / SUBPIXEL_VARIANTS_Y as f32,
4983        );
4984        let subpixel_variant = Point::new(
4985            (quantized_origin.x.fract() * SUBPIXEL_VARIANTS_X as f32) as u8,
4986            (quantized_origin.y.fract() * SUBPIXEL_VARIANTS_Y as f32) as u8,
4987        );
4988        let integer_origin = quantized_origin.map(|c| ScaledPixels(c.trunc()));
4989        let glyph_brush = self.glyph_brush_stack.last().cloned();
4990        // Colored materials use grayscale coverage; ordinary text keeps its
4991        // platform-selected grayscale/subpixel pipeline and color dilation.
4992        let subpixel_rendering = glyph_brush.is_none()
4993            && self.layer_capture_depth == 0
4994            && self.should_use_subpixel_rendering(font_id, font_size);
4995        let dilation = self
4996            .text_system()
4997            .glyph_dilation_for_color(if glyph_brush.is_some() {
4998                crate::white()
4999            } else {
5000                color
5001            });
5002        let params = RenderGlyphParams {
5003            font_id,
5004            glyph_id,
5005            font_size,
5006            subpixel_variant,
5007            scale_factor,
5008            is_emoji: false,
5009            subpixel_rendering,
5010            dilation,
5011        };
5012
5013        let raster_bounds = self.text_system().raster_bounds(&params)?;
5014        if !raster_bounds.is_zero() {
5015            let tile = self
5016                .sprite_atlas
5017                .get_or_insert_with(params.clone().into(), &mut || {
5018                    let (size, bytes) = self.text_system().rasterize_glyph(&params)?;
5019                    Ok(Some((size, Cow::Owned(bytes))))
5020                })?
5021                .expect("Callback above only errors or returns Some");
5022            let bounds = Bounds {
5023                origin: integer_origin + raster_bounds.origin.map(Into::into),
5024                size: tile.bounds.size.map(Into::into),
5025            };
5026            let content_mask = self.snapped_content_mask();
5027
5028            if let Some((brush, brush_bounds)) = glyph_brush {
5029                brush.paint_glyph(
5030                    self,
5031                    MonochromeSprite {
5032                        order: 0,
5033                        pad: 0,
5034                        bounds,
5035                        content_mask,
5036                        color: crate::white(),
5037                        tile,
5038                        transformation: TransformationMatrix::unit(),
5039                    },
5040                    brush_bounds,
5041                    element_opacity,
5042                )?;
5043            } else if subpixel_rendering {
5044                self.next_frame.scene.insert_primitive(SubpixelSprite {
5045                    order: 0,
5046                    pad: 0,
5047                    bounds,
5048                    content_mask,
5049                    color: color.opacity(element_opacity),
5050                    tile,
5051                    transformation: TransformationMatrix::unit(),
5052                });
5053            } else {
5054                self.next_frame.scene.insert_primitive(MonochromeSprite {
5055                    order: 0,
5056                    pad: 0,
5057                    bounds,
5058                    content_mask,
5059                    color: color.opacity(element_opacity),
5060                    tile,
5061                    transformation: TransformationMatrix::unit(),
5062                });
5063            }
5064        }
5065        Ok(())
5066    }
5067
5068    fn should_use_subpixel_rendering(&self, font_id: FontId, font_size: Pixels) -> bool {
5069        if self.platform_window.background_appearance() != WindowBackgroundAppearance::Opaque {
5070            return false;
5071        }
5072
5073        if !self.platform_window.is_subpixel_rendering_supported() {
5074            return false;
5075        }
5076
5077        let mode = match self.text_rendering_mode.get() {
5078            TextRenderingMode::PlatformDefault => self
5079                .text_system()
5080                .recommended_rendering_mode(font_id, font_size),
5081            mode => mode,
5082        };
5083
5084        mode == TextRenderingMode::Subpixel
5085    }
5086
5087    /// Paints an emoji glyph into the scene for the next frame at the current z-index.
5088    ///
5089    /// The y component of the origin is the baseline of the glyph.
5090    /// You should generally prefer to use the [`ShapedLine::paint`](crate::ShapedLine::paint) or
5091    /// [`WrappedLine::paint`](crate::WrappedLine::paint) methods in the [`TextSystem`](crate::TextSystem).
5092    /// This method is only useful if you need to paint a single emoji that has already been shaped.
5093    ///
5094    /// This method should only be called as part of the paint phase of element drawing.
5095    pub fn paint_emoji(
5096        &mut self,
5097        origin: Point<Pixels>,
5098        font_id: FontId,
5099        glyph_id: GlyphId,
5100        font_size: Pixels,
5101    ) -> Result<()> {
5102        self.invalidator.debug_assert_paint();
5103
5104        let scale_factor = self.scale_factor();
5105        let glyph_origin = origin.scale(scale_factor);
5106        let integer_origin = glyph_origin.map(|c| ScaledPixels(round_half_toward_zero(c.0)));
5107        let params = RenderGlyphParams {
5108            font_id,
5109            glyph_id,
5110            font_size,
5111            subpixel_variant: Default::default(),
5112            scale_factor,
5113            is_emoji: true,
5114            subpixel_rendering: false,
5115            dilation: 0,
5116        };
5117
5118        let raster_bounds = self.text_system().raster_bounds(&params)?;
5119        if !raster_bounds.is_zero() {
5120            let tile = self
5121                .sprite_atlas
5122                .get_or_insert_with(params.clone().into(), &mut || {
5123                    let (size, bytes) = self.text_system().rasterize_glyph(&params)?;
5124                    Ok(Some((size, Cow::Owned(bytes))))
5125                })?
5126                .expect("Callback above only errors or returns Some");
5127
5128            let bounds = Bounds {
5129                origin: integer_origin + raster_bounds.origin.map(Into::into),
5130                size: tile.bounds.size.map(Into::into),
5131            };
5132            let content_mask = self.snapped_content_mask();
5133            let opacity = self.element_opacity();
5134
5135            self.next_frame.scene.insert_primitive(PolychromeSprite {
5136                order: 0,
5137                pad: 0,
5138                grayscale: false.into(),
5139                bounds,
5140                corner_radii: Default::default(),
5141                content_mask,
5142                tile,
5143                opacity,
5144            });
5145        }
5146        Ok(())
5147    }
5148
5149    /// Paint a monochrome SVG into the scene for the next frame at the current stacking context.
5150    ///
5151    /// This method should only be called as part of the paint phase of element drawing.
5152    pub fn paint_svg(
5153        &mut self,
5154        bounds: Bounds<Pixels>,
5155        path: SharedString,
5156        data: Option<&[u8]>,
5157        transformation: TransformationMatrix,
5158        color: Hsla,
5159        cx: &App,
5160    ) -> Result<()> {
5161        self.invalidator.debug_assert_paint();
5162
5163        let element_opacity = self.element_opacity();
5164        let bounds = self.snap_bounds(bounds);
5165
5166        let params = RenderSvgParams {
5167            path,
5168            size: bounds.size.map(|pixels| {
5169                DevicePixels::from((pixels.0 * SMOOTH_SVG_SCALE_FACTOR).ceil() as i32)
5170            }),
5171        };
5172
5173        let Some(tile) =
5174            self.sprite_atlas
5175                .get_or_insert_with(params.clone().into(), &mut || {
5176                    let Some((size, bytes)) = cx.svg_renderer.render_alpha_mask(&params, data)?
5177                    else {
5178                        return Ok(None);
5179                    };
5180                    Ok(Some((size, Cow::Owned(bytes))))
5181                })?
5182        else {
5183            return Ok(());
5184        };
5185        let content_mask = self.snapped_content_mask();
5186        let svg_bounds = Bounds {
5187            origin: bounds.center()
5188                - Point::new(
5189                    ScaledPixels(tile.bounds.size.width.0 as f32 / SMOOTH_SVG_SCALE_FACTOR / 2.),
5190                    ScaledPixels(tile.bounds.size.height.0 as f32 / SMOOTH_SVG_SCALE_FACTOR / 2.),
5191                ),
5192            size: tile
5193                .bounds
5194                .size
5195                .map(|value| ScaledPixels(value.0 as f32 / SMOOTH_SVG_SCALE_FACTOR)),
5196        };
5197        let final_bounds = svg_bounds
5198            .map_origin(|value| ScaledPixels(round_half_toward_zero(value.0)))
5199            .map_size(|size| size.ceil());
5200
5201        self.next_frame.scene.insert_primitive(MonochromeSprite {
5202            order: 0,
5203            pad: 0,
5204            bounds: final_bounds,
5205            content_mask,
5206            color: color.opacity(element_opacity),
5207            tile,
5208            transformation,
5209        });
5210
5211        Ok(())
5212    }
5213
5214    /// Paint an image into the scene for the next frame at the current z-index.
5215    /// This method will panic if the frame_index is not valid
5216    ///
5217    /// This method should only be called as part of the paint phase of element drawing.
5218    /// Paint an image into `bounds`, positioning and scaling it according to `image_bounds`.
5219    ///
5220    /// The visible region rendered is `bounds.intersect(&image_bounds)`, with `corner_radii`
5221    /// applied to `bounds`.
5222    pub fn paint_image(
5223        &mut self,
5224        bounds: Bounds<Pixels>,
5225        image_bounds: Bounds<Pixels>,
5226        corner_radii: Corners<Pixels>,
5227        data: Arc<RenderImage>,
5228        frame_index: usize,
5229        grayscale: bool,
5230    ) -> Result<()> {
5231        self.invalidator.debug_assert_paint();
5232
5233        let visible_bounds = bounds.intersect(&image_bounds);
5234        if visible_bounds.size.width <= Pixels::ZERO || visible_bounds.size.height <= Pixels::ZERO {
5235            return Ok(());
5236        }
5237        if image_bounds.size.width <= Pixels::ZERO || image_bounds.size.height <= Pixels::ZERO {
5238            return Ok(());
5239        }
5240
5241        let params = RenderImageParams {
5242            image_id: data.id,
5243            frame_index,
5244        };
5245
5246        let tile = self
5247            .sprite_atlas
5248            .get_or_insert_with(params.into(), &mut || {
5249                Ok(Some((
5250                    data.size(frame_index),
5251                    Cow::Borrowed(
5252                        data.as_bytes(frame_index)
5253                            .expect("It's the caller's job to pass a valid frame index"),
5254                    ),
5255                )))
5256            })?
5257            .expect("Callback above only returns Some");
5258
5259        let visible_bounds_snapped = self.snap_bounds(visible_bounds);
5260
5261        let sub_tile = if visible_bounds == image_bounds {
5262            tile
5263        } else {
5264            let x_offset_ratio =
5265                (visible_bounds.origin.x - image_bounds.origin.x) / image_bounds.size.width;
5266            let y_offset_ratio =
5267                (visible_bounds.origin.y - image_bounds.origin.y) / image_bounds.size.height;
5268            let width_ratio = visible_bounds.size.width / image_bounds.size.width;
5269            let height_ratio = visible_bounds.size.height / image_bounds.size.height;
5270
5271            let tile_origin_x = tile.bounds.origin.x.0;
5272            let tile_origin_y = tile.bounds.origin.y.0;
5273            let tile_width = tile.bounds.size.width.0;
5274            let tile_height = tile.bounds.size.height.0;
5275
5276            let sub_origin_x = tile_origin_x + (x_offset_ratio * tile_width as f32).round() as i32;
5277            let sub_origin_y = tile_origin_y + (y_offset_ratio * tile_height as f32).round() as i32;
5278            let sub_width = (width_ratio * tile_width as f32).round() as i32;
5279            let sub_height = (height_ratio * tile_height as f32).round() as i32;
5280
5281            let max_x = tile_origin_x + tile_width;
5282            let max_y = tile_origin_y + tile_height;
5283
5284            let clamped_origin_x = sub_origin_x.clamp(tile_origin_x, max_x);
5285            let clamped_origin_y = sub_origin_y.clamp(tile_origin_y, max_y);
5286            let clamped_width = sub_width.min(max_x - clamped_origin_x).max(0);
5287            let clamped_height = sub_height.min(max_y - clamped_origin_y).max(0);
5288
5289            AtlasTile {
5290                bounds: Bounds {
5291                    origin: point(
5292                        DevicePixels(clamped_origin_x),
5293                        DevicePixels(clamped_origin_y),
5294                    ),
5295                    size: size(DevicePixels(clamped_width), DevicePixels(clamped_height)),
5296                },
5297                ..tile
5298            }
5299        };
5300
5301        let content_mask = self.snapped_content_mask();
5302        let corner_radii = corner_radii
5303            .clamp_radii_for_quad_size(visible_bounds.size)
5304            .scale(self.scale_factor());
5305        let opacity = self.element_opacity();
5306
5307        self.next_frame.scene.insert_primitive(PolychromeSprite {
5308            order: 0,
5309            pad: 0,
5310            grayscale: grayscale.into(),
5311            bounds: visible_bounds_snapped,
5312            content_mask,
5313            corner_radii,
5314            tile: sub_tile,
5315            opacity,
5316        });
5317        Ok(())
5318    }
5319
5320    pub(crate) fn glyph_brush_cache_key(&self) -> Option<GlyphBrushCacheKey> {
5321        self.glyph_brush_stack
5322            .last()
5323            .map(|(brush, bounds)| GlyphBrushCacheKey {
5324                identity: brush.cache_key(),
5325                bounds: *bounds,
5326            })
5327    }
5328    /// Scope a glyph brush across descendants. Establish the same scope in
5329    /// prepaint so deferred children retain their brush and original coordinates.
5330    pub fn with_glyph_brush<R>(
5331        &mut self,
5332        brush: Arc<dyn crate::GlyphBrush>,
5333        bounds: Bounds<Pixels>,
5334        f: impl FnOnce(&mut Self) -> R,
5335    ) -> R {
5336        self.glyph_brush_stack.push((brush, bounds));
5337        let result = f(self);
5338        self.glyph_brush_stack.pop();
5339        result
5340    }
5341    /// Record an atlas-masked shader with the same clipping/opacity rules as a
5342    /// monochrome glyph. Payload interpretation belongs to the extension.
5343    pub fn paint_glyph_shader(
5344        &mut self,
5345        glyph: MonochromeSprite,
5346        program: Arc<crate::SceneShaderProgram>,
5347        data: [[f32; 4]; crate::SHADER_DATA_SLOTS],
5348        opacity: f32,
5349    ) {
5350        self.invalidator.debug_assert_paint();
5351        assert!(
5352            program.uses_glyph_mask(),
5353            "glyph drawing requires an atlas-masked program"
5354        );
5355        self.next_frame
5356            .scene
5357            .insert_primitive(crate::Primitive::Shader(crate::ShaderDraw {
5358                order: 0,
5359                bounds: glyph.bounds,
5360                content_mask: glyph.content_mask,
5361                opacity,
5362                scale_factor: self.scale_factor(),
5363                program,
5364                data,
5365                path_mask: None,
5366                glyph_mask: Some(glyph.tile),
5367            }));
5368    }
5369    /// Whether descendant text must use coverage suitable for isolated composition.
5370    pub fn is_layer_captured(&self) -> bool {
5371        self.layer_capture_depth > 0
5372    }
5373
5374    /// Prepaint/paint scope shared by explicit captured containers. Descendants
5375    /// use local opacity and cannot paint outside the bounded capture rectangle.
5376    pub fn with_layer_capture_scope<R>(
5377        &mut self,
5378        bounds: Bounds<Pixels>,
5379        f: impl FnOnce(&mut Self) -> R,
5380    ) -> R {
5381        let source = bounds.intersect(&self.content_mask().bounds);
5382        self.with_layer_capture_masks(source, source, f)
5383    }
5384
5385    /// Prepaint a captured subtree with a sampling halo and a separate visible clip.
5386    /// Reserve the supported remaining nesting budget so later radius edits and
5387    /// nested filters can reuse raw source pixels without painting past the crop.
5388    pub fn with_layer_effect_scope<R>(
5389        &mut self,
5390        bounds: Bounds<Pixels>,
5391        f: impl FnOnce(&mut Self) -> R,
5392    ) -> R {
5393        let (source, clip) = self.layer_capture_regions(bounds);
5394        self.with_layer_capture_masks(source, clip, f)
5395    }
5396    fn layer_capture_regions(&self, bounds: Bounds<Pixels>) -> (Bounds<Pixels>, Bounds<Pixels>) {
5397        let viewport = Bounds::new(Point::default(), self.viewport_size);
5398        let clip = bounds
5399            .intersect(&self.content_mask().bounds)
5400            .intersect(&viewport);
5401        if clip.is_empty() {
5402            return (clip, clip);
5403        }
5404        let levels = crate::MAX_LAYER_GROUPS
5405            .saturating_sub(self.layer_capture_depth)
5406            .max(1) as f32;
5407        // 16 logical pixels per Gaussian plus eight device pixels for area
5408        // downsampling, reconstruction and integer crop rounding per level.
5409        let halo = px((16. + 8. / self.scale_factor()) * levels);
5410        let mut source = clip.dilate(halo).intersect(&viewport);
5411        if let Some(parent) = self.layer_capture_sources.last() {
5412            source = source.intersect(parent);
5413        }
5414        (source, clip)
5415    }
5416    pub(crate) fn layer_capture_visible_bounds(&self) -> Option<Bounds<Pixels>> {
5417        self.layer_capture_clips.last().copied()
5418    }
5419    fn with_layer_capture_masks<R>(
5420        &mut self,
5421        source: Bounds<Pixels>,
5422        clip: Bounds<Pixels>,
5423        f: impl FnOnce(&mut Self) -> R,
5424    ) -> R {
5425        self.invalidator.debug_assert_paint_or_prepaint();
5426        let previous = self.element_opacity;
5427        self.element_opacity = 1.;
5428        self.layer_capture_depth += 1;
5429        self.layer_capture_sources.push(source);
5430        let visible = self
5431            .layer_capture_clips
5432            .last()
5433            .map_or(clip, |parent| clip.intersect(parent));
5434        self.layer_capture_clips.push(visible);
5435        // Bypass ancestor paint clips for source sampling; descendant clips still
5436        // intersect this mask. Interaction keeps the original final visible clip.
5437        self.content_mask_stack.push(ContentMask { bounds: source });
5438        let result = f(self);
5439        self.content_mask_stack.pop();
5440        self.layer_capture_clips.pop();
5441        self.layer_capture_sources.pop();
5442        self.layer_capture_depth -= 1;
5443        self.element_opacity = previous;
5444        result
5445    }
5446
5447    /// Capture a subtree and apply opacity once to its completed RGBA result.
5448    /// Deferred overlays remain outside this paint-time boundary.
5449    pub fn with_layer_opacity<R>(
5450        &mut self,
5451        bounds: Bounds<Pixels>,
5452        opacity: f32,
5453        program: Arc<crate::SceneShaderProgram>,
5454        f: impl FnOnce(&mut Self) -> R,
5455    ) -> R {
5456        self.with_layer_effect(bounds, opacity, 1., program, f)
5457    }
5458
5459    /// Capture a subtree, filter saturation, then apply opacity to the group.
5460    /// Saturation changes reuse raw retained child pixels when commands match.
5461    pub fn with_layer_effect<R>(
5462        &mut self,
5463        bounds: Bounds<Pixels>,
5464        opacity: f32,
5465        saturation: f32,
5466        program: Arc<crate::SceneShaderProgram>,
5467        f: impl FnOnce(&mut Self) -> R,
5468    ) -> R {
5469        self.with_layer_color_filter(
5470            bounds,
5471            opacity,
5472            crate::LayerColorFilter {
5473                saturation,
5474                ..Default::default()
5475            },
5476            program,
5477            f,
5478        )
5479    }
5480
5481    /// Capture a subtree and apply color filtering, group opacity and destination blending.
5482    /// Color operations reuse retained raw child pixels when commands match.
5483    pub fn with_layer_color_filter<R>(
5484        &mut self,
5485        bounds: Bounds<Pixels>,
5486        opacity: f32,
5487        color_filter: crate::LayerColorFilter,
5488        program: Arc<crate::SceneShaderProgram>,
5489        f: impl FnOnce(&mut Self) -> R,
5490    ) -> R {
5491        self.invalidator.debug_assert_paint();
5492        let viewport = Bounds::new(Point::default(), self.viewport_size);
5493        let (source, clipped) = self.layer_capture_regions(bounds);
5494        let effective = opacity * self.element_opacity();
5495        if clipped.is_empty() {
5496            return self.with_layer_capture_scope(clipped, f);
5497        }
5498        let scale = self.scale_factor();
5499        let capture = Arc::new(crate::LayerCapture {
5500            blur_quality: color_filter.blur_quality,
5501            blur_radius: crate::ScaledPixels(f32::from(color_filter.blur_radius) * scale),
5502            blend_mode: color_filter.blend_mode,
5503            bounds: source.scale(scale),
5504            clip: Some(clipped.scale(scale)),
5505            opacity: effective,
5506            saturation: color_filter.saturation,
5507            brightness: color_filter.brightness,
5508            contrast: color_filter.contrast,
5509            invert: color_filter.invert,
5510            program,
5511        });
5512        let fence = ContentMask {
5513            bounds: viewport.scale(scale),
5514        };
5515        self.next_frame
5516            .scene
5517            .begin_layer_capture(capture.clone(), fence);
5518        let result = self.with_layer_capture_masks(source, clipped, f);
5519        self.next_frame.scene.end_layer_capture(capture, fence);
5520        result
5521    }
5522
5523    /// Record an explicit backdrop filter before painting the receiving surface.
5524    /// Unlike paint_layer, this boundary may interrupt the host render pass.
5525    pub fn paint_backdrop_blur(
5526        &mut self,
5527        bounds: Bounds<Pixels>,
5528        radii: Corners<Pixels>,
5529        radius: Pixels,
5530        opacity: f32,
5531        program: Arc<crate::SceneShaderProgram>,
5532    ) {
5533        self.invalidator.debug_assert_paint();
5534        let viewport = Bounds::new(Point::default(), self.viewport_size);
5535        let clip = self.content_mask();
5536        if radius <= px(0.)
5537            || bounds
5538                .intersect(&clip.bounds)
5539                .intersect(&viewport)
5540                .is_empty()
5541            || opacity <= 0.
5542        {
5543            return;
5544        }
5545        let scale = self.scale_factor();
5546        let halo = radius + px(crate::BACKDROP_DOWNSAMPLE as f32 / scale);
5547        let footprint = Bounds::new(
5548            bounds.origin - point(halo, halo),
5549            bounds.size + size(halo * 2., halo * 2.),
5550        );
5551        self.next_frame
5552            .scene
5553            .insert_primitive(crate::Primitive::Backdrop(crate::BackdropDraw {
5554                order: 0,
5555                bounds: footprint.scale(scale),
5556                content_mask: ContentMask {
5557                    bounds: viewport.scale(scale),
5558                },
5559                surface_bounds: bounds.scale(scale),
5560                clip: clip.scale(scale),
5561                corner_radii: radii.scale(scale),
5562                radius: f32::from(radius) * scale,
5563                opacity: opacity * self.element_opacity(),
5564                program,
5565            }));
5566    }
5567    /// Record an instanced fragment shader in the current scene order.
5568    /// Bounds include the entire effect; the host applies clipping and opacity.
5569    pub fn paint_shader(
5570        &mut self,
5571        bounds: Bounds<Pixels>,
5572        program: std::sync::Arc<crate::SceneShaderProgram>,
5573        data: [[f32; 4]; crate::SHADER_DATA_SLOTS],
5574    ) {
5575        self.invalidator.debug_assert_paint();
5576        if bounds.is_empty() || self.element_opacity() <= 0.0 {
5577            return;
5578        }
5579        self.next_frame
5580            .scene
5581            .insert_primitive(crate::Primitive::Shader(crate::ShaderDraw {
5582                path_mask: None,
5583                glyph_mask: None,
5584                order: 0,
5585                bounds: bounds.scale(self.scale_factor()),
5586                content_mask: self.snapped_content_mask(),
5587                opacity: self.element_opacity(),
5588                scale_factor: self.scale_factor(),
5589                program,
5590                data,
5591            }));
5592    }
5593
5594    /// Record independent GPU content using native geometry at the current scene order.
5595    /// Producers span the full unclipped shape; GPUI applies clip, coverage and opacity.
5596    pub fn paint_custom(
5597        &mut self,
5598        geometry: crate::CustomGeometry,
5599        content: std::sync::Arc<dyn crate::CustomContent>,
5600    ) {
5601        self.invalidator.debug_assert_paint();
5602        if self.element_opacity() <= 0.0 {
5603            return;
5604        }
5605        let (bounds, corner_radii, coverage) = match geometry {
5606            crate::CustomGeometry::RoundedRect {
5607                bounds,
5608                corner_radii,
5609            } => (bounds, corner_radii, None),
5610            crate::CustomGeometry::Border(quad) => {
5611                if quad.border_widths == Edges::default() {
5612                    return;
5613                }
5614                let coverage = crate::CustomCoverage::Border {
5615                    widths: self.snap_border_widths(quad.border_widths),
5616                    style: quad.border_style,
5617                };
5618                (quad.bounds, quad.corner_radii, Some(coverage))
5619            }
5620            crate::CustomGeometry::Path(path) => {
5621                if path.bounds.is_empty() || path.vertices.is_empty() {
5622                    return;
5623                }
5624                let bounds = path.bounds;
5625                (
5626                    bounds,
5627                    Corners::default(),
5628                    Some(crate::CustomCoverage::Path(std::sync::Arc::new(
5629                        path.scale(self.scale_factor()),
5630                    ))),
5631                )
5632            }
5633        };
5634        if bounds.is_empty() {
5635            return;
5636        }
5637        // Path geometry retains its original scaled bounds. Rectangle/border bounds
5638        // use the same pixel snapping as native quads.
5639        let scaled_bounds = if matches!(&coverage, Some(crate::CustomCoverage::Path(_))) {
5640            bounds.scale(self.scale_factor())
5641        } else {
5642            self.snap_bounds(bounds)
5643        };
5644        self.next_frame.scene.insert_primitive(crate::CustomDraw {
5645            order: 0,
5646            bounds: scaled_bounds,
5647            content_mask: self.snapped_content_mask(),
5648            corner_radii: corner_radii
5649                .clamp_radii_for_quad_size(bounds.size)
5650                .scale(self.scale_factor()),
5651            opacity: self.element_opacity(),
5652            content: crate::scene::content_with_preparation_geometry(
5653                content,
5654                bounds.size,
5655                self.scale_factor(),
5656            ),
5657            coverage,
5658        });
5659    }
5660
5661    /// Paint a surface into the scene for the next frame at the current z-index.
5662    ///
5663    /// This method should only be called as part of the paint phase of element drawing.
5664    #[cfg(any(target_os = "macos", target_os = "ios"))]
5665    pub fn paint_surface(
5666        &mut self,
5667        bounds: Bounds<Pixels>,
5668        image_buffer: CFRetained<CVPixelBuffer>,
5669    ) {
5670        use crate::PaintSurface;
5671
5672        self.invalidator.debug_assert_paint();
5673
5674        let bounds = self.snap_bounds(bounds);
5675        let content_mask = self.snapped_content_mask();
5676        self.next_frame.scene.insert_primitive(PaintSurface {
5677            order: 0,
5678            bounds,
5679            content_mask,
5680            image_buffer,
5681        });
5682    }
5683
5684    /// Removes an image from the sprite atlas.
5685    pub fn drop_image(&mut self, data: Arc<RenderImage>) -> Result<()> {
5686        for frame_index in 0..data.frame_count() {
5687            let params = RenderImageParams {
5688                image_id: data.id,
5689                frame_index,
5690            };
5691
5692            self.sprite_atlas.remove(&params.clone().into());
5693        }
5694
5695        Ok(())
5696    }
5697
5698    /// Returns whether every frame of an image is present in the sprite atlas.
5699    #[cfg(any(test, feature = "test-support"))]
5700    pub fn has_image_atlas_entry(&self, data: &RenderImage) -> bool {
5701        data.frame_count() > 0
5702            && (0..data.frame_count()).all(|frame_index| {
5703                self.sprite_atlas.contains(
5704                    &RenderImageParams {
5705                        image_id: data.id,
5706                        frame_index,
5707                    }
5708                    .into(),
5709                )
5710            })
5711    }
5712
5713    /// Add a node to the layout tree for the current frame. Takes the `Style` of the element for which
5714    /// layout is being requested, along with the layout ids of any children. This method is called during
5715    /// calls to the [`Element::request_layout`] trait method and enables any element to participate in layout.
5716    ///
5717    /// This method should only be called as part of the request_layout or prepaint phase of element drawing.
5718    #[must_use]
5719    pub fn request_layout(
5720        &mut self,
5721        style: Style,
5722        children: impl IntoIterator<Item = LayoutId>,
5723        cx: &mut App,
5724    ) -> LayoutId {
5725        self.invalidator.debug_assert_prepaint();
5726
5727        cx.layout_id_buffer.clear();
5728        cx.layout_id_buffer.extend(children);
5729        let rem_size = self.rem_size();
5730        let scale_factor = self.scale_factor();
5731
5732        self.layout_engine.as_mut().unwrap().request_layout(
5733            style,
5734            rem_size,
5735            scale_factor,
5736            &cx.layout_id_buffer,
5737        )
5738    }
5739
5740    /// Add a node to the layout tree for the current frame. Instead of taking a `Style` and children,
5741    /// this variant takes a function that is invoked during layout so you can use arbitrary logic to
5742    /// determine the element's size. One place this is used internally is when measuring text.
5743    ///
5744    /// The given closure is invoked at layout time with the known dimensions and available space and
5745    /// returns a `Size`.
5746    ///
5747    /// This method should only be called as part of the request_layout or prepaint phase of element drawing.
5748    pub fn request_measured_layout<F>(&mut self, style: Style, measure: F) -> LayoutId
5749    where
5750        F: Fn(Size<Option<Pixels>>, Size<AvailableSpace>, &mut Window, &mut App) -> Size<Pixels>
5751            + 'static,
5752    {
5753        self.invalidator.debug_assert_prepaint();
5754
5755        let rem_size = self.rem_size();
5756        let scale_factor = self.scale_factor();
5757        self.layout_engine
5758            .as_mut()
5759            .unwrap()
5760            .request_measured_layout(style, rem_size, scale_factor, measure)
5761    }
5762
5763    /// Compute the layout for the given id within the given available space.
5764    /// This method is called for its side effect, typically by the framework prior to painting.
5765    /// After calling it, you can request the bounds of the given layout node id or any descendant.
5766    ///
5767    /// This method should only be called as part of the prepaint phase of element drawing.
5768    pub fn compute_layout(
5769        &mut self,
5770        layout_id: LayoutId,
5771        available_space: Size<AvailableSpace>,
5772        cx: &mut App,
5773    ) {
5774        self.invalidator.debug_assert_prepaint();
5775
5776        let mut layout_engine = self.layout_engine.take().unwrap();
5777        layout_engine.compute_layout(layout_id, available_space, self, cx);
5778        self.layout_engine = Some(layout_engine);
5779    }
5780
5781    /// Obtain the bounds computed for the given LayoutId relative to the window. This method will usually be invoked by
5782    /// GPUI itself automatically in order to pass your element its `Bounds` automatically.
5783    ///
5784    /// This method should only be called as part of element drawing.
5785    pub fn layout_bounds(&mut self, layout_id: LayoutId) -> Bounds<Pixels> {
5786        self.invalidator.debug_assert_prepaint();
5787
5788        let scale_factor = self.scale_factor();
5789        let mut bounds = self
5790            .layout_engine
5791            .as_mut()
5792            .unwrap()
5793            .layout_bounds(layout_id, scale_factor)
5794            .map(Into::into);
5795        let snapped_offset = self.pixel_snap_point(self.element_offset());
5796        bounds.origin += snapped_offset;
5797        bounds
5798    }
5799
5800    /// This method should be called during `prepaint`. You can use
5801    /// the returned [Hitbox] during `paint` or in an event handler
5802    /// to determine whether the inserted hitbox was the topmost.
5803    ///
5804    /// This method should only be called as part of the prepaint phase of element drawing.
5805    pub fn insert_hitbox(&mut self, bounds: Bounds<Pixels>, behavior: HitboxBehavior) -> Hitbox {
5806        self.invalidator.debug_assert_prepaint();
5807
5808        let mut content_mask = self.content_mask();
5809        if let Some(clip) = self.layer_capture_visible_bounds() {
5810            content_mask.bounds = content_mask.bounds.intersect(&clip);
5811        }
5812        let id = self.next_hitbox_id;
5813        self.next_hitbox_id = self.next_hitbox_id.next();
5814        let hitbox = Hitbox {
5815            id,
5816            bounds,
5817            content_mask,
5818            behavior,
5819        };
5820        self.next_frame.hitboxes.push(hitbox.clone());
5821        hitbox
5822    }
5823
5824    /// Set a hitbox which will act as a control area of the platform window.
5825    ///
5826    /// This method should only be called as part of the paint phase of element drawing.
5827    pub fn insert_window_control_hitbox(&mut self, area: WindowControlArea, hitbox: Hitbox) {
5828        self.invalidator.debug_assert_paint();
5829        self.next_frame.window_control_hitboxes.push((area, hitbox));
5830    }
5831
5832    /// Sets the key context for the current element. This context will be used to translate
5833    /// keybindings into actions.
5834    ///
5835    /// This method should only be called as part of the paint phase of element drawing.
5836    pub fn set_key_context(&mut self, context: KeyContext) {
5837        self.invalidator.debug_assert_paint();
5838        self.next_frame.dispatch_tree.set_key_context(context);
5839    }
5840
5841    /// Sets the focus handle for the current element. This handle will be used to manage focus state
5842    /// and keyboard event dispatch for the element.
5843    ///
5844    /// This method should only be called as part of the prepaint phase of element drawing.
5845    pub fn set_focus_handle(&mut self, focus_handle: &FocusHandle, _: &App) {
5846        self.invalidator.debug_assert_prepaint();
5847        if focus_handle.is_focused(self) {
5848            self.next_frame.focus = Some(focus_handle.id);
5849        }
5850        self.next_frame.dispatch_tree.set_focus_id(focus_handle.id);
5851    }
5852
5853    /// Sets the view id for the current element, which will be used to manage view caching.
5854    ///
5855    /// This method should only be called as part of element prepaint. We plan on removing this
5856    /// method eventually when we solve some issues that require us to construct editor elements
5857    /// directly instead of always using editors via views.
5858    pub fn set_view_id(&mut self, view_id: EntityId) {
5859        self.invalidator.debug_assert_prepaint();
5860        self.next_frame.dispatch_tree.set_view_id(view_id);
5861    }
5862
5863    /// Get the entity ID for the currently rendering view
5864    pub fn current_view(&self) -> EntityId {
5865        self.invalidator.debug_assert_paint_or_prepaint();
5866        self.rendered_entity_stack.last().copied().unwrap()
5867    }
5868
5869    #[inline]
5870    pub(crate) fn with_rendered_view<R>(
5871        &mut self,
5872        id: EntityId,
5873        f: impl FnOnce(&mut Self) -> R,
5874    ) -> R {
5875        self.rendered_entity_stack.push(id);
5876        let result = f(self);
5877        self.rendered_entity_stack.pop();
5878        result
5879    }
5880
5881    /// Executes the provided function with the specified image cache.
5882    pub fn with_image_cache<F, R>(&mut self, image_cache: Option<AnyImageCache>, f: F) -> R
5883    where
5884        F: FnOnce(&mut Self) -> R,
5885    {
5886        if let Some(image_cache) = image_cache {
5887            self.image_cache_stack.push(image_cache);
5888            let result = f(self);
5889            self.image_cache_stack.pop();
5890            result
5891        } else {
5892            f(self)
5893        }
5894    }
5895
5896    /// Sets an input handler, such as [`ElementInputHandler`][element_input_handler], which interfaces with the
5897    /// platform to receive textual input with proper integration with concerns such
5898    /// as IME interactions. This handler will be active for the upcoming frame until the following frame is
5899    /// rendered.
5900    ///
5901    /// This method should only be called as part of the paint phase of element drawing.
5902    ///
5903    /// [element_input_handler]: crate::ElementInputHandler
5904    pub fn handle_input(
5905        &mut self,
5906        focus_handle: &FocusHandle,
5907        input_handler: impl InputHandler,
5908        cx: &App,
5909    ) {
5910        self.invalidator.debug_assert_paint();
5911
5912        if focus_handle.is_focused(self) {
5913            let cx = self.to_async(cx);
5914            self.next_frame.input_handlers.push(Some(
5915                PlatformInputHandler::new(cx, Box::new(input_handler)).with_focus(focus_handle.id),
5916            ));
5917        }
5918    }
5919
5920    /// Notifies native text services that the focused component's text changed.
5921    ///
5922    /// Text components should call this after application-driven edits, in addition
5923    /// to notifying GPUI to redraw. Unfocused or unregistered components are ignored.
5924    pub fn notify_text_input_changed(&self, focus_handle: &FocusHandle) {
5925        if self.focused_text_input == Some(focus_handle.id) && focus_handle.is_focused(self) {
5926            self.platform_window
5927                .text_input_state_changed(TextInputStateChange::ContentChanged);
5928        }
5929    }
5930
5931    /// Notifies native text services that the focused component's selection changed.
5932    ///
5933    /// Text components should call this after application-driven selection changes,
5934    /// in addition to notifying GPUI to redraw.
5935    pub fn notify_text_selection_changed(&self, focus_handle: &FocusHandle) {
5936        if self.focused_text_input == Some(focus_handle.id) && focus_handle.is_focused(self) {
5937            self.platform_window
5938                .text_input_state_changed(TextInputStateChange::SelectionChanged);
5939        }
5940    }
5941
5942    /// Forwards the focused input handler's [`TextInputConfiguration`] to the
5943    /// platform window when it differs from the last forwarded value. With no
5944    /// input handler the default configuration applies, so a field's
5945    /// preferences don't outlive its focus.
5946    fn apply_text_input_configuration(&mut self, cx: &mut App) {
5947        let configuration = match self.platform_window.take_input_handler() {
5948            Some(mut input_handler) => {
5949                let configuration = input_handler.text_input_configuration(self, cx);
5950                self.platform_window.set_input_handler(input_handler);
5951                configuration
5952            }
5953            None => TextInputConfiguration::default(),
5954        };
5955        if self.last_text_input_configuration.as_ref() != Some(&configuration) {
5956            self.platform_window
5957                .set_text_input_configuration(configuration.clone());
5958            self.last_text_input_configuration = Some(configuration);
5959        }
5960    }
5961
5962    /// Register a mouse event listener on the window for the next frame. The type of event
5963    /// is determined by the first parameter of the given listener. When the next frame is rendered
5964    /// the listener will be cleared.
5965    ///
5966    /// This method should only be called as part of the paint phase of element drawing.
5967    pub fn on_mouse_event<Event: MouseEvent>(
5968        &mut self,
5969        mut listener: impl FnMut(&Event, DispatchPhase, &mut Window, &mut App) + 'static,
5970    ) {
5971        self.invalidator.debug_assert_paint();
5972
5973        self.next_frame.mouse_listeners.push(Some(Box::new(
5974            move |event: &dyn Any, phase: DispatchPhase, window: &mut Window, cx: &mut App| {
5975                if let Some(event) = event.downcast_ref() {
5976                    listener(event, phase, window, cx)
5977                }
5978            },
5979        )));
5980    }
5981
5982    /// Register a key event listener on this node for the next frame. The type of event
5983    /// is determined by the first parameter of the given listener. When the next frame is rendered
5984    /// the listener will be cleared.
5985    ///
5986    /// This is a fairly low-level method, so prefer using event handlers on elements unless you have
5987    /// a specific need to register a listener yourself.
5988    ///
5989    /// This method should only be called as part of the paint phase of element drawing.
5990    pub fn on_key_event<Event: KeyEvent>(
5991        &mut self,
5992        listener: impl Fn(&Event, DispatchPhase, &mut Window, &mut App) + 'static,
5993    ) {
5994        self.invalidator.debug_assert_paint();
5995
5996        self.next_frame.dispatch_tree.on_key_event(Rc::new(
5997            move |event: &dyn Any, phase, window: &mut Window, cx: &mut App| {
5998                if let Some(event) = event.downcast_ref::<Event>() {
5999                    listener(event, phase, window, cx)
6000                }
6001            },
6002        ));
6003    }
6004
6005    /// Register a modifiers changed event listener on the window for the next frame.
6006    ///
6007    /// This is a fairly low-level method, so prefer using event handlers on elements unless you have
6008    /// a specific need to register a global listener.
6009    ///
6010    /// This method should only be called as part of the paint phase of element drawing.
6011    pub fn on_modifiers_changed(
6012        &mut self,
6013        listener: impl Fn(&ModifiersChangedEvent, &mut Window, &mut App) + 'static,
6014    ) {
6015        self.invalidator.debug_assert_paint();
6016
6017        self.next_frame.dispatch_tree.on_modifiers_changed(Rc::new(
6018            move |event: &ModifiersChangedEvent, window: &mut Window, cx: &mut App| {
6019                listener(event, window, cx)
6020            },
6021        ));
6022    }
6023
6024    /// Register a listener to be called when the given focus handle or one of its descendants receives focus.
6025    /// This does not fire if the given focus handle - or one of its descendants - was previously focused.
6026    /// Returns a subscription and persists until the subscription is dropped.
6027    pub fn on_focus_in(
6028        &mut self,
6029        handle: &FocusHandle,
6030        cx: &mut App,
6031        mut listener: impl FnMut(&mut Window, &mut App) + 'static,
6032    ) -> Subscription {
6033        let focus_id = handle.id;
6034        let (subscription, activate) =
6035            self.new_focus_listener(Box::new(move |event, window, cx| {
6036                if event.is_focus_in(focus_id) {
6037                    listener(window, cx);
6038                }
6039                true
6040            }));
6041        cx.defer(move |_| activate());
6042        subscription
6043    }
6044
6045    /// Register a listener to be called when the given focus handle or one of its descendants loses focus.
6046    /// Returns a subscription and persists until the subscription is dropped.
6047    pub fn on_focus_out(
6048        &mut self,
6049        handle: &FocusHandle,
6050        cx: &mut App,
6051        mut listener: impl FnMut(FocusOutEvent, &mut Window, &mut App) + 'static,
6052    ) -> Subscription {
6053        let focus_id = handle.id;
6054        let (subscription, activate) =
6055            self.new_focus_listener(Box::new(move |event, window, cx| {
6056                if let Some(blurred_id) = event.previous_focus_path.last().copied()
6057                    && event.is_focus_out(focus_id)
6058                {
6059                    let event = FocusOutEvent {
6060                        blurred: WeakFocusHandle {
6061                            id: blurred_id,
6062                            handles: Arc::downgrade(&cx.focus_handles),
6063                        },
6064                    };
6065                    listener(event, window, cx)
6066                }
6067                true
6068            }));
6069        cx.defer(move |_| activate());
6070        subscription
6071    }
6072
6073    fn reset_cursor_style(&self, cx: &mut App) {
6074        // Set the cursor only if we're the active window.
6075        if self.is_window_hovered() {
6076            let style = self
6077                .rendered_frame
6078                .cursor_style(self)
6079                .unwrap_or(CursorStyle::Arrow);
6080            cx.platform.set_cursor_style(style);
6081        }
6082    }
6083
6084    /// Dispatch a given keystroke as though the user had typed it.
6085    /// You can create a keystroke with Keystroke::parse("").
6086    pub fn dispatch_keystroke(&mut self, keystroke: Keystroke, cx: &mut App) -> bool {
6087        let keystroke = keystroke.with_simulated_ime();
6088        let result = self.dispatch_event(
6089            PlatformInput::KeyDown(KeyDownEvent {
6090                keystroke: keystroke.clone(),
6091                is_held: false,
6092                prefer_character_input: false,
6093            }),
6094            cx,
6095        );
6096        if !result.propagate {
6097            return true;
6098        }
6099
6100        if let Some(input) = keystroke.key_char
6101            && let Some(mut input_handler) = self.platform_window.take_input_handler()
6102        {
6103            input_handler.dispatch_input(&input, self, cx);
6104            self.platform_window.set_input_handler(input_handler);
6105            return true;
6106        }
6107
6108        false
6109    }
6110
6111    /// Return a key binding string for an action, to display in the UI. Uses the highest precedence
6112    /// binding for the action (last binding added to the keymap).
6113    pub fn keystroke_text_for(&self, action: &dyn Action, cx: &App) -> String {
6114        self.highest_precedence_binding_for_action(action)
6115            .map(|binding| {
6116                binding
6117                    .keystrokes()
6118                    .iter()
6119                    .map(|keystroke| keystroke.display(cx.platform_info().os).to_string())
6120                    .collect::<Vec<_>>()
6121                    .join(" ")
6122            })
6123            .unwrap_or_else(|| action.name().to_string())
6124    }
6125
6126    /// Dispatch a mouse, keyboard, or touch event on the window.
6127    #[profiling::function]
6128    pub fn dispatch_event(&mut self, event: PlatformInput, cx: &mut App) -> DispatchEventResult {
6129        #[cfg(feature = "profiler")]
6130        self.window_profiler.begin_input(event.kind_name());
6131        let update_count_before = self.invalidator.update_count();
6132        // Track input modality for focus-visible styling and hover suppression.
6133        // Hover is suppressed during keyboard modality so that keyboard navigation
6134        // doesn't show hover highlights on the item under the mouse cursor.
6135        let old_modality = self.last_input_modality;
6136        self.last_input_modality = match &event {
6137            PlatformInput::KeyDown(_) => InputModality::Keyboard,
6138            PlatformInput::MouseMove(_) | PlatformInput::MouseDown(_) => InputModality::Mouse,
6139            PlatformInput::Touch(_) => InputModality::Touch,
6140            _ => self.last_input_modality,
6141        };
6142        if self.last_input_modality != old_modality {
6143            self.refresh();
6144        }
6145
6146        // Handlers may set this to false by calling `stop_propagation`.
6147        cx.propagate_event = true;
6148        // Handlers may set this to true by calling `prevent_default`.
6149        self.default_prevented = false;
6150
6151        let event = match event {
6152            // Track the mouse position with our own state, since accessing the platform
6153            // API for the mouse position can only occur on the main thread.
6154            PlatformInput::MouseMove(mouse_move) => {
6155                self.mouse_position = mouse_move.position;
6156                self.modifiers = mouse_move.modifiers;
6157                PlatformInput::MouseMove(mouse_move)
6158            }
6159            PlatformInput::MouseDown(mouse_down) => {
6160                self.mouse_position = mouse_down.position;
6161                self.modifiers = mouse_down.modifiers;
6162                PlatformInput::MouseDown(mouse_down)
6163            }
6164            PlatformInput::MouseUp(mouse_up) => {
6165                self.mouse_position = mouse_up.position;
6166                self.modifiers = mouse_up.modifiers;
6167                PlatformInput::MouseUp(mouse_up)
6168            }
6169            PlatformInput::MousePressure(mouse_pressure) => {
6170                PlatformInput::MousePressure(mouse_pressure)
6171            }
6172            PlatformInput::MouseExited(mouse_exited) => {
6173                self.modifiers = mouse_exited.modifiers;
6174                PlatformInput::MouseExited(mouse_exited)
6175            }
6176            PlatformInput::ModifiersChanged(modifiers_changed) => {
6177                self.modifiers = modifiers_changed.modifiers;
6178                self.capslock = modifiers_changed.capslock;
6179                PlatformInput::ModifiersChanged(modifiers_changed)
6180            }
6181            PlatformInput::Scroll(scroll_wheel) => {
6182                self.mouse_position = scroll_wheel.position;
6183                self.modifiers = scroll_wheel.modifiers;
6184                PlatformInput::Scroll(scroll_wheel)
6185            }
6186            PlatformInput::Pinch(pinch) => {
6187                self.mouse_position = pinch.position;
6188                self.modifiers = pinch.modifiers;
6189                PlatformInput::Pinch(pinch)
6190            }
6191            // Translate dragging and dropping of external files from the operating system
6192            // to internal drag and drop events.
6193            PlatformInput::FileDrop(file_drop) => match file_drop {
6194                FileDropEvent::Entered { position, paths } => {
6195                    self.mouse_position = position;
6196                    let source_window = self.handle.window_id();
6197                    if !cx.restore_platform_drag(source_window) && cx.active_drag.is_none() {
6198                        cx.active_drag = Some(AnyDrag {
6199                            value: Arc::new(paths.clone()),
6200                            view: cx.new(|_| paths).into(),
6201                            cursor_offset: position,
6202                            cursor_style: None,
6203                            external_payload_source: None,
6204                        });
6205                    }
6206                    PlatformInput::MouseMove(MouseMoveEvent {
6207                        position,
6208                        pressed_button: Some(MouseButton::Left),
6209                        modifiers: Modifiers::default(),
6210                    })
6211                }
6212                FileDropEvent::Pending { position } => {
6213                    self.mouse_position = position;
6214                    PlatformInput::MouseMove(MouseMoveEvent {
6215                        position,
6216                        pressed_button: Some(MouseButton::Left),
6217                        modifiers: Modifiers::default(),
6218                    })
6219                }
6220                FileDropEvent::Submit { position } => {
6221                    cx.activate(true);
6222                    self.mouse_position = position;
6223                    PlatformInput::MouseUp(MouseUpEvent {
6224                        button: MouseButton::Left,
6225                        position,
6226                        modifiers: Modifiers::default(),
6227                        click_count: 1,
6228                    })
6229                }
6230                FileDropEvent::Exited => {
6231                    if !cx.hand_restored_drag_to_platform(self.handle.window_id()) {
6232                        cx.active_drag.take();
6233                    }
6234                    self.refresh();
6235                    PlatformInput::FileDrop(FileDropEvent::Exited)
6236                }
6237                FileDropEvent::Ended => {
6238                    cx.end_platform_drag(self.handle.window_id());
6239                    self.refresh();
6240                    PlatformInput::FileDrop(FileDropEvent::Ended)
6241                }
6242            },
6243            PlatformInput::Touch(touch) => PlatformInput::Touch(touch),
6244            PlatformInput::LongPress(long_press) => {
6245                self.mouse_position = if long_press.phase == crate::TouchPhase::Started {
6246                    long_press.start_position
6247                } else {
6248                    long_press.position
6249                };
6250                if long_press.phase == crate::TouchPhase::Started {
6251                    self.long_press_capture = None;
6252                }
6253                PlatformInput::LongPress(long_press)
6254            }
6255            PlatformInput::TouchDrag(touch_drag) => {
6256                self.mouse_position = touch_drag.start_position;
6257                PlatformInput::TouchDrag(touch_drag)
6258            }
6259            PlatformInput::BackGesture(back) => {
6260                self.mouse_position = back.start_position;
6261                PlatformInput::BackGesture(back)
6262            }
6263            PlatformInput::KeyDown(_) | PlatformInput::KeyUp(_) => event,
6264        };
6265
6266        if let Some(any_mouse_event) = event.mouse_event() {
6267            self.dispatch_mouse_event(any_mouse_event, cx);
6268        } else if let Some(any_key_event) = event.keyboard_event() {
6269            self.dispatch_key_event(any_key_event, cx);
6270        } else if let Some(touch_event) = event.touch_event() {
6271            self.dispatch_touch_event(touch_event, cx);
6272        }
6273        if let PlatformInput::LongPress(long_press) = &event {
6274            match long_press.phase {
6275                crate::TouchPhase::Started if !self.default_prevented => {
6276                    self.long_press_capture = None;
6277                }
6278                crate::TouchPhase::Ended | crate::TouchPhase::Cancelled => {
6279                    self.long_press_capture = None;
6280                }
6281                crate::TouchPhase::Started | crate::TouchPhase::Moved => {}
6282            }
6283        }
6284
6285        // Must run after the move is dispatched: the platform owns the gesture afterwards, so this
6286        // is the last chance for drag listeners to see the pointer leave and reset their state.
6287        self.promote_external_drag_to_platform(&event, cx);
6288
6289        let caused_invalidation = self.invalidator.update_count() > update_count_before;
6290        if caused_invalidation {
6291            self.input_rate_tracker.borrow_mut().record_input();
6292        }
6293        #[cfg(feature = "profiler")]
6294        self.window_profiler.end_input(caused_invalidation);
6295
6296        DispatchEventResult {
6297            propagate: cx.propagate_event,
6298            default_prevented: self.default_prevented,
6299        }
6300    }
6301
6302    fn promote_external_drag_to_platform(&mut self, event: &PlatformInput, cx: &mut App) {
6303        let PlatformInput::MouseMove(mouse_move) = event else {
6304            return;
6305        };
6306        if mouse_move.pressed_button != Some(MouseButton::Left) {
6307            return;
6308        }
6309        if Bounds::new(Point::default(), self.viewport_size).contains(&mouse_move.position) {
6310            return;
6311        }
6312        if !self.platform_window.can_start_external_drag() {
6313            return;
6314        }
6315        let Some(payload_source) = cx
6316            .active_drag
6317            .as_mut()
6318            .and_then(|drag| drag.external_payload_source.take())
6319        else {
6320            return;
6321        };
6322        let Some(payload) = payload_source(self, cx) else {
6323            return;
6324        };
6325        if self.platform_window.start_external_drag(&payload)
6326            && cx.hand_active_drag_to_platform(self.handle.window_id())
6327        {
6328            self.refresh();
6329        }
6330    }
6331
6332    /// Whether recognized touch pans may use the platform's predicted touch
6333    /// positions ([`TouchEvent::predicted_position`]) to compensate for input
6334    /// latency. Defaults to true.
6335    pub fn touch_prediction_enabled(&self) -> bool {
6336        self.touch_prediction_enabled
6337    }
6338
6339    /// Sets whether recognized touch pans may use the platform's predicted
6340    /// touch positions. Disabling drops [`TouchEvent::predicted_position`]
6341    /// before gesture recognition, so pans track only raw touch positions.
6342    pub fn set_touch_prediction_enabled(&mut self, enabled: bool) {
6343        self.touch_prediction_enabled = enabled;
6344    }
6345
6346    /// Runs the portable gesture recognizer over a raw touch event and
6347    /// dispatches whatever it resolves (scroll steps, synthesized taps)
6348    /// through the ordinary mouse-event path.
6349    fn dispatch_touch_event(&mut self, event: &TouchEvent, cx: &mut App) {
6350        let mut event = event.clone();
6351        if !self.touch_prediction_enabled {
6352            event.predicted_position = None;
6353        }
6354        let recognized_gestures = self.touch_gestures.handle_event(&event);
6355        if event.phase == crate::TouchPhase::Started
6356            && let Some(touch_drag) = self.touch_gestures.offer_touch_drag(event.id)
6357        {
6358            self.dispatch_recognized_touch_gesture(touch_drag, cx);
6359        }
6360        if event.phase == crate::TouchPhase::Started
6361            && self.touch_gestures.pending_long_press().is_some()
6362        {
6363            self.long_press_capture = None;
6364        }
6365        let mut tapped = false;
6366        for gesture in recognized_gestures {
6367            tapped |= matches!(gesture, RecognizedTouchGesture::Tap { .. });
6368            self.dispatch_recognized_touch_gesture(gesture, cx);
6369        }
6370        if event.phase == crate::TouchPhase::Started {
6371            self.schedule_long_press_timer(cx);
6372        } else if self.touch_gestures.pending_long_press().is_none() {
6373            self.long_press_timer.take();
6374        }
6375        // The platform's touch-release handler may inspect the input handler
6376        // as soon as this dispatch returns (the web platform decides virtual
6377        // keyboard visibility there, inside the user gesture). Input handlers
6378        // are registered during draw, so draw now to make them reflect any
6379        // focus change the tap just caused.
6380        if tapped && self.invalidator.is_dirty() {
6381            self.draw(cx).clear(cx);
6382        }
6383        if self.touch_gestures.has_momentum() {
6384            self.schedule_touch_momentum_tick();
6385        }
6386    }
6387
6388    fn dispatch_recognized_touch_gesture(&mut self, gesture: RecognizedTouchGesture, cx: &mut App) {
6389        match gesture {
6390            RecognizedTouchGesture::Scroll(scroll_wheel) => {
6391                self.mouse_position = scroll_wheel.position;
6392                cx.propagate_event = true;
6393                self.dispatch_mouse_event(&scroll_wheel, cx);
6394            }
6395            RecognizedTouchGesture::Tap { down, up } => {
6396                self.mouse_position = up.position;
6397                cx.propagate_event = true;
6398                self.dispatch_mouse_event(&down, cx);
6399                cx.propagate_event = true;
6400                self.dispatch_mouse_event(&up, cx);
6401            }
6402            RecognizedTouchGesture::TouchDrag(touch_drag) => {
6403                self.mouse_position = touch_drag.start_position;
6404                cx.propagate_event = true;
6405                self.default_prevented = false;
6406                let started = touch_drag.phase == crate::TouchPhase::Started;
6407                self.dispatch_mouse_event(&touch_drag, cx);
6408                if started {
6409                    self.touch_gestures
6410                        .resolve_touch_drag(self.default_prevented);
6411                }
6412            }
6413            RecognizedTouchGesture::LongPress(long_press) => {
6414                self.mouse_position = if long_press.phase == crate::TouchPhase::Started {
6415                    long_press.start_position
6416                } else {
6417                    long_press.position
6418                };
6419                cx.propagate_event = true;
6420                self.default_prevented = false;
6421                let started = long_press.phase == crate::TouchPhase::Started;
6422                let ended = matches!(
6423                    long_press.phase,
6424                    crate::TouchPhase::Ended | crate::TouchPhase::Cancelled
6425                );
6426                self.dispatch_mouse_event(&long_press, cx);
6427                if started {
6428                    let claimed = self.default_prevented;
6429                    self.touch_gestures.resolve_long_press(claimed);
6430                    if !claimed {
6431                        self.long_press_capture = None;
6432                    }
6433                }
6434                if ended {
6435                    self.long_press_capture = None;
6436                }
6437            }
6438        }
6439    }
6440
6441    fn schedule_long_press_timer(&mut self, cx: &mut App) {
6442        self.long_press_timer.take();
6443        let Some((touch_id, duration)) = self.touch_gestures.pending_long_press() else {
6444            return;
6445        };
6446        self.long_press_timer = Some(self.spawn(cx, async move |cx| {
6447            cx.background_executor.timer(duration).await;
6448            cx.update(move |window, cx| {
6449                window.long_press_timer.take();
6450                if let Some(gesture) = window.touch_gestures.offer_long_press(touch_id) {
6451                    window.dispatch_recognized_touch_gesture(gesture, cx);
6452                }
6453            })
6454            .log_err();
6455        }));
6456    }
6457
6458    fn schedule_touch_momentum_tick(&mut self) {
6459        self.on_next_frame(|window, cx| {
6460            if let Some(gesture) = window.touch_gestures.tick_momentum() {
6461                window.dispatch_recognized_touch_gesture(gesture, cx);
6462            }
6463            if window.touch_gestures.has_momentum() {
6464                window.schedule_touch_momentum_tick();
6465            }
6466        });
6467    }
6468
6469    fn dispatch_mouse_event(&mut self, event: &dyn Any, cx: &mut App) {
6470        let hit_test = self.rendered_frame.hit_test(self.mouse_position());
6471        if hit_test != self.mouse_hit_test {
6472            self.mouse_hit_test = hit_test;
6473            self.reset_cursor_style(cx);
6474        }
6475
6476        #[cfg(debug_assertions)]
6477        if self.is_inspector_picking(cx) {
6478            self.handle_inspector_mouse_event(event, cx);
6479            // When inspector is picking, all other mouse handling is skipped.
6480            return;
6481        }
6482
6483        let mut mouse_listeners = mem::take(&mut self.rendered_frame.mouse_listeners);
6484
6485        // Capture phase, events bubble from back to front. Handlers for this phase are used for
6486        // special purposes, such as detecting events outside of a given Bounds.
6487        for listener in &mut mouse_listeners {
6488            let listener = listener.as_mut().unwrap();
6489            listener(event, DispatchPhase::Capture, self, cx);
6490            if !cx.propagate_event {
6491                break;
6492            }
6493        }
6494
6495        // Bubble phase, where most normal handlers do their work.
6496        if cx.propagate_event {
6497            for listener in mouse_listeners.iter_mut().rev() {
6498                let listener = listener.as_mut().unwrap();
6499                listener(event, DispatchPhase::Bubble, self, cx);
6500                if !cx.propagate_event {
6501                    break;
6502                }
6503            }
6504        }
6505
6506        self.rendered_frame.mouse_listeners = mouse_listeners;
6507
6508        if cx.has_active_drag() {
6509            if event.is::<MouseMoveEvent>() {
6510                // If this was a mouse move event, redraw the window so that the
6511                // active drag can follow the mouse cursor.
6512                self.refresh();
6513            } else if event.is::<MouseUpEvent>() {
6514                // If this was a mouse up event, cancel the active drag and redraw
6515                // the window.
6516                cx.active_drag = None;
6517                self.refresh();
6518            }
6519        }
6520
6521        // Auto-release pointer capture on mouse up
6522        if event.is::<MouseUpEvent>() && self.captured_hitbox.is_some() {
6523            self.captured_hitbox = None;
6524        }
6525    }
6526
6527    // If modifiers are not excessive (e.g. AltGr), and the input handler is accepting text input,
6528    // we prefer the text input over bindings.
6529    fn input_preference(&mut self, event: &dyn Any, cx: &mut App) -> InputPreference {
6530        let prefer_character_input = event
6531            .downcast_ref::<KeyDownEvent>()
6532            .is_some_and(|key_down_event| key_down_event.prefer_character_input);
6533        if !prefer_character_input {
6534            return InputPreference::KeyBindings;
6535        }
6536        let Some(mut input_handler) = self.platform_window.take_input_handler() else {
6537            return InputPreference::KeyBindings;
6538        };
6539        let accepts_text_input = input_handler.accepts_text_input(self, cx);
6540        self.platform_window.set_input_handler(input_handler);
6541        if accepts_text_input {
6542            InputPreference::CharacterInput
6543        } else {
6544            InputPreference::KeyBindings
6545        }
6546    }
6547
6548    fn dispatch_key_event(&mut self, event: &dyn Any, cx: &mut App) {
6549        if self.invalidator.is_dirty() {
6550            self.draw(cx).clear(cx);
6551        }
6552
6553        let node_id = self.focus_node_id_in_rendered_frame(self.focus);
6554        let dispatch_path = self.rendered_frame.dispatch_tree.dispatch_path(node_id);
6555
6556        let mut keystroke: Option<Keystroke> = None;
6557
6558        if let Some(event) = event.downcast_ref::<ModifiersChangedEvent>() {
6559            if event.modifiers.number_of_modifiers() == 0
6560                && self.pending_modifier.modifiers.number_of_modifiers() == 1
6561                && !self.pending_modifier.saw_other_input
6562            {
6563                let key = match self.pending_modifier.modifiers {
6564                    modifiers if modifiers.shift => Some("shift"),
6565                    modifiers if modifiers.control => Some("control"),
6566                    modifiers if modifiers.alt => Some("alt"),
6567                    modifiers if modifiers.platform => Some("platform"),
6568                    modifiers if modifiers.function => Some("function"),
6569                    _ => None,
6570                };
6571                if let Some(key) = key {
6572                    keystroke = Some(Keystroke {
6573                        key: key.to_string(),
6574                        key_char: None,
6575                        modifiers: Modifiers::default(),
6576                    });
6577                }
6578            }
6579
6580            if self.pending_modifier.modifiers.number_of_modifiers() == 0
6581                && event.modifiers.number_of_modifiers() == 1
6582            {
6583                self.pending_modifier.saw_other_input = false
6584            } else if event.modifiers.number_of_modifiers() > 1 {
6585                self.pending_modifier.saw_other_input = true
6586            }
6587            self.pending_modifier.modifiers = event.modifiers
6588        } else if let Some(key_down_event) = event.downcast_ref::<KeyDownEvent>() {
6589            self.pending_modifier.saw_other_input = true;
6590            keystroke = Some(key_down_event.keystroke.clone());
6591            if key_down_event.keystroke.key_char.is_some()
6592                && matches!(
6593                    cx.cursor_hide_mode,
6594                    CursorHideMode::OnTyping | CursorHideMode::OnTypingAndAction
6595                )
6596            {
6597                cx.platform.hide_cursor_until_mouse_moves();
6598            }
6599        }
6600
6601        let Some(keystroke) = keystroke else {
6602            self.finish_dispatch_key_event(
6603                event,
6604                None,
6605                InputPreference::KeyBindings,
6606                dispatch_path,
6607                self.context_stack(),
6608                cx,
6609            );
6610            return;
6611        };
6612
6613        let input_preference = self.input_preference(event, cx);
6614
6615        cx.propagate_event = true;
6616        self.dispatch_keystroke_interceptors(
6617            &keystroke,
6618            input_preference,
6619            self.context_stack(),
6620            cx,
6621        );
6622        if !cx.propagate_event {
6623            self.finish_dispatch_key_event(
6624                event,
6625                Some(&keystroke),
6626                input_preference,
6627                dispatch_path,
6628                self.context_stack(),
6629                cx,
6630            );
6631            return;
6632        }
6633
6634        let mut currently_pending = self.pending_input.take().unwrap_or_default();
6635        if currently_pending.focus.is_some() && currently_pending.focus != self.focus {
6636            currently_pending = PendingInput::default();
6637        }
6638
6639        let match_result = self.rendered_frame.dispatch_tree.dispatch_key(
6640            currently_pending.keystrokes,
6641            keystroke.clone(),
6642            &dispatch_path,
6643        );
6644
6645        if !match_result.to_replay.is_empty() {
6646            self.replay_pending_input(match_result.to_replay, cx);
6647            cx.propagate_event = true;
6648        }
6649
6650        if !match_result.pending.is_empty() {
6651            let previous_timeout = currently_pending.timeout.take();
6652            currently_pending.keystrokes = match_result.pending;
6653            currently_pending.focus = self.focus;
6654
6655            let text_input_requires_timeout = event
6656                .downcast_ref::<KeyDownEvent>()
6657                .filter(|key_down| key_down.keystroke.key_char.is_some())
6658                .and_then(|_| self.platform_window.take_input_handler())
6659                .map_or(false, |mut input_handler| {
6660                    let accepts = input_handler.accepts_text_input(self, cx);
6661                    self.platform_window.set_input_handler(input_handler);
6662                    accepts
6663                });
6664
6665            let needs_timeout = previous_timeout.is_some()
6666                || match_result.pending_has_binding
6667                || text_input_requires_timeout;
6668            currently_pending.timeout = if needs_timeout {
6669                match previous_timeout {
6670                    Some(mut timeout) if timeout.is_paused() => {
6671                        timeout.reset_duration(PENDING_INPUT_TIMEOUT);
6672                        Some(timeout)
6673                    }
6674                    previous_timeout => {
6675                        drop(previous_timeout);
6676                        Some(self.new_pending_input_timeout(PENDING_INPUT_TIMEOUT, cx))
6677                    }
6678                }
6679            } else {
6680                None
6681            };
6682            self.pending_input = Some(currently_pending);
6683            self.pending_input_changed(cx);
6684            cx.propagate_event = false;
6685            return;
6686        }
6687
6688        // Interceptors or replayed actions may have changed whether the input handler accepts text.
6689        let input_preference = self.input_preference(event, cx);
6690        if input_preference == InputPreference::KeyBindings {
6691            for binding in match_result.bindings {
6692                self.dispatch_action_on_node(node_id, binding.action.as_ref(), cx);
6693                if !cx.propagate_event {
6694                    self.dispatch_keystroke_observers(
6695                        &keystroke,
6696                        input_preference,
6697                        Some(binding.action.as_ref()),
6698                        match_result.context_stack,
6699                        cx,
6700                    );
6701                    self.pending_input_changed(cx);
6702                    return;
6703                }
6704            }
6705        }
6706
6707        self.finish_dispatch_key_event(
6708            event,
6709            Some(&keystroke),
6710            input_preference,
6711            dispatch_path,
6712            match_result.context_stack,
6713            cx,
6714        );
6715        self.pending_input_changed(cx);
6716    }
6717
6718    fn new_pending_input_timeout(&self, duration: Duration, cx: &App) -> PendingInputTimeout {
6719        let (started_at, task) = self.start_pending_input_timeout(duration, cx);
6720        PendingInputTimeout {
6721            duration,
6722            remaining: duration,
6723            state: PendingInputTimeoutState::Running { started_at, task },
6724        }
6725    }
6726
6727    fn start_pending_input_timeout(&self, remaining: Duration, cx: &App) -> (Instant, Task<()>) {
6728        let started_at = cx.background_executor().now();
6729        let task = self.spawn(cx, async move |cx| {
6730            cx.background_executor.timer(remaining).await;
6731            cx.update(move |window, cx| {
6732                let Some(currently_pending) = window
6733                    .pending_input
6734                    .take()
6735                    .filter(|pending| pending.focus == window.focus)
6736                else {
6737                    return;
6738                };
6739
6740                let node_id = window.focus_node_id_in_rendered_frame(window.focus);
6741                let dispatch_path = window.rendered_frame.dispatch_tree.dispatch_path(node_id);
6742
6743                let to_replay = window
6744                    .rendered_frame
6745                    .dispatch_tree
6746                    .flush_dispatch(currently_pending.keystrokes, &dispatch_path);
6747
6748                window.pending_input_changed(cx);
6749                window.replay_pending_input(to_replay, cx)
6750            })
6751            .log_err();
6752        });
6753        (started_at, task)
6754    }
6755
6756    fn finish_dispatch_key_event(
6757        &mut self,
6758        event: &dyn Any,
6759        recognized_keystroke: Option<&Keystroke>,
6760        input_preference: InputPreference,
6761        dispatch_path: SmallVec<[DispatchNodeId; 32]>,
6762        context_stack: Vec<KeyContext>,
6763        cx: &mut App,
6764    ) {
6765        self.dispatch_key_down_up_event(event, &dispatch_path, cx);
6766        if !cx.propagate_event {
6767            return;
6768        }
6769
6770        self.dispatch_modifiers_changed_event(event, &dispatch_path, cx);
6771        if !cx.propagate_event {
6772            return;
6773        }
6774
6775        if let Some(keystroke) = recognized_keystroke {
6776            self.dispatch_keystroke_observers(keystroke, input_preference, None, context_stack, cx);
6777        }
6778    }
6779
6780    pub(crate) fn pending_input_changed(&mut self, cx: &mut App) {
6781        self.pending_input_observers
6782            .clone()
6783            .retain(|callback| callback(self, cx));
6784    }
6785
6786    fn defer_pending_input_changed(&self, cx: &mut App) {
6787        // Avoid re-entrant entity updates by deferring observer notifications to the end of the
6788        // current effect cycle, and only for this window.
6789        let window_handle = self.handle;
6790        cx.defer(move |cx| {
6791            window_handle
6792                .update(cx, |_, window, cx| {
6793                    window.pending_input_changed(cx);
6794                })
6795                .ok();
6796        });
6797    }
6798
6799    fn dispatch_key_down_up_event(
6800        &mut self,
6801        event: &dyn Any,
6802        dispatch_path: &SmallVec<[DispatchNodeId; 32]>,
6803        cx: &mut App,
6804    ) {
6805        // Capture phase
6806        for node_id in dispatch_path {
6807            let node = self.rendered_frame.dispatch_tree.node(*node_id);
6808
6809            for key_listener in node.key_listeners.clone() {
6810                key_listener(event, DispatchPhase::Capture, self, cx);
6811                if !cx.propagate_event {
6812                    return;
6813                }
6814            }
6815        }
6816
6817        // Bubble phase
6818        for node_id in dispatch_path.iter().rev() {
6819            // Handle low level key events
6820            let node = self.rendered_frame.dispatch_tree.node(*node_id);
6821            for key_listener in node.key_listeners.clone() {
6822                key_listener(event, DispatchPhase::Bubble, self, cx);
6823                if !cx.propagate_event {
6824                    return;
6825                }
6826            }
6827        }
6828    }
6829
6830    fn dispatch_modifiers_changed_event(
6831        &mut self,
6832        event: &dyn Any,
6833        dispatch_path: &SmallVec<[DispatchNodeId; 32]>,
6834        cx: &mut App,
6835    ) {
6836        let Some(event) = event.downcast_ref::<ModifiersChangedEvent>() else {
6837            return;
6838        };
6839        for node_id in dispatch_path.iter().rev() {
6840            let node = self.rendered_frame.dispatch_tree.node(*node_id);
6841            for listener in node.modifiers_changed_listeners.clone() {
6842                listener(event, self, cx);
6843                if !cx.propagate_event {
6844                    return;
6845                }
6846            }
6847        }
6848    }
6849
6850    /// Determine whether a potential multi-stroke key binding is in progress on this window.
6851    pub fn has_pending_keystrokes(&self) -> bool {
6852        self.pending_input().is_some()
6853    }
6854
6855    #[cfg(test)]
6856    pub(crate) fn pending_input_is_none(&self) -> bool {
6857        self.pending_input.is_none()
6858    }
6859
6860    pub(crate) fn clear_pending_keystrokes(&mut self, cx: &mut App) {
6861        if self.pending_input.take().is_some() {
6862            self.defer_pending_input_changed(cx);
6863        }
6864    }
6865
6866    /// Returns pending input that can still complete a multi-stroke key binding. Input left over
6867    /// from a previous focus can never complete one.
6868    pub fn pending_input(&self) -> Option<PendingInputStatus<'_>> {
6869        self.pending_input
6870            .as_ref()
6871            .filter(|pending_input| pending_input.focus == self.focus)
6872            .map(|pending_input| PendingInputStatus {
6873                keystrokes: pending_input.keystrokes.as_slice(),
6874                timeout: pending_input
6875                    .timeout
6876                    .as_ref()
6877                    .map(PendingInputTimeout::status),
6878            })
6879    }
6880
6881    /// Pauses or resumes the current pending input timeout on behalf of `owner`.
6882    ///
6883    /// A paused timeout resumes automatically if `owner` is released. Returns whether the timeout
6884    /// state changed. A timeout paused by one owner cannot be resumed by another.
6885    pub fn set_pending_input_timeout_paused<T: 'static>(
6886        &mut self,
6887        owner: &Entity<T>,
6888        paused: bool,
6889        cx: &mut App,
6890    ) -> bool {
6891        let owner_id = owner.entity_id();
6892        if !paused {
6893            return self.resume_pending_input_timeout(owner_id, cx);
6894        }
6895
6896        let timeout = self
6897            .pending_input
6898            .as_ref()
6899            .filter(|pending_input| pending_input.focus == self.focus)
6900            .and_then(|pending_input| pending_input.timeout.as_ref());
6901        let Some(timeout) = timeout else {
6902            return false;
6903        };
6904        if timeout.is_paused() {
6905            return false;
6906        }
6907
6908        let release_subscription = self.observe_release(owner, cx, move |_, window, cx| {
6909            window.resume_pending_input_timeout(owner_id, cx);
6910        });
6911        let now = cx.background_executor().now();
6912        let changed = self
6913            .pending_input
6914            .as_mut()
6915            .filter(|pending_input| pending_input.focus == self.focus)
6916            .and_then(|pending_input| pending_input.timeout.as_mut())
6917            .is_some_and(|timeout| {
6918                timeout.pause(
6919                    PendingInputTimeoutPause {
6920                        owner_id,
6921                        _release_subscription: release_subscription,
6922                    },
6923                    now,
6924                )
6925            });
6926
6927        if changed {
6928            self.defer_pending_input_changed(cx);
6929        }
6930        changed
6931    }
6932
6933    fn resume_pending_input_timeout(&mut self, owner_id: EntityId, cx: &mut App) -> bool {
6934        let Some(remaining) = self
6935            .pending_input
6936            .as_ref()
6937            .and_then(|pending_input| pending_input.timeout.as_ref())
6938            .filter(|timeout| timeout.pause_owner_id() == Some(owner_id))
6939            .map(|timeout| timeout.remaining)
6940        else {
6941            return false;
6942        };
6943
6944        let (started_at, task) = self.start_pending_input_timeout(remaining, cx);
6945        let changed = self
6946            .pending_input
6947            .as_mut()
6948            .and_then(|pending_input| pending_input.timeout.as_mut())
6949            .is_some_and(|timeout| timeout.resume(owner_id, started_at, task));
6950
6951        if changed {
6952            self.defer_pending_input_changed(cx);
6953        }
6954        changed
6955    }
6956
6957    /// Returns the currently pending input keystrokes that might result in a multi-stroke key binding.
6958    pub fn pending_input_keystrokes(&self) -> Option<&[Keystroke]> {
6959        self.pending_input()
6960            .map(|pending_input| pending_input.keystrokes())
6961    }
6962
6963    fn replay_pending_input(&mut self, replays: SmallVec<[Replay; 1]>, cx: &mut App) {
6964        let node_id = self.focus_node_id_in_rendered_frame(self.focus);
6965        let dispatch_path = self.rendered_frame.dispatch_tree.dispatch_path(node_id);
6966
6967        'replay: for replay in replays {
6968            let event = KeyDownEvent {
6969                keystroke: replay.keystroke.clone(),
6970                is_held: false,
6971                prefer_character_input: true,
6972            };
6973
6974            cx.propagate_event = true;
6975            for binding in replay.bindings {
6976                self.dispatch_action_on_node(node_id, binding.action.as_ref(), cx);
6977                if !cx.propagate_event {
6978                    self.dispatch_keystroke_observers(
6979                        &replay.keystroke,
6980                        InputPreference::KeyBindings,
6981                        Some(binding.action.as_ref()),
6982                        Vec::default(),
6983                        cx,
6984                    );
6985                    continue 'replay;
6986                }
6987            }
6988
6989            self.dispatch_key_down_up_event(&event, &dispatch_path, cx);
6990            if !cx.propagate_event {
6991                continue 'replay;
6992            }
6993            if let Some(input) = replay.keystroke.key_char.as_ref().cloned()
6994                && let Some(mut input_handler) = self.platform_window.take_input_handler()
6995            {
6996                input_handler.dispatch_input(&input, self, cx);
6997                self.platform_window.set_input_handler(input_handler)
6998            }
6999        }
7000    }
7001
7002    fn focus_node_id_in_rendered_frame(&self, focus_id: Option<FocusId>) -> DispatchNodeId {
7003        focus_id
7004            .and_then(|focus_id| {
7005                self.rendered_frame
7006                    .dispatch_tree
7007                    .focusable_node_id(focus_id)
7008            })
7009            .unwrap_or_else(|| self.rendered_frame.dispatch_tree.root_node_id())
7010    }
7011
7012    fn dispatch_action_on_node(
7013        &mut self,
7014        node_id: DispatchNodeId,
7015        action: &dyn Action,
7016        cx: &mut App,
7017    ) {
7018        self.dispatch_action_on_node_inner(node_id, action, cx);
7019
7020        if !cx.propagate_event
7021            && cx.cursor_hide_mode == CursorHideMode::OnTypingAndAction
7022            && self.last_input_was_keyboard()
7023        {
7024            cx.platform.hide_cursor_until_mouse_moves();
7025        }
7026    }
7027
7028    fn dispatch_action_on_node_inner(
7029        &mut self,
7030        node_id: DispatchNodeId,
7031        action: &dyn Action,
7032        cx: &mut App,
7033    ) {
7034        let dispatch_path = self.rendered_frame.dispatch_tree.dispatch_path(node_id);
7035
7036        // Capture phase for global actions.
7037        cx.propagate_event = true;
7038        if let Some(mut global_listeners) = cx
7039            .global_action_listeners
7040            .remove(&action.as_any().type_id())
7041        {
7042            for listener in &global_listeners {
7043                #[cfg(feature = "profiler")]
7044                self.window_profiler.begin_action_handler(action, cx);
7045                listener(action.as_any(), DispatchPhase::Capture, cx);
7046                #[cfg(feature = "profiler")]
7047                self.window_profiler.end_action_handler();
7048                if !cx.propagate_event {
7049                    break;
7050                }
7051            }
7052
7053            global_listeners.extend(
7054                cx.global_action_listeners
7055                    .remove(&action.as_any().type_id())
7056                    .unwrap_or_default(),
7057            );
7058
7059            cx.global_action_listeners
7060                .insert(action.as_any().type_id(), global_listeners);
7061        }
7062
7063        if !cx.propagate_event {
7064            return;
7065        }
7066
7067        // Capture phase for window actions.
7068        for node_id in &dispatch_path {
7069            let node = self.rendered_frame.dispatch_tree.node(*node_id);
7070            for DispatchActionListener {
7071                action_type,
7072                listener,
7073            } in node.action_listeners.clone()
7074            {
7075                let any_action = action.as_any();
7076                if action_type == any_action.type_id() {
7077                    #[cfg(feature = "profiler")]
7078                    self.window_profiler.begin_action_handler(action, cx);
7079                    listener(any_action, DispatchPhase::Capture, self, cx);
7080                    #[cfg(feature = "profiler")]
7081                    self.window_profiler.end_action_handler();
7082
7083                    if !cx.propagate_event {
7084                        return;
7085                    }
7086                }
7087            }
7088        }
7089
7090        // Bubble phase for window actions.
7091        for node_id in dispatch_path.iter().rev() {
7092            let node = self.rendered_frame.dispatch_tree.node(*node_id);
7093            for DispatchActionListener {
7094                action_type,
7095                listener,
7096            } in node.action_listeners.clone()
7097            {
7098                let any_action = action.as_any();
7099                if action_type == any_action.type_id() {
7100                    cx.propagate_event = false; // Actions stop propagation by default during the bubble phase
7101                    #[cfg(feature = "profiler")]
7102                    self.window_profiler.begin_action_handler(action, cx);
7103                    listener(any_action, DispatchPhase::Bubble, self, cx);
7104                    #[cfg(feature = "profiler")]
7105                    self.window_profiler.end_action_handler();
7106
7107                    if !cx.propagate_event {
7108                        return;
7109                    }
7110                }
7111            }
7112        }
7113
7114        // Bubble phase for global actions.
7115        if let Some(mut global_listeners) = cx
7116            .global_action_listeners
7117            .remove(&action.as_any().type_id())
7118        {
7119            for listener in global_listeners.iter().rev() {
7120                cx.propagate_event = false; // Actions stop propagation by default during the bubble phase
7121
7122                #[cfg(feature = "profiler")]
7123                self.window_profiler.begin_action_handler(action, cx);
7124                listener(action.as_any(), DispatchPhase::Bubble, cx);
7125                #[cfg(feature = "profiler")]
7126                self.window_profiler.end_action_handler();
7127                if !cx.propagate_event {
7128                    break;
7129                }
7130            }
7131
7132            global_listeners.extend(
7133                cx.global_action_listeners
7134                    .remove(&action.as_any().type_id())
7135                    .unwrap_or_default(),
7136            );
7137
7138            cx.global_action_listeners
7139                .insert(action.as_any().type_id(), global_listeners);
7140        }
7141    }
7142
7143    /// Register the given handler to be invoked whenever the global of the given type
7144    /// is updated.
7145    pub fn observe_global<G: Global>(
7146        &mut self,
7147        cx: &mut App,
7148        f: impl Fn(&mut Window, &mut App) + 'static,
7149    ) -> Subscription {
7150        let window_handle = self.handle;
7151        let (subscription, activate) = cx.global_observers.insert_pending(
7152            TypeId::of::<G>(),
7153            Box::new(move |cx| {
7154                window_handle
7155                    .update(cx, |_, window, cx| f(window, cx))
7156                    .is_ok()
7157            }),
7158        );
7159        cx.defer(move |_| activate());
7160        subscription
7161    }
7162
7163    /// Focus the current window and bring it to the foreground at the platform level.
7164    pub fn activate_window(&self) {
7165        self.platform_window.activate();
7166    }
7167
7168    /// Requests that the operating system draw attention to this window.
7169    pub fn request_attention(&self) {
7170        self.platform_window.request_attention();
7171    }
7172
7173    /// Minimize the current window at the platform level.
7174    pub fn minimize_window(&self) {
7175        self.platform_window.minimize();
7176    }
7177
7178    /// Toggle full screen status on the current window at the platform level.
7179    pub fn toggle_fullscreen(&self) {
7180        self.platform_window.toggle_fullscreen();
7181    }
7182
7183    /// Toggle simple (borderless) fullscreen, where the window covers the entire
7184    /// screen including the menu bar and, on notched displays, the area around the
7185    /// notch. Unlike [`Window::toggle_fullscreen`], this does not move the window
7186    /// into its own Mission Control space. Only has an effect on macOS.
7187    pub fn toggle_simple_fullscreen(&self) {
7188        self.platform_window.toggle_simple_fullscreen();
7189    }
7190
7191    /// Updates the IME panel position suggestions for languages like japanese, chinese.
7192    pub fn invalidate_character_coordinates(&self) {
7193        self.on_next_frame(|window, cx| {
7194            if let Some(mut input_handler) = window.platform_window.take_input_handler() {
7195                if let Some(bounds) = input_handler.selected_bounds(window, cx) {
7196                    window.platform_window.update_ime_position(bounds);
7197                }
7198                window.platform_window.set_input_handler(input_handler);
7199            }
7200        });
7201    }
7202
7203    /// Present a platform dialog.
7204    /// The provided message will be presented, along with buttons for each answer.
7205    /// When a button is clicked, the returned Receiver will receive the index of the clicked button.
7206    pub fn prompt<T>(
7207        &mut self,
7208        level: PromptLevel,
7209        message: &str,
7210        detail: Option<&str>,
7211        answers: &[T],
7212        cx: &mut App,
7213    ) -> oneshot::Receiver<usize>
7214    where
7215        T: Clone + Into<PromptButton>,
7216    {
7217        let prompt_builder = cx.prompt_builder.take();
7218        let Some(prompt_builder) = prompt_builder else {
7219            unreachable!("Re-entrant window prompting is not supported by GPUI");
7220        };
7221
7222        let answers = answers
7223            .iter()
7224            .map(|answer| answer.clone().into())
7225            .collect::<Vec<_>>();
7226
7227        let receiver = match &prompt_builder {
7228            PromptBuilder::Default => self
7229                .platform_window
7230                .prompt(level, message, detail, &answers)
7231                .unwrap_or_else(|| {
7232                    self.build_custom_prompt(&prompt_builder, level, message, detail, &answers, cx)
7233                }),
7234            PromptBuilder::Custom(_) => {
7235                self.build_custom_prompt(&prompt_builder, level, message, detail, &answers, cx)
7236            }
7237        };
7238
7239        cx.prompt_builder = Some(prompt_builder);
7240
7241        receiver
7242    }
7243
7244    fn build_custom_prompt(
7245        &mut self,
7246        prompt_builder: &PromptBuilder,
7247        level: PromptLevel,
7248        message: &str,
7249        detail: Option<&str>,
7250        answers: &[PromptButton],
7251        cx: &mut App,
7252    ) -> oneshot::Receiver<usize> {
7253        let (sender, receiver) = oneshot::channel();
7254        let handle = PromptHandle::new(sender);
7255        let handle = (prompt_builder)(level, message, detail, answers, handle, self, cx);
7256        self.prompt = Some(handle);
7257        receiver
7258    }
7259
7260    /// Returns whether a prompt rendered by GPUI is currently active in this window.
7261    ///
7262    /// This is only true for prompts rendered in the window (see
7263    /// [`App::set_prompt_builder`]), not for platform-native prompt dialogs.
7264    pub fn has_active_prompt(&self) -> bool {
7265        self.prompt.is_some()
7266    }
7267
7268    /// Returns the current context stack.
7269    pub fn context_stack(&self) -> Vec<KeyContext> {
7270        let node_id = self.focus_node_id_in_rendered_frame(self.focus);
7271        let dispatch_tree = &self.rendered_frame.dispatch_tree;
7272        dispatch_tree
7273            .dispatch_path(node_id)
7274            .iter()
7275            .filter_map(move |&node_id| dispatch_tree.node(node_id).context.clone())
7276            .collect()
7277    }
7278
7279    /// Returns all available actions for the focused element.
7280    pub fn available_actions(&self, cx: &App) -> Vec<Box<dyn Action>> {
7281        let node_id = self.focus_node_id_in_rendered_frame(self.focus);
7282        let mut actions = self.rendered_frame.dispatch_tree.available_actions(node_id);
7283        for action_type in cx.global_action_listeners.keys() {
7284            if let Err(ix) = actions.binary_search_by_key(action_type, |a| a.as_any().type_id()) {
7285                let action = cx.actions.build_action_type(action_type).ok();
7286                if let Some(action) = action {
7287                    actions.insert(ix, action);
7288                }
7289            }
7290        }
7291        actions
7292    }
7293
7294    /// Returns key bindings that invoke an action on the currently focused element. Bindings are
7295    /// returned in the order they were added. For display, the last binding should take precedence.
7296    pub fn bindings_for_action(&self, action: &dyn Action) -> Vec<KeyBinding> {
7297        self.rendered_frame
7298            .dispatch_tree
7299            .bindings_for_action(action, &self.rendered_frame.dispatch_tree.context_stack)
7300    }
7301
7302    /// Returns the highest precedence key binding that invokes an action on the currently focused
7303    /// element. This is more efficient than getting the last result of `bindings_for_action`.
7304    pub fn highest_precedence_binding_for_action(&self, action: &dyn Action) -> Option<KeyBinding> {
7305        self.rendered_frame
7306            .dispatch_tree
7307            .highest_precedence_binding_for_action(
7308                action,
7309                &self.rendered_frame.dispatch_tree.context_stack,
7310            )
7311    }
7312
7313    /// Returns the key bindings for an action in a context.
7314    pub fn bindings_for_action_in_context(
7315        &self,
7316        action: &dyn Action,
7317        context: KeyContext,
7318    ) -> Vec<KeyBinding> {
7319        let dispatch_tree = &self.rendered_frame.dispatch_tree;
7320        dispatch_tree.bindings_for_action(action, &[context])
7321    }
7322
7323    /// Returns the highest precedence key binding for an action in a context. This is more
7324    /// efficient than getting the last result of `bindings_for_action_in_context`.
7325    pub fn highest_precedence_binding_for_action_in_context(
7326        &self,
7327        action: &dyn Action,
7328        context: KeyContext,
7329    ) -> Option<KeyBinding> {
7330        let dispatch_tree = &self.rendered_frame.dispatch_tree;
7331        dispatch_tree.highest_precedence_binding_for_action(action, &[context])
7332    }
7333
7334    /// Returns any bindings that would invoke an action on the given focus handle if it were
7335    /// focused. Bindings are returned in the order they were added. For display, the last binding
7336    /// should take precedence.
7337    pub fn bindings_for_action_in(
7338        &self,
7339        action: &dyn Action,
7340        focus_handle: &FocusHandle,
7341    ) -> Vec<KeyBinding> {
7342        let dispatch_tree = &self.rendered_frame.dispatch_tree;
7343        let Some(context_stack) = self.context_stack_for_focus_handle(focus_handle) else {
7344            return vec![];
7345        };
7346        dispatch_tree.bindings_for_action(action, &context_stack)
7347    }
7348
7349    /// Returns the highest precedence key binding that would invoke an action on the given focus
7350    /// handle if it were focused. This is more efficient than getting the last result of
7351    /// `bindings_for_action_in`.
7352    pub fn highest_precedence_binding_for_action_in(
7353        &self,
7354        action: &dyn Action,
7355        focus_handle: &FocusHandle,
7356    ) -> Option<KeyBinding> {
7357        let dispatch_tree = &self.rendered_frame.dispatch_tree;
7358        let context_stack = self.context_stack_for_focus_handle(focus_handle)?;
7359        dispatch_tree.highest_precedence_binding_for_action(action, &context_stack)
7360    }
7361
7362    /// Find the bindings that can follow the current input sequence for the current context stack.
7363    pub fn possible_bindings_for_input(&self, input: &[Keystroke]) -> Vec<KeyBinding> {
7364        self.rendered_frame
7365            .dispatch_tree
7366            .possible_next_bindings_for_input(input, &self.context_stack())
7367    }
7368
7369    fn context_stack_for_focus_handle(
7370        &self,
7371        focus_handle: &FocusHandle,
7372    ) -> Option<Vec<KeyContext>> {
7373        let dispatch_tree = &self.rendered_frame.dispatch_tree;
7374        let node_id = dispatch_tree.focusable_node_id(focus_handle.id)?;
7375        let context_stack: Vec<_> = dispatch_tree
7376            .dispatch_path(node_id)
7377            .into_iter()
7378            .filter_map(|node_id| dispatch_tree.node(node_id).context.clone())
7379            .collect();
7380        Some(context_stack)
7381    }
7382
7383    /// Returns a generic event listener that invokes the given listener with the view and context associated with the given view handle.
7384    pub fn listener_for<T: 'static, E>(
7385        &self,
7386        view: &Entity<T>,
7387        f: impl Fn(&mut T, &E, &mut Window, &mut Context<T>) + 'static,
7388    ) -> impl Fn(&E, &mut Window, &mut App) + 'static {
7389        let view = view.downgrade();
7390        move |e: &E, window: &mut Window, cx: &mut App| {
7391            view.update(cx, |view, cx| f(view, e, window, cx)).ok();
7392        }
7393    }
7394
7395    /// Returns a generic handler that invokes the given handler with the view and context associated with the given view handle.
7396    pub fn handler_for<E: 'static, Callback: Fn(&mut E, &mut Window, &mut Context<E>) + 'static>(
7397        &self,
7398        entity: &Entity<E>,
7399        f: Callback,
7400    ) -> impl Fn(&mut Window, &mut App) + 'static {
7401        let entity = entity.downgrade();
7402        move |window: &mut Window, cx: &mut App| {
7403            entity.update(cx, |entity, cx| f(entity, window, cx)).ok();
7404        }
7405    }
7406
7407    /// Register a callback that can interrupt the closing of the current window based the returned boolean.
7408    /// If the callback returns false, the window won't be closed.
7409    pub fn on_window_should_close(
7410        &self,
7411        cx: &App,
7412        f: impl Fn(&mut Window, &mut App) -> bool + 'static,
7413    ) {
7414        let mut cx = self.to_async(cx);
7415        self.platform_window.on_should_close(Box::new(move || {
7416            cx.update(|window, cx| f(window, cx)).unwrap_or(true)
7417        }))
7418    }
7419
7420    /// Register an action listener on this node for the next frame. The type of action
7421    /// is determined by the first parameter of the given listener. When the next frame is rendered
7422    /// the listener will be cleared.
7423    ///
7424    /// This is a fairly low-level method, so prefer using action handlers on elements unless you have
7425    /// a specific need to register a listener yourself.
7426    ///
7427    /// This method should only be called as part of the paint phase of element drawing.
7428    pub fn on_action(
7429        &mut self,
7430        action_type: TypeId,
7431        listener: impl Fn(&dyn Any, DispatchPhase, &mut Window, &mut App) + 'static,
7432    ) {
7433        self.invalidator.debug_assert_paint();
7434
7435        self.next_frame
7436            .dispatch_tree
7437            .on_action(action_type, Rc::new(listener));
7438    }
7439
7440    /// Register a capturing action listener on this node for the next frame if the condition is true.
7441    /// The type of action is determined by the first parameter of the given listener. When the next
7442    /// frame is rendered the listener will be cleared.
7443    ///
7444    /// This is a fairly low-level method, so prefer using action handlers on elements unless you have
7445    /// a specific need to register a listener yourself.
7446    ///
7447    /// This method should only be called as part of the paint phase of element drawing.
7448    pub fn on_action_when(
7449        &mut self,
7450        condition: bool,
7451        action_type: TypeId,
7452        listener: impl Fn(&dyn Any, DispatchPhase, &mut Window, &mut App) + 'static,
7453    ) {
7454        self.invalidator.debug_assert_paint();
7455
7456        if condition {
7457            self.next_frame
7458                .dispatch_tree
7459                .on_action(action_type, Rc::new(listener));
7460        }
7461    }
7462
7463    /// Read information about the GPU backing this window.
7464    /// Currently returns None on Mac and Windows.
7465    pub fn gpu_specs(&self) -> Option<GpuSpecs> {
7466        self.platform_window.gpu_specs()
7467    }
7468
7469    /// Perform titlebar double-click action.
7470    /// This is macOS specific.
7471    pub fn titlebar_double_click(&self) {
7472        self.platform_window
7473            .titlebar_double_click(self.is_resizable, self.is_minimizable);
7474    }
7475
7476    /// Gets the window's title at the platform level.
7477    /// This is macOS specific.
7478    pub fn window_title(&self) -> String {
7479        self.platform_window.get_title()
7480    }
7481
7482    /// Returns a list of all tabbed windows and their titles.
7483    /// This is macOS specific.
7484    pub fn tabbed_windows(&self) -> Option<Vec<SystemWindowTab>> {
7485        self.platform_window.tabbed_windows()
7486    }
7487
7488    /// Returns the tab bar visibility.
7489    /// This is macOS specific.
7490    pub fn tab_bar_visible(&self) -> bool {
7491        self.platform_window.tab_bar_visible()
7492    }
7493
7494    /// Merges all open windows into a single tabbed window.
7495    /// This is macOS specific.
7496    pub fn merge_all_windows(&self) {
7497        self.platform_window.merge_all_windows()
7498    }
7499
7500    /// Moves the tab to a new containing window.
7501    /// This is macOS specific.
7502    pub fn move_tab_to_new_window(&self) {
7503        self.platform_window.move_tab_to_new_window()
7504    }
7505
7506    /// Shows or hides the window tab overview.
7507    /// This is macOS specific.
7508    pub fn toggle_window_tab_overview(&self) {
7509        self.platform_window.toggle_window_tab_overview()
7510    }
7511
7512    /// Sets the tabbing identifier for the window.
7513    /// This is macOS specific.
7514    pub fn set_tabbing_identifier(&self, tabbing_identifier: Option<String>) {
7515        self.platform_window
7516            .set_tabbing_identifier(tabbing_identifier)
7517    }
7518
7519    /// Request the OS to play an alert sound. On some platforms this is associated
7520    /// with the window, for others it's just a simple global function call.
7521    pub fn play_system_bell(&self) {
7522        self.platform_window.play_system_bell()
7523    }
7524
7525    /// Returns whether accessibility support is enabled for this window.
7526    ///
7527    /// This is false when the app was created with [`crate::Application::new_inaccessible`].
7528    /// Unlike [`Self::is_a11y_active`], this does not depend on whether assistive
7529    /// technology is currently connected, so it can be used to gate subscriptions
7530    /// that are only needed for accessibility.
7531    pub fn is_a11y_enabled(&self) -> bool {
7532        self.a11y.is_enabled()
7533    }
7534
7535    /// Returns whether accessibility features are active for this frame,
7536    /// i.e. whether assistive technology (such as a screen reader) is
7537    /// connected and an accessibility tree is being built.
7538    ///
7539    /// Use this to skip computing data during rendering that is only
7540    /// observable through the accessibility tree. When accessibility is
7541    /// activated, a redraw is forced, so gated work is recomputed before the
7542    /// next tree update is sent to the platform.
7543    ///
7544    /// See the [accessibility guide](crate::_accessibility) for an overview.
7545    pub fn is_a11y_active(&self) -> bool {
7546        self.a11y.is_active()
7547    }
7548
7549    /// Debug representation of the last frame's accessibility information.
7550    pub fn debug_a11y_tree_json(&self) -> Option<String> {
7551        self.a11y.debug_tree_json()
7552    }
7553
7554    /// Register a listener for an accessibility action on a specific node.
7555    /// The listener will be called when a screen reader requests the given
7556    /// action on the node identified by `node_id`.
7557    ///
7558    /// See the [accessibility guide](crate::_accessibility) for an overview.
7559    pub fn on_a11y_action(
7560        &mut self,
7561        node_id: accesskit::NodeId,
7562        action: accesskit::Action,
7563        listener: impl FnMut(Option<&accesskit::ActionData>, &mut Window, &mut App) + 'static,
7564    ) {
7565        self.a11y
7566            .action_listeners
7567            .entry(node_id)
7568            .or_default()
7569            .push((action, Box::new(listener)));
7570    }
7571
7572    #[cfg(not(target_family = "wasm"))]
7573    pub(crate) fn handle_a11y_action(&mut self, request: accesskit::ActionRequest, cx: &mut App) {
7574        // Take listeners out temporarily so the closures can borrow Window
7575        // mutably, then restore them afterward.
7576        if let Some(mut listeners) = self.a11y.action_listeners.remove(&request.target_node) {
7577            let extra_data = request.data.as_ref();
7578            let mut matched = false;
7579            for (action, listener) in &mut listeners {
7580                if *action == request.action {
7581                    listener(extra_data, self, cx);
7582                    matched = true;
7583                }
7584            }
7585            self.a11y
7586                .action_listeners
7587                .insert(request.target_node, listeners);
7588            if matched {
7589                return;
7590            }
7591        }
7592
7593        // Fall back to built-in action handling.
7594        match request.action {
7595            accesskit::Action::Click => {
7596                if let Some(bounds) = self.a11y.node_bounds.get(&request.target_node).copied() {
7597                    let center = bounds.center();
7598                    let mouse_down = PlatformInput::MouseDown(crate::MouseDownEvent {
7599                        button: MouseButton::Left,
7600                        position: center,
7601                        modifiers: Modifiers::default(),
7602                        click_count: 1,
7603                        first_mouse: false,
7604                    });
7605                    let mouse_up = PlatformInput::MouseUp(MouseUpEvent {
7606                        button: MouseButton::Left,
7607                        position: center,
7608                        modifiers: Modifiers::default(),
7609                        click_count: 1,
7610                    });
7611                    self.dispatch_event(mouse_down, cx);
7612                    self.dispatch_event(mouse_up, cx);
7613                }
7614            }
7615            accesskit::Action::Focus => {
7616                if let Some(focus_id) = self.a11y.focus_ids.get(&request.target_node).copied()
7617                    && let Some(handle) = FocusHandle::for_id(focus_id, &cx.focus_handles)
7618                {
7619                    self.focus(&handle, cx);
7620                }
7621            }
7622            accesskit::Action::Blur => {
7623                self.blur(cx);
7624            }
7625            _ => {
7626                log::debug!(
7627                    "Unhandled a11y action: {:?} on {:?}",
7628                    request.action,
7629                    request.target_node
7630                );
7631            }
7632        }
7633    }
7634
7635    /// Toggles the inspector mode on this window.
7636    #[cfg(debug_assertions)]
7637    pub fn toggle_inspector(&mut self, cx: &mut App) {
7638        self.inspector = match self.inspector {
7639            None => Some(cx.new(|_| Inspector::new())),
7640            Some(_) => {
7641                self.rendered_frame.next_inspector_instance_ids = FxHashMap::default();
7642                self.rendered_frame.inspector_hitboxes = FxHashMap::default();
7643                self.next_frame.next_inspector_instance_ids = FxHashMap::default();
7644                self.next_frame.inspector_hitboxes = FxHashMap::default();
7645                None
7646            }
7647        };
7648        self.refresh();
7649    }
7650
7651    /// Returns true if the window is in inspector mode.
7652    pub fn is_inspector_picking(&self, _cx: &App) -> bool {
7653        #[cfg(debug_assertions)]
7654        {
7655            if let Some(inspector) = &self.inspector {
7656                return inspector.read(_cx).is_picking();
7657            }
7658        }
7659        false
7660    }
7661
7662    /// Executes the provided function with mutable access to an inspector state.
7663    #[cfg(debug_assertions)]
7664    pub fn with_inspector_state<T: 'static, R>(
7665        &mut self,
7666        inspector_id: Option<&crate::InspectorElementId>,
7667        cx: &mut App,
7668        f: impl FnOnce(&mut Option<T>, &mut Self) -> R,
7669    ) -> Option<R> {
7670        let inspector_id = inspector_id?;
7671        let inspector = self.inspector.as_ref()?;
7672        if inspector.read(cx).active_element_id() != Some(inspector_id) {
7673            return None;
7674        }
7675        let inspector = inspector.clone();
7676        Some(inspector.update(cx, |inspector, _cx| {
7677            inspector.with_active_element_state(self, f)
7678        }))
7679    }
7680
7681    #[cfg(debug_assertions)]
7682    pub(crate) fn inspector_enabled(&self) -> bool {
7683        self.inspector.is_some()
7684    }
7685
7686    #[cfg(debug_assertions)]
7687    pub(crate) fn build_inspector_element_id(
7688        &mut self,
7689        path: crate::InspectorElementPath,
7690    ) -> crate::InspectorElementId {
7691        self.invalidator.debug_assert_paint_or_prepaint();
7692        let path = Rc::new(path);
7693        let next_instance_id = self
7694            .next_frame
7695            .next_inspector_instance_ids
7696            .entry(path.clone())
7697            .or_insert(0);
7698        let instance_id = *next_instance_id;
7699        *next_instance_id += 1;
7700        crate::InspectorElementId { path, instance_id }
7701    }
7702
7703    #[cfg(debug_assertions)]
7704    fn prepaint_inspector(&mut self, inspector_width: Pixels, cx: &mut App) -> Option<AnyElement> {
7705        if let Some(inspector) = self.inspector.take() {
7706            let mut inspector_element = AnyView::from(inspector.clone()).into_any_element();
7707            inspector_element.prepaint_as_root(
7708                point(self.viewport_size.width - inspector_width, px(0.0)),
7709                size(inspector_width, self.viewport_size.height).into(),
7710                self,
7711                cx,
7712            );
7713            self.inspector = Some(inspector);
7714            Some(inspector_element)
7715        } else {
7716            None
7717        }
7718    }
7719
7720    #[cfg(debug_assertions)]
7721    fn paint_inspector(&mut self, inspector_element: Option<AnyElement>, cx: &mut App) {
7722        if let Some(mut inspector_element) = inspector_element {
7723            inspector_element.paint(self, cx);
7724        };
7725    }
7726
7727    /// Registers a hitbox that can be used for inspector picking mode, allowing users to select and
7728    /// inspect UI elements by clicking on them.
7729    #[cfg(debug_assertions)]
7730    pub fn insert_inspector_hitbox(
7731        &mut self,
7732        hitbox_id: HitboxId,
7733        inspector_id: Option<&crate::InspectorElementId>,
7734        cx: &App,
7735    ) {
7736        self.invalidator.debug_assert_paint_or_prepaint();
7737        if !self.is_inspector_picking(cx) {
7738            return;
7739        }
7740        if let Some(inspector_id) = inspector_id {
7741            self.next_frame
7742                .inspector_hitboxes
7743                .insert(hitbox_id, inspector_id.clone());
7744        }
7745    }
7746
7747    #[cfg(debug_assertions)]
7748    fn paint_inspector_hitbox(&mut self, cx: &App) {
7749        if let Some(inspector) = self.inspector.as_ref() {
7750            let inspector = inspector.read(cx);
7751            if let Some((hitbox_id, _)) = self.hovered_inspector_hitbox(inspector, &self.next_frame)
7752                && let Some(hitbox) = self
7753                    .next_frame
7754                    .hitboxes
7755                    .iter()
7756                    .find(|hitbox| hitbox.id == hitbox_id)
7757            {
7758                self.paint_quad(crate::fill(hitbox.bounds, crate::rgba(0x61afef4d)));
7759            }
7760        }
7761    }
7762
7763    #[cfg(debug_assertions)]
7764    fn handle_inspector_mouse_event(&mut self, event: &dyn Any, cx: &mut App) {
7765        let Some(inspector) = self.inspector.clone() else {
7766            return;
7767        };
7768        if event.downcast_ref::<MouseMoveEvent>().is_some() {
7769            inspector.update(cx, |inspector, _cx| {
7770                if let Some((_, inspector_id)) =
7771                    self.hovered_inspector_hitbox(inspector, &self.rendered_frame)
7772                {
7773                    inspector.hover(inspector_id, self);
7774                }
7775            });
7776        } else if event.downcast_ref::<crate::MouseDownEvent>().is_some() {
7777            inspector.update(cx, |inspector, _cx| {
7778                if let Some((_, inspector_id)) =
7779                    self.hovered_inspector_hitbox(inspector, &self.rendered_frame)
7780                {
7781                    inspector.select(inspector_id, self);
7782                }
7783            });
7784        } else if let Some(event) = event.downcast_ref::<crate::ScrollEvent>() {
7785            // This should be kept in sync with SCROLL_LINES in x11 platform.
7786            const SCROLL_LINES: f32 = 3.0;
7787            const SCROLL_PIXELS_PER_LAYER: f32 = 36.0;
7788            let delta_y = event
7789                .delta
7790                .pixel_delta(px(SCROLL_PIXELS_PER_LAYER / SCROLL_LINES))
7791                .y;
7792            if let Some(inspector) = self.inspector.clone() {
7793                inspector.update(cx, |inspector, _cx| {
7794                    if let Some(depth) = inspector.pick_depth.as_mut() {
7795                        *depth += f32::from(delta_y) / SCROLL_PIXELS_PER_LAYER;
7796                        let max_depth = self.mouse_hit_test.ids.len() as f32 - 0.5;
7797                        if *depth < 0.0 {
7798                            *depth = 0.0;
7799                        } else if *depth > max_depth {
7800                            *depth = max_depth;
7801                        }
7802                        if let Some((_, inspector_id)) =
7803                            self.hovered_inspector_hitbox(inspector, &self.rendered_frame)
7804                        {
7805                            inspector.set_active_element_id(inspector_id, self);
7806                        }
7807                    }
7808                });
7809            }
7810        }
7811    }
7812
7813    #[cfg(debug_assertions)]
7814    fn hovered_inspector_hitbox(
7815        &self,
7816        inspector: &Inspector,
7817        frame: &Frame,
7818    ) -> Option<(HitboxId, crate::InspectorElementId)> {
7819        if let Some(pick_depth) = inspector.pick_depth {
7820            let depth = (pick_depth as i64).try_into().unwrap_or(0);
7821            let max_skipped = self.mouse_hit_test.ids.len().saturating_sub(1);
7822            let skip_count = (depth as usize).min(max_skipped);
7823            for hitbox_id in self.mouse_hit_test.ids.iter().skip(skip_count) {
7824                if let Some(inspector_id) = frame.inspector_hitboxes.get(hitbox_id) {
7825                    return Some((*hitbox_id, inspector_id.clone()));
7826                }
7827            }
7828        }
7829        None
7830    }
7831
7832    /// For testing: set the current modifier keys state.
7833    /// This does not generate any events.
7834    #[cfg(any(test, feature = "test-support"))]
7835    pub fn set_modifiers(&mut self, modifiers: Modifiers) {
7836        self.modifiers = modifiers;
7837    }
7838
7839    /// For testing: simulate a mouse move event to the given position.
7840    /// This dispatches the event through the normal event handling path,
7841    /// which will trigger hover states and tooltips.
7842    #[cfg(any(test, feature = "test-support"))]
7843    pub fn simulate_mouse_move(&mut self, position: Point<Pixels>, cx: &mut App) {
7844        let event = PlatformInput::MouseMove(MouseMoveEvent {
7845            position,
7846            modifiers: self.modifiers,
7847            pressed_button: None,
7848        });
7849        let _ = self.dispatch_event(event, cx);
7850    }
7851
7852    #[inline(never)]
7853    fn take_element_state(
7854        &mut self,
7855        global_id: &GlobalElementId,
7856        state_type: TypeId,
7857    ) -> ((GlobalElementId, TypeId), Option<ElementStateBox>) {
7858        let key = (global_id.clone(), state_type);
7859        self.next_frame.accessed_element_states.push(key.clone());
7860        let state = self
7861            .next_frame
7862            .element_states
7863            .remove(&key)
7864            .or_else(|| self.rendered_frame.element_states.remove(&key));
7865        (key, state)
7866    }
7867
7868    #[inline(never)]
7869    fn insert_element_state(
7870        &mut self,
7871        key: (GlobalElementId, TypeId),
7872        state: ElementStateBox,
7873    ) -> Option<ElementStateBox> {
7874        self.next_frame.element_states.insert(key, state)
7875    }
7876
7877    #[inline(never)]
7878    fn observe_keyed_state<S: 'static>(state: &Entity<S>, current_view: EntityId, cx: &mut App) {
7879        cx.observe(state, move |_, cx| {
7880            cx.notify(current_view);
7881        })
7882        .detach();
7883    }
7884}
7885
7886// #[derive(Clone, Copy, Eq, PartialEq, Hash)]
7887slotmap::new_key_type! {
7888    /// A unique identifier for a window.
7889    pub struct WindowId;
7890}
7891
7892impl WindowId {
7893    /// Converts this window ID to a `u64`.
7894    pub fn as_u64(&self) -> u64 {
7895        self.0.as_ffi()
7896    }
7897}
7898
7899impl From<u64> for WindowId {
7900    fn from(value: u64) -> Self {
7901        WindowId(slotmap::KeyData::from_ffi(value))
7902    }
7903}
7904
7905/// A handle to a window with a specific root view type.
7906/// Note that this does not keep the window alive on its own.
7907#[derive(Deref, DerefMut)]
7908pub struct WindowHandle<V> {
7909    #[deref]
7910    #[deref_mut]
7911    pub(crate) any_handle: AnyWindowHandle,
7912    state_type: PhantomData<fn(V) -> V>,
7913}
7914
7915impl<V> Debug for WindowHandle<V> {
7916    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
7917        f.debug_struct("WindowHandle")
7918            .field("any_handle", &self.any_handle.id.as_u64())
7919            .finish()
7920    }
7921}
7922
7923impl<V: 'static + Render> WindowHandle<V> {
7924    /// Creates a new handle from a window ID.
7925    /// This does not check if the root type of the window is `V`.
7926    pub fn new(id: WindowId) -> Self {
7927        WindowHandle {
7928            any_handle: AnyWindowHandle {
7929                id,
7930                state_type: TypeId::of::<V>(),
7931                root_entity_type_name: std::any::type_name::<V>(),
7932            },
7933            state_type: PhantomData,
7934        }
7935    }
7936
7937    /// Get the root view out of this window.
7938    ///
7939    /// This will fail if the window is closed or if the root view's type does not match `V`.
7940    #[cfg(any(test, feature = "test-support"))]
7941    pub fn root<C>(&self, cx: &mut C) -> Result<Entity<V>>
7942    where
7943        C: AppContext,
7944    {
7945        cx.update_window(self.any_handle, |root_view, _, _| {
7946            root_view
7947                .downcast::<V>()
7948                .map_err(|_| anyhow!("the type of the window's root view has changed"))
7949        })?
7950    }
7951
7952    /// Updates the root view of this window.
7953    ///
7954    /// This will fail if the window has been closed or if the root view's type does not match
7955    pub fn update<C, R>(
7956        &self,
7957        cx: &mut C,
7958        update: impl FnOnce(&mut V, &mut Window, &mut Context<V>) -> R,
7959    ) -> Result<R>
7960    where
7961        C: AppContext,
7962    {
7963        cx.update_window(self.any_handle, |root_view, window, cx| {
7964            let view = root_view
7965                .downcast::<V>()
7966                .map_err(|_| anyhow!("the type of the window's root view has changed"))?;
7967
7968            Ok(view.update(cx, |view, cx| update(view, window, cx)))
7969        })?
7970    }
7971
7972    /// Read the root view out of this window.
7973    ///
7974    /// This will fail if the window is closed or if the root view's type does not match `V`.
7975    pub fn read<'a>(&self, cx: &'a App) -> Result<&'a V> {
7976        let x = cx
7977            .windows
7978            .get(self.id)
7979            .and_then(|window| {
7980                window
7981                    .as_deref()
7982                    .and_then(|window| window.root.clone())
7983                    .map(|root_view| root_view.downcast::<V>())
7984            })
7985            .context("window not found")?
7986            .map_err(|_| anyhow!("the type of the window's root view has changed"))?;
7987
7988        Ok(x.read(cx))
7989    }
7990
7991    /// Read the root view out of this window, with a callback
7992    ///
7993    /// This will fail if the window is closed or if the root view's type does not match `V`.
7994    pub fn read_with<C, R>(&self, cx: &C, read_with: impl FnOnce(&V, &App) -> R) -> Result<R>
7995    where
7996        C: AppContext,
7997    {
7998        cx.read_window(self, |root_view, cx| read_with(root_view.read(cx), cx))
7999    }
8000
8001    /// Read the root view pointer off of this window.
8002    ///
8003    /// This will fail if the window is closed or if the root view's type does not match `V`.
8004    pub fn entity<C>(&self, cx: &C) -> Result<Entity<V>>
8005    where
8006        C: AppContext,
8007    {
8008        cx.read_window(self, |root_view, _cx| root_view)
8009    }
8010
8011    /// Check if this window is 'active'.
8012    ///
8013    /// Will return `None` if the window is closed or currently
8014    /// borrowed.
8015    pub fn is_active(&self, cx: &mut App) -> Option<bool> {
8016        cx.update_window(self.any_handle, |_, window, _| window.is_window_active())
8017            .ok()
8018    }
8019}
8020
8021impl<V> Copy for WindowHandle<V> {}
8022
8023impl<V> Clone for WindowHandle<V> {
8024    fn clone(&self) -> Self {
8025        *self
8026    }
8027}
8028
8029impl<V> PartialEq for WindowHandle<V> {
8030    fn eq(&self, other: &Self) -> bool {
8031        self.any_handle == other.any_handle
8032    }
8033}
8034
8035impl<V> Eq for WindowHandle<V> {}
8036
8037impl<V> Hash for WindowHandle<V> {
8038    fn hash<H: Hasher>(&self, state: &mut H) {
8039        self.any_handle.hash(state);
8040    }
8041}
8042
8043impl<V: 'static> From<WindowHandle<V>> for AnyWindowHandle {
8044    fn from(val: WindowHandle<V>) -> Self {
8045        val.any_handle
8046    }
8047}
8048
8049/// A handle to a window with any root view type, which can be downcast to a window with a specific root view type.
8050#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
8051pub struct AnyWindowHandle {
8052    pub(crate) id: WindowId,
8053    state_type: TypeId,
8054    root_entity_type_name: &'static str,
8055}
8056
8057impl AnyWindowHandle {
8058    /// Get the ID of this window.
8059    pub fn window_id(&self) -> WindowId {
8060        self.id
8061    }
8062
8063    /// Returns the name of the window's declared root entity type.
8064    pub fn root_entity_type_name(&self) -> &'static str {
8065        self.root_entity_type_name
8066    }
8067
8068    /// Attempt to convert this handle to a window handle with a specific root view type.
8069    /// If the types do not match, this will return `None`.
8070    pub fn downcast<T: 'static>(&self) -> Option<WindowHandle<T>> {
8071        if TypeId::of::<T>() == self.state_type {
8072            Some(WindowHandle {
8073                any_handle: *self,
8074                state_type: PhantomData,
8075            })
8076        } else {
8077            None
8078        }
8079    }
8080
8081    /// Updates the state of the root view of this window.
8082    ///
8083    /// This will fail if the window has been closed.
8084    pub fn update<C, R>(
8085        self,
8086        cx: &mut C,
8087        update: impl FnOnce(AnyView, &mut Window, &mut App) -> R,
8088    ) -> Result<R>
8089    where
8090        C: AppContext,
8091    {
8092        cx.update_window(self, update)
8093    }
8094
8095    /// Read the state of the root view of this window.
8096    ///
8097    /// This will fail if the window has been closed.
8098    pub fn read<T, C, R>(self, cx: &C, read: impl FnOnce(Entity<T>, &App) -> R) -> Result<R>
8099    where
8100        C: AppContext,
8101        T: 'static,
8102    {
8103        let view = self
8104            .downcast::<T>()
8105            .context("the type of the window's root view has changed")?;
8106
8107        cx.read_window(&view, read)
8108    }
8109}
8110
8111impl HasWindowHandle for Window {
8112    fn window_handle(&self) -> Result<raw_window_handle::WindowHandle<'_>, HandleError> {
8113        self.platform_window.window_handle()
8114    }
8115}
8116
8117impl HasDisplayHandle for Window {
8118    fn display_handle(
8119        &self,
8120    ) -> std::result::Result<raw_window_handle::DisplayHandle<'_>, HandleError> {
8121        self.platform_window.display_handle()
8122    }
8123}
8124
8125/// An identifier for an [`Element`].
8126///
8127/// Can be constructed with a string, a number, or both, as well
8128/// as other internal representations.
8129#[derive(Clone, Debug, Eq, PartialEq, Hash)]
8130pub enum ElementId {
8131    /// The ID of a View element
8132    View(EntityId),
8133    /// An integer ID.
8134    Integer(u64),
8135    /// A string based ID.
8136    Name(SharedString),
8137    /// A UUID.
8138    Uuid(Uuid),
8139    /// An ID that's equated with a focus handle.
8140    FocusHandle(FocusId),
8141    /// A combination of a name and an integer.
8142    NamedInteger(SharedString, u64),
8143    /// A path.
8144    Path(Arc<std::path::Path>),
8145    /// A code location.
8146    CodeLocation(core::panic::Location<'static>),
8147    /// A labeled child of an element.
8148    NamedChild(Arc<ElementId>, SharedString),
8149    /// A byte array ID (used for text-anchors)
8150    OpaqueId([u8; 20]),
8151}
8152
8153impl ElementId {
8154    /// Constructs an `ElementId::NamedInteger` from a name and `usize`.
8155    pub fn named_usize(name: impl Into<SharedString>, integer: usize) -> ElementId {
8156        Self::NamedInteger(name.into(), integer as u64)
8157    }
8158}
8159
8160impl Display for ElementId {
8161    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
8162        match self {
8163            ElementId::View(entity_id) => write!(f, "view-{}", entity_id)?,
8164            ElementId::Integer(ix) => write!(f, "{}", ix)?,
8165            ElementId::Name(name) => write!(f, "{}", name)?,
8166            ElementId::FocusHandle(_) => write!(f, "FocusHandle")?,
8167            ElementId::NamedInteger(s, i) => write!(f, "{}-{}", s, i)?,
8168            ElementId::Uuid(uuid) => write!(f, "{}", uuid)?,
8169            ElementId::Path(path) => write!(f, "{}", path.display())?,
8170            ElementId::CodeLocation(location) => write!(f, "{}", location)?,
8171            ElementId::NamedChild(id, name) => write!(f, "{}-{}", id, name)?,
8172            ElementId::OpaqueId(opaque_id) => write!(f, "{:x?}", opaque_id)?,
8173        }
8174
8175        Ok(())
8176    }
8177}
8178
8179impl TryInto<SharedString> for ElementId {
8180    type Error = anyhow::Error;
8181
8182    fn try_into(self) -> anyhow::Result<SharedString> {
8183        if let ElementId::Name(name) = self {
8184            Ok(name)
8185        } else {
8186            anyhow::bail!("element id is not string")
8187        }
8188    }
8189}
8190
8191impl From<u64> for ElementId {
8192    fn from(id: u64) -> Self {
8193        ElementId::Integer(id)
8194    }
8195}
8196
8197impl From<usize> for ElementId {
8198    fn from(id: usize) -> Self {
8199        ElementId::Integer(id as u64)
8200    }
8201}
8202
8203impl From<i32> for ElementId {
8204    fn from(id: i32) -> Self {
8205        Self::Integer(id as u64)
8206    }
8207}
8208
8209impl From<SharedString> for ElementId {
8210    fn from(name: SharedString) -> Self {
8211        ElementId::Name(name)
8212    }
8213}
8214
8215impl From<String> for ElementId {
8216    fn from(name: String) -> Self {
8217        ElementId::Name(name.into())
8218    }
8219}
8220
8221impl From<Arc<str>> for ElementId {
8222    fn from(name: Arc<str>) -> Self {
8223        ElementId::Name(name.into())
8224    }
8225}
8226
8227impl From<Arc<std::path::Path>> for ElementId {
8228    fn from(path: Arc<std::path::Path>) -> Self {
8229        ElementId::Path(path)
8230    }
8231}
8232
8233impl From<&'static str> for ElementId {
8234    fn from(name: &'static str) -> Self {
8235        ElementId::Name(SharedString::new_static(name))
8236    }
8237}
8238
8239impl<'a> From<&'a FocusHandle> for ElementId {
8240    fn from(handle: &'a FocusHandle) -> Self {
8241        ElementId::FocusHandle(handle.id)
8242    }
8243}
8244
8245impl From<(&'static str, EntityId)> for ElementId {
8246    fn from((name, id): (&'static str, EntityId)) -> Self {
8247        ElementId::NamedInteger(SharedString::new_static(name), id.as_u64())
8248    }
8249}
8250
8251impl From<(&'static str, usize)> for ElementId {
8252    fn from((name, id): (&'static str, usize)) -> Self {
8253        ElementId::NamedInteger(SharedString::new_static(name), id as u64)
8254    }
8255}
8256
8257impl From<(SharedString, usize)> for ElementId {
8258    fn from((name, id): (SharedString, usize)) -> Self {
8259        ElementId::NamedInteger(name, id as u64)
8260    }
8261}
8262
8263impl From<(&'static str, u64)> for ElementId {
8264    fn from((name, id): (&'static str, u64)) -> Self {
8265        ElementId::NamedInteger(SharedString::new_static(name), id)
8266    }
8267}
8268
8269impl From<Uuid> for ElementId {
8270    fn from(value: Uuid) -> Self {
8271        Self::Uuid(value)
8272    }
8273}
8274
8275impl From<(&'static str, u32)> for ElementId {
8276    fn from((name, id): (&'static str, u32)) -> Self {
8277        ElementId::NamedInteger(SharedString::new_static(name), u64::from(id))
8278    }
8279}
8280
8281impl<T: Into<SharedString>> From<(ElementId, T)> for ElementId {
8282    fn from((id, name): (ElementId, T)) -> Self {
8283        ElementId::NamedChild(Arc::new(id), name.into())
8284    }
8285}
8286
8287impl From<&'static core::panic::Location<'static>> for ElementId {
8288    fn from(location: &'static core::panic::Location<'static>) -> Self {
8289        ElementId::CodeLocation(*location)
8290    }
8291}
8292
8293impl From<[u8; 20]> for ElementId {
8294    fn from(opaque_id: [u8; 20]) -> Self {
8295        ElementId::OpaqueId(opaque_id)
8296    }
8297}
8298
8299/// A rectangle to be rendered in the window at the given position and size.
8300/// Passed as an argument [`Window::paint_quad`].
8301#[derive(Clone)]
8302pub struct PaintQuad {
8303    /// The bounds of the quad within the window.
8304    pub bounds: Bounds<Pixels>,
8305    /// The radii of the quad's corners.
8306    pub corner_radii: Corners<Pixels>,
8307    /// The background color of the quad.
8308    pub background: Background,
8309    /// The widths of the quad's borders.
8310    pub border_widths: Edges<Pixels>,
8311    /// The color of the quad's borders.
8312    pub border_color: Hsla,
8313    /// The style of the quad's borders.
8314    pub border_style: BorderStyle,
8315}
8316
8317impl PaintQuad {
8318    /// Sets the corner radii of the quad.
8319    pub fn corner_radii(self, corner_radii: impl Into<Corners<Pixels>>) -> Self {
8320        PaintQuad {
8321            corner_radii: corner_radii.into(),
8322            ..self
8323        }
8324    }
8325
8326    /// Sets the border widths of the quad.
8327    pub fn border_widths(self, border_widths: impl Into<Edges<Pixels>>) -> Self {
8328        PaintQuad {
8329            border_widths: border_widths.into(),
8330            ..self
8331        }
8332    }
8333
8334    /// Sets the border color of the quad.
8335    pub fn border_color(self, border_color: impl Into<Hsla>) -> Self {
8336        PaintQuad {
8337            border_color: border_color.into(),
8338            ..self
8339        }
8340    }
8341
8342    /// Sets the background color of the quad.
8343    pub fn background(self, background: impl Into<Background>) -> Self {
8344        PaintQuad {
8345            background: background.into(),
8346            ..self
8347        }
8348    }
8349}
8350
8351/// Creates a quad with the given parameters.
8352pub fn quad(
8353    bounds: Bounds<Pixels>,
8354    corner_radii: impl Into<Corners<Pixels>>,
8355    background: impl Into<Background>,
8356    border_widths: impl Into<Edges<Pixels>>,
8357    border_color: impl Into<Hsla>,
8358    border_style: BorderStyle,
8359) -> PaintQuad {
8360    PaintQuad {
8361        bounds,
8362        corner_radii: corner_radii.into(),
8363        background: background.into(),
8364        border_widths: border_widths.into(),
8365        border_color: border_color.into(),
8366        border_style,
8367    }
8368}
8369
8370/// Creates a filled quad with the given bounds and background color.
8371pub fn fill(bounds: impl Into<Bounds<Pixels>>, background: impl Into<Background>) -> PaintQuad {
8372    PaintQuad {
8373        bounds: bounds.into(),
8374        corner_radii: (0.).into(),
8375        background: background.into(),
8376        border_widths: (0.).into(),
8377        border_color: transparent_black(),
8378        border_style: BorderStyle::default(),
8379    }
8380}
8381
8382/// Creates a rectangle outline with the given bounds, border color, and a 1px border width
8383pub fn outline(
8384    bounds: impl Into<Bounds<Pixels>>,
8385    border_color: impl Into<Hsla>,
8386    border_style: BorderStyle,
8387) -> PaintQuad {
8388    PaintQuad {
8389        bounds: bounds.into(),
8390        corner_radii: (0.).into(),
8391        background: transparent_black().into(),
8392        border_widths: (1.).into(),
8393        border_color: border_color.into(),
8394        border_style,
8395    }
8396}
8397
8398#[inline(never)]
8399fn with_element_arena_erased(callback: &mut dyn FnMut(&mut Arena)) -> Result<(), AccessError> {
8400    if let Some(arena_pointer) = CURRENT_ELEMENT_ARENA.try_with(Cell::get)? {
8401        // SAFETY: The pointer is valid for the duration of the draw operation
8402        // that set it, and we're being called during that same draw.
8403        let arena_cell = unsafe { &*arena_pointer };
8404        callback(&mut arena_cell.borrow_mut());
8405        Ok(())
8406    } else {
8407        ELEMENT_ARENA.try_with(|arena| callback(&mut arena.borrow_mut()))
8408    }
8409}
8410
8411#[cfg(test)]
8412mod tests {
8413    use std::{
8414        cell::{Cell, RefCell},
8415        path::PathBuf,
8416        rc::Rc,
8417        time::Duration,
8418    };
8419
8420    use crate::{
8421        AnyWindowHandle, AppContext as _, BackGestureEvent, BackGesturePhase, Bounds, ContentMask,
8422        Context, DispatchPhase, DragMoveEvent, Empty, ExternalDragPayload, ExternalPaths,
8423        FileDragPaths, FileDropEvent, FocusHandle, InputEvent as _, InteractiveElement as _,
8424        IntoElement, KeyDownEvent, Keystroke, LongPressEvent, MouseButton, MouseDownEvent,
8425        MouseMoveEvent, ParentElement, Pixels, PlatformInput, Point, Render, RequestFrameOptions,
8426        ScaledPixels, StatefulInteractiveElement as _, Styled, TestAppContext, ThermalState,
8427        TouchDragEvent, TouchEvent, TouchId, TouchPhase, Underline, UnderlineStyle, Window,
8428        WindowAppearance, WindowOptions, canvas, div, hsla, point, px, size,
8429    };
8430
8431    #[gpui::test]
8432    fn test_cover_bounds_preserves_empty_fractional_clips(cx: &mut TestAppContext) {
8433        let window = cx.add_window(|_, _| EmptyView);
8434        window
8435            .update(cx, |_, window, _| {
8436                for scale in [1., 1.25, 2.] {
8437                    window.scale_factor = scale;
8438                    let tile = Bounds::new(point(px(10.), px(10.)), size(px(20.), px(20.)));
8439                    let glyph = Bounds::new(point(px(40.25), px(15.25)), size(px(4.), px(4.)));
8440                    for clip in [
8441                        tile.intersect(&glyph),
8442                        Bounds::new(point(px(40.25), px(15.25)), size(px(0.), px(4.))),
8443                        Bounds::new(point(px(15.25), px(40.25)), size(px(4.), px(0.))),
8444                    ] {
8445                        assert!(clip.is_empty());
8446                        assert!(window.cover_bounds(clip).is_empty());
8447                    }
8448                    let visible = Bounds::new(point(px(15.25), px(15.25)), size(px(0.1), px(0.1)));
8449                    assert!(!window.cover_bounds(visible).is_empty());
8450                }
8451            })
8452            .unwrap();
8453    }
8454
8455    #[gpui::test]
8456    async fn test_focus_handle_release(cx: &mut TestAppContext) {
8457        let (handle, survivor) = cx.update(|cx| (cx.focus_handle(), cx.focus_handle()));
8458        let handle_id = handle.id;
8459        let weak_handle = handle.downgrade();
8460        let retained = handle.clone();
8461        drop(handle);
8462
8463        cx.update(|_| {});
8464        cx.read(|cx| {
8465            let handles = cx.focus_handles.read();
8466            assert_eq!(handles.handles.len(), 2);
8467            assert!(handles.dropped_handles.is_empty());
8468        });
8469        assert_eq!(weak_handle.upgrade().as_ref(), Some(&retained));
8470
8471        cx.background_spawn(async move { drop(retained) }).await;
8472        assert_eq!(weak_handle.upgrade(), None);
8473        cx.read(|cx| {
8474            assert_eq!(cx.focus_handles.read().dropped_handles, [handle_id]);
8475        });
8476        cx.update(|_| {});
8477        cx.read(|cx| {
8478            let handles = cx.focus_handles.read();
8479            assert_eq!(handles.handles.keys().collect::<Vec<_>>(), [survivor.id]);
8480            assert!(handles.dropped_handles.is_empty());
8481        });
8482
8483        let replacements = cx.update(|cx| [cx.focus_handle(), cx.focus_handle()]);
8484        assert_eq!(weak_handle.upgrade(), None);
8485        cx.update(|cx| {
8486            drop(replacements);
8487            cx.defer(move |_| drop(survivor));
8488        });
8489        cx.read(|cx| {
8490            let handles = cx.focus_handles.read();
8491            assert_eq!(handles.handles.len(), 0);
8492            assert!(handles.dropped_handles.is_empty());
8493        });
8494    }
8495
8496    #[gpui::test]
8497    fn test_dropped_focus_handle_blurs_only_its_windows(cx: &mut TestAppContext) {
8498        let windows = [
8499            cx.add_window(|_, _| EmptyView),
8500            cx.add_window(|_, _| EmptyView),
8501            cx.add_window(|_, _| EmptyView),
8502            cx.add_window(|_, _| EmptyView),
8503            cx.add_window(|_, _| EmptyView),
8504        ];
8505        let (handle, other_handle, survivor) =
8506            cx.update(|cx| (cx.focus_handle(), cx.focus_handle(), cx.focus_handle()));
8507        for window in &windows[..2] {
8508            window
8509                .update(cx, |_, window, cx| window.focus(&handle, cx))
8510                .expect("window exists");
8511        }
8512        windows[2]
8513            .update(cx, |_, window, cx| window.focus(&other_handle, cx))
8514            .expect("window exists");
8515        windows[3]
8516            .update(cx, |_, window, cx| window.focus(&survivor, cx))
8517            .expect("window exists");
8518
8519        cx.update(|cx| {
8520            for _ in 0..1_000 {
8521                drop(cx.focus_handle());
8522            }
8523            drop((handle, other_handle));
8524        });
8525        for window in &windows[..3] {
8526            window
8527                .update(cx, |_, window, _| assert_eq!(window.focus, None))
8528                .expect("window exists");
8529        }
8530        windows[3]
8531            .update(cx, |_, window, cx| {
8532                assert_eq!(window.focused(cx).as_ref(), Some(&survivor));
8533                assert_eq!(window.focus_generation, 1);
8534            })
8535            .expect("window exists");
8536        windows[4]
8537            .update(cx, |_, window, _| {
8538                assert_eq!(window.focus, None);
8539                assert_eq!(window.focus_generation, 0);
8540            })
8541            .expect("window exists");
8542    }
8543
8544    #[gpui::test]
8545    fn test_native_close_defers_app_access(cx: &mut TestAppContext) {
8546        let window = cx.add_window(|_, _| EmptyView);
8547        let platform_window = cx.test_window(window.into());
8548        {
8549            let app = cx.app.borrow_mut();
8550            platform_window.simulate_close();
8551            assert!(app.windows.contains_key(window.window_id()));
8552        }
8553        cx.run_until_parked();
8554        assert!(!cx.app.borrow().windows.contains_key(window.window_id()));
8555    }
8556
8557    #[cfg(feature = "profiler")]
8558    #[gpui::test]
8559    fn test_frame_requests_and_skips_are_journaled(cx: &mut TestAppContext) {
8560        use crate::FrameRequestSource;
8561        use crate::profiler::journal::{
8562            self, ForegroundJournalEntry, FrameSkipReason, IntervalBoundary,
8563        };
8564        use scheduler::Instant;
8565
8566        cx.app.borrow_mut().mode = crate::app::GpuiMode::Production;
8567        let window = cx.add_window(|_, _| EmptyView);
8568        let platform_window = cx.test_window(window.into());
8569        platform_window.simulate_frame_request(RequestFrameOptions::default());
8570        let (journal, _guard) = journal::install_test_foreground_journal(64, 4);
8571        let mut collector = journal.collector();
8572
8573        for (signal_at, source) in [
8574            (Some(Instant::now()), FrameRequestSource::NativeCallback),
8575            (Some(Instant::now()), FrameRequestSource::LocalSchedule),
8576            (None, FrameRequestSource::NativeCallback),
8577        ] {
8578            platform_window.simulate_frame_request(RequestFrameOptions {
8579                signal_at,
8580                signal_source: source,
8581                require_presentation: true,
8582                ..Default::default()
8583            });
8584            let entries = collector.collect_unseen().entries;
8585            let signal_index = entries
8586                .iter()
8587                .position(|entry| {
8588                    matches!(
8589                        entry,
8590                        ForegroundJournalEntry::PlatformSignal(signal)
8591                            if signal.window_id == window.window_id()
8592                                && signal.signal_at == signal_at
8593                                && signal.source == source
8594                                && signal_at.is_none_or(|at| signal.handled_at >= at)
8595                    )
8596                })
8597                .expect("frame request metadata");
8598            let skip_index = entries
8599                .iter()
8600                .position(|entry| {
8601                    matches!(
8602                        entry,
8603                        ForegroundJournalEntry::Boundary(IntervalBoundary::FrameSkipped(skipped))
8604                            if skipped.window_id == window.window_id()
8605                                && skipped.reason == FrameSkipReason::NoRenderNeeded
8606                    )
8607                })
8608                .expect("completed no-render boundary");
8609            assert!(signal_index < skip_index);
8610        }
8611    }
8612
8613    #[cfg(feature = "profiler")]
8614    #[gpui::test]
8615    fn test_frame_demand_survives_throttling(cx: &mut TestAppContext) {
8616        use crate::profiler::journal::{
8617            self, ForegroundJournalEntry, FrameSkipReason, IntervalBoundary,
8618        };
8619        use scheduler::Instant;
8620
8621        // Test mode draws during effect flushing, bypassing platform frame throttling.
8622        cx.app.borrow_mut().mode = crate::app::GpuiMode::Production;
8623        let (journal, _guard) = journal::install_test_foreground_journal(256, 4);
8624        let mut collector = journal.collector();
8625        for initially_dirty in [true, false] {
8626            // Keep the throttle closed without depending on short wall-clock deadlines.
8627            let window = cx
8628                .app
8629                .borrow_mut()
8630                .open_window(
8631                    WindowOptions {
8632                        inactive_frame_interval: Some(Duration::from_secs(3600)),
8633                        ..Default::default()
8634                    },
8635                    |_, cx| cx.new(|_| EmptyView),
8636                )
8637                .expect("open inactive test window");
8638            let platform_window = cx.test_window(window.into());
8639            platform_window.simulate_active_status_change(false);
8640            platform_window.simulate_frame_request(RequestFrameOptions::default());
8641            let callback_ran = Rc::new(Cell::new(false));
8642            let draws_before = window
8643                .update(cx, |_, window, _| {
8644                    let draws_before = window
8645                        .frame_duration_snapshot()
8646                        .draw_duration_histogram
8647                        .len();
8648                    if initially_dirty {
8649                        window.refresh();
8650                    }
8651                    window.on_next_frame({
8652                        let callback_ran = callback_ran.clone();
8653                        move |window, _| {
8654                            callback_ran.set(true);
8655                            window.refresh();
8656                        }
8657                    });
8658                    draws_before
8659                })
8660                .expect("schedule throttled frame");
8661            // Skips only seal retained work, so give the throttled skip some.
8662            let input_at = Instant::now();
8663            journal::record_input(journal::InputTiming {
8664                kind: "test",
8665                start: input_at,
8666                end: input_at,
8667                caused_invalidation: false,
8668            });
8669            collector.collect_unseen();
8670            platform_window.simulate_frame_request(RequestFrameOptions {
8671                signal_at: Some(Instant::now()),
8672                ..Default::default()
8673            });
8674            window
8675                .update(cx, |_, window, _| {
8676                    assert_eq!(
8677                        window
8678                            .frame_duration_snapshot()
8679                            .draw_duration_histogram
8680                            .len(),
8681                        draws_before,
8682                    );
8683                })
8684                .expect("inspect deferred frame");
8685            assert!(!callback_ran.get());
8686            assert!(collector.collect_unseen().entries.iter().any(|entry| {
8687                matches!(
8688                    entry,
8689                    ForegroundJournalEntry::Boundary(IntervalBoundary::FrameSkipped(skipped))
8690                        if skipped.window_id == window.window_id()
8691                            && skipped.reason == FrameSkipReason::InactiveFrameRateLimit
8692                )
8693            }));
8694            platform_window.simulate_frame_request(RequestFrameOptions {
8695                signal_at: Some(Instant::now()),
8696                require_presentation: true,
8697                ..Default::default()
8698            });
8699            window
8700                .update(cx, |_, window, _| {
8701                    assert_eq!(
8702                        window
8703                            .frame_duration_snapshot()
8704                            .draw_duration_histogram
8705                            .len(),
8706                        draws_before + 1,
8707                    );
8708                })
8709                .expect("inspect presented frame");
8710            assert!(callback_ran.get());
8711        }
8712    }
8713
8714    /// The inactive-window throttle applies only to frames with pending
8715    /// `on_next_frame` callbacks or a forced render. A redraw requested with
8716    /// `cx.notify()` alone renders on the next frame request (#211).
8717    #[cfg(feature = "profiler")]
8718    #[gpui::test]
8719    fn test_notify_redraw_bypasses_inactive_throttle(cx: &mut TestAppContext) {
8720        // Test mode draws during effect flushing, bypassing platform frame throttling.
8721        cx.app.borrow_mut().mode = crate::app::GpuiMode::Production;
8722        let window = cx
8723            .app
8724            .borrow_mut()
8725            .open_window(
8726                WindowOptions {
8727                    inactive_frame_interval: Some(Duration::from_secs(3600)),
8728                    ..Default::default()
8729                },
8730                |_, cx| cx.new(|_| EmptyView),
8731            )
8732            .expect("open inactive test window");
8733        let platform_window = cx.test_window(window.into());
8734        platform_window.simulate_active_status_change(false);
8735        // Records the last frame time, so a throttled request would now wait an hour.
8736        platform_window.simulate_frame_request(RequestFrameOptions::default());
8737        let draws = |cx: &mut TestAppContext| {
8738            window
8739                .update(cx, |_, window, _| {
8740                    window
8741                        .frame_duration_snapshot()
8742                        .draw_duration_histogram
8743                        .len()
8744                })
8745                .expect("read draw count")
8746        };
8747        for _ in 0..3 {
8748            let before = draws(cx);
8749            window
8750                .update(cx, |_, _, cx| cx.notify())
8751                .expect("notify root view");
8752            platform_window.simulate_frame_request(RequestFrameOptions::default());
8753            assert_eq!(draws(cx), before + 1, "notify redraw was throttled");
8754        }
8755    }
8756
8757    /// Visibility transitions reach observers exactly once each, with the new
8758    /// state already stored on the window, and never wake the platform for a
8759    /// frame: the platform requests one itself when it resumes presenting.
8760    #[gpui::test]
8761    fn test_window_visibility(cx: &mut TestAppContext) {
8762        use crate::WindowVisibility;
8763
8764        let window = cx.add_window(|_, _| EmptyView);
8765        let observed = Rc::new(RefCell::new(Vec::new()));
8766        let _subscription = window
8767            .update(cx, {
8768                let observed = observed.clone();
8769                move |_, window, _| {
8770                    assert_eq!(window.visibility(), WindowVisibility::Visible);
8771                    assert!(window.is_visible());
8772                    window.observe_window_visibility(move |visibility, window, _| {
8773                        assert_eq!(window.visibility(), visibility);
8774                        observed.borrow_mut().push(visibility);
8775                    })
8776                }
8777            })
8778            .unwrap();
8779        let test_window = cx.test_window(window.into());
8780        let frame_wake_count = test_window.frame_wake_count();
8781
8782        test_window.simulate_visibility_change(WindowVisibility::Hidden);
8783        assert_eq!(*observed.borrow(), [WindowVisibility::Hidden]);
8784        window
8785            .update(cx, |_, window, _| assert!(!window.is_visible()))
8786            .unwrap();
8787
8788        // Platforms may report the same state again; observers only see changes.
8789        test_window.simulate_visibility_change(WindowVisibility::Hidden);
8790        assert_eq!(observed.borrow().len(), 1);
8791
8792        test_window.simulate_visibility_change(WindowVisibility::Visible);
8793        assert_eq!(
8794            *observed.borrow(),
8795            [WindowVisibility::Hidden, WindowVisibility::Visible]
8796        );
8797        window
8798            .update(cx, |_, window, _| assert!(window.is_visible()))
8799            .unwrap();
8800        assert_eq!(test_window.frame_wake_count(), frame_wake_count);
8801    }
8802
8803    /// App learns display state from the platform's display notifications,
8804    /// and a window from the platform's report of which display it is on.
8805    #[gpui::test]
8806    fn test_display_tracking(cx: &mut TestAppContext) {
8807        use crate::{DisplayChanges, DisplayEvent, DisplayId, Subscription};
8808
8809        let sixty_hertz = Duration::from_secs(1) / 60;
8810        let one_hundred_twenty_hertz = Duration::from_secs(1) / 120;
8811        let one_hundred_forty_four_hertz = Duration::from_secs(1) / 144;
8812
8813        let display_events = Rc::new(RefCell::new(Vec::new()));
8814        let _display_subscription = cx.update({
8815            let display_events = display_events.clone();
8816            move |cx| cx.observe_displays(move |event, _| display_events.borrow_mut().push(event))
8817        });
8818
8819        let window = cx.add_window(|window, cx| DisplayTracker {
8820            refresh_intervals: Vec::new(),
8821            _subscription: cx.observe_window_display(
8822                window,
8823                |tracker: &mut DisplayTracker, window, cx| {
8824                    tracker.refresh_intervals.push(window.refresh_interval(cx));
8825                },
8826            ),
8827        });
8828        let window_notifications = Rc::new(RefCell::new(Vec::new()));
8829        let _window_subscription = window
8830            .update(cx, {
8831                let window_notifications = window_notifications.clone();
8832                move |_, window, cx| {
8833                    assert_eq!(window.refresh_interval(cx), Some(sixty_hertz));
8834                    window.observe_window_display(move |window, cx| {
8835                        window_notifications
8836                            .borrow_mut()
8837                            .push((window.display_id, window.refresh_interval(cx)));
8838                    })
8839                }
8840            })
8841            .unwrap();
8842        let test_window = cx.test_window(window.into());
8843
8844        // The window may hear that it moved before App hears the display was
8845        // connected. App learns about the display before the window's
8846        // observers run, and the platform's later notification changes
8847        // nothing.
8848        cx.test_platform()
8849            .connect_display(DisplayId(2), Some(one_hundred_twenty_hertz));
8850        test_window.simulate_move_to_display(DisplayId(2));
8851        assert_eq!(
8852            window_notifications.take(),
8853            [(Some(DisplayId(2)), Some(one_hundred_twenty_hertz))]
8854        );
8855        assert_eq!(display_events.take(), [DisplayEvent::Added(DisplayId(2))]);
8856        cx.simulate_display_refresh_interval_change(DisplayId(2), Some(one_hundred_twenty_hertz));
8857        assert!(window_notifications.borrow().is_empty());
8858
8859        // Platforms may report a move that isn't one.
8860        test_window.simulate_move_to_display(DisplayId(2));
8861        assert!(window_notifications.borrow().is_empty());
8862
8863        cx.simulate_display_refresh_interval_change(
8864            DisplayId(2),
8865            Some(one_hundred_forty_four_hertz),
8866        );
8867        assert_eq!(
8868            window_notifications.take(),
8869            [(Some(DisplayId(2)), Some(one_hundred_forty_four_hertz))]
8870        );
8871
8872        // Changes to a display the window isn't on don't notify it.
8873        cx.simulate_display_refresh_interval_change(DisplayId(1), Some(one_hundred_twenty_hertz));
8874        cx.simulate_display_removed(DisplayId(1));
8875        assert!(window_notifications.borrow().is_empty());
8876
8877        assert_eq!(
8878            display_events.take(),
8879            [
8880                DisplayEvent::Changed {
8881                    id: DisplayId(2),
8882                    changes: DisplayChanges::REFRESH_INTERVAL,
8883                },
8884                DisplayEvent::Changed {
8885                    id: DisplayId(1),
8886                    changes: DisplayChanges::REFRESH_INTERVAL,
8887                },
8888                DisplayEvent::Removed(DisplayId(1)),
8889            ]
8890        );
8891        window
8892            .update(cx, |tracker, _, _| {
8893                assert_eq!(
8894                    tracker.refresh_intervals,
8895                    [
8896                        Some(one_hundred_twenty_hertz),
8897                        Some(one_hundred_forty_four_hertz)
8898                    ]
8899                );
8900            })
8901            .unwrap();
8902
8903        struct DisplayTracker {
8904            refresh_intervals: Vec<Option<Duration>>,
8905            _subscription: Subscription,
8906        }
8907
8908        impl Render for DisplayTracker {
8909            fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
8910                Empty
8911            }
8912        }
8913    }
8914
8915    #[gpui::test]
8916    fn test_fully_visible_bounds_preserve_layout_viewport(cx: &mut TestAppContext) {
8917        let window = cx.add_window(|_, _| EmptyView);
8918        let mut platform_window = cx.test_window(window.into());
8919        platform_window.simulate_resize(size(px(400.), px(800.)));
8920        window
8921            .update(cx, |_, window, _| {
8922                assert_eq!(
8923                    window.visual_viewport_bounds(),
8924                    Bounds::new(Point::default(), size(px(400.), px(800.)))
8925                );
8926                assert_eq!(
8927                    window.fully_visible_bounds(),
8928                    window.visual_viewport_bounds()
8929                );
8930            })
8931            .unwrap();
8932
8933        platform_window.simulate_frame_request(RequestFrameOptions::default());
8934        let wakes = platform_window.frame_wake_count();
8935        let visual_bounds = Bounds::new(point(px(10.), px(40.)), size(px(380.), px(460.)));
8936        platform_window.simulate_visual_viewport_change(visual_bounds);
8937        assert!(platform_window.frame_wake_count() > wakes);
8938        platform_window.simulate_frame_request(RequestFrameOptions::default());
8939        let wakes = platform_window.frame_wake_count();
8940        let insets = crate::WindowInsets {
8941            safe_area: crate::Edges {
8942                top: px(60.),
8943                right: px(20.),
8944                bottom: px(30.),
8945                left: px(-10.),
8946            },
8947            ime: crate::Edges {
8948                bottom: px(350.),
8949                ..Default::default()
8950            },
8951            ..Default::default()
8952        };
8953        platform_window.simulate_insets_change(insets.clone());
8954        assert!(platform_window.frame_wake_count() > wakes);
8955        window
8956            .update(cx, |_, window, cx| {
8957                let focus = cx.focus_handle();
8958                window.focus(&focus, cx);
8959                assert_eq!(window.insets(), insets);
8960                assert_eq!(window.viewport_size(), size(px(400.), px(800.)));
8961                assert_eq!(window.visual_viewport_bounds(), visual_bounds);
8962                assert_eq!(
8963                    window.fully_visible_bounds(),
8964                    Bounds::new(point(px(10.), px(60.)), size(px(370.), px(390.)))
8965                );
8966                window.request_virtual_keyboard();
8967                window.dismiss_virtual_keyboard();
8968                assert!(focus.is_focused(window));
8969                assert_eq!(window.viewport_size(), size(px(400.), px(800.)));
8970            })
8971            .unwrap();
8972        assert_eq!(platform_window.virtual_keyboard_requests(), 1);
8973        assert_eq!(platform_window.virtual_keyboard_dismissals(), 1);
8974
8975        platform_window.simulate_insets_change(crate::WindowInsets {
8976            safe_area: crate::Edges {
8977                top: px(900.),
8978                left: px(500.),
8979                ..Default::default()
8980            },
8981            ..Default::default()
8982        });
8983        window
8984            .update(cx, |_, window, _| {
8985                assert_eq!(
8986                    window.fully_visible_bounds().size,
8987                    size(Pixels::ZERO, Pixels::ZERO)
8988                );
8989            })
8990            .unwrap();
8991
8992        // Some backends update geometry snapshots without delivering inset callbacks.
8993        use crate::PlatformWindow as _;
8994        platform_window.on_insets_changed(Box::new(|_| {}));
8995        platform_window.simulate_insets_change(crate::WindowInsets::default());
8996        window
8997            .update(cx, |_, window, _| {
8998                assert_eq!(window.insets(), crate::WindowInsets::default());
8999            })
9000            .unwrap();
9001    }
9002
9003    #[test]
9004    fn frame_throttle_accepts_display_link_rounding() {
9005        assert!(!super::frame_request_arrived_too_early(
9006            Duration::from_micros(16_666),
9007            super::SIXTY_FPS_INTERVAL,
9008        ));
9009        assert!(!super::frame_request_arrived_too_early(
9010            Duration::from_micros(33_332),
9011            super::THIRTY_FPS_INTERVAL,
9012        ));
9013    }
9014
9015    #[test]
9016    fn frame_throttle_rejects_an_extra_display_refresh() {
9017        assert!(super::frame_request_arrived_too_early(
9018            Duration::from_micros(8_333),
9019            super::SIXTY_FPS_INTERVAL,
9020        ));
9021        assert!(super::frame_request_arrived_too_early(
9022            Duration::from_micros(16_666),
9023            super::THIRTY_FPS_INTERVAL,
9024        ));
9025    }
9026
9027    #[test]
9028    fn power_modes_preserve_frame_limits() {
9029        for (power_mode, active_interval, thermal_interval) in [
9030            (
9031                crate::PowerMode::LowPower,
9032                Some(super::THIRTY_FPS_INTERVAL),
9033                super::THIRTY_FPS_INTERVAL,
9034            ),
9035            (crate::PowerMode::Unknown, None, super::SIXTY_FPS_INTERVAL),
9036            (crate::PowerMode::Balanced, None, super::SIXTY_FPS_INTERVAL),
9037            (crate::PowerMode::HighPower, None, super::SIXTY_FPS_INTERVAL),
9038        ] {
9039            assert_eq!(
9040                super::minimum_frame_interval(true, false, None, ThermalState::Nominal, power_mode),
9041                active_interval,
9042            );
9043            assert_eq!(
9044                super::minimum_frame_interval(true, false, None, ThermalState::Serious, power_mode),
9045                Some(thermal_interval),
9046            );
9047            let inactive_interval = Duration::from_millis(100);
9048            assert_eq!(
9049                super::minimum_frame_interval(
9050                    true,
9051                    true,
9052                    Some(inactive_interval),
9053                    ThermalState::Nominal,
9054                    power_mode,
9055                ),
9056                Some(inactive_interval),
9057            );
9058        }
9059    }
9060
9061    struct EmptyView;
9062
9063    impl Render for EmptyView {
9064        fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
9065            div()
9066        }
9067    }
9068
9069    struct OpensWindowOnPaint {
9070        opened: Rc<Cell<bool>>,
9071    }
9072
9073    impl Render for OpensWindowOnPaint {
9074        fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
9075            let opened = self.opened.clone();
9076            div()
9077                .size_full()
9078                .child(canvas(
9079                    |_, _, _| {},
9080                    move |_, _, _window, cx| {
9081                        if !opened.replace(true) {
9082                            cx.open_window(WindowOptions::default(), |_, cx| cx.new(|_| EmptyView))
9083                                .unwrap();
9084                        }
9085                    },
9086                ))
9087                // Siblings painted after the canvas: their elements were
9088                // allocated in the arena before the nested draw, so they detect
9089                // a mid-draw arena clear when painted afterwards.
9090                .child(div().child("after"))
9091        }
9092    }
9093
9094    /// Opening a window synchronously draws it and requests an element arena
9095    /// clear. When that happens from within another window's draw (here: from
9096    /// an element's paint), the clear must be deferred until the outer draw
9097    /// finishes, or the outer draw's arena-allocated elements would be freed
9098    /// out from under it.
9099    #[test]
9100    fn test_window_opened_during_draw_defers_arena_clear() {
9101        let mut cx = TestAppContext::single();
9102
9103        let opened = Rc::new(Cell::new(false));
9104        // add_window draws once, which runs the nested open_window mid-draw.
9105        let window = cx.add_window({
9106            let opened = opened.clone();
9107            move |_, _| OpensWindowOnPaint { opened }
9108        });
9109
9110        assert!(opened.get());
9111        assert_eq!(cx.windows().len(), 2);
9112
9113        // The deferred clear must actually run once the outer draw unwinds:
9114        // subsequent draws of both windows work against a fresh arena.
9115        cx.update_window(window.into(), |_, window, cx| window.draw(cx).clear(cx))
9116            .unwrap();
9117    }
9118
9119    #[test]
9120    fn test_scale_factor_change_preserves_bounds_and_survives_resize() {
9121        let mut cx = TestAppContext::single();
9122        let window = cx.add_window(|_, _| EmptyView);
9123        let handle: AnyWindowHandle = window.into();
9124        let window_state = |cx: &mut TestAppContext| {
9125            cx.update_window(handle, |_, window, _| {
9126                (
9127                    window.scale_factor(),
9128                    window.bounds(),
9129                    window.viewport_size(),
9130                )
9131            })
9132            .unwrap()
9133        };
9134
9135        let (scale_factor, mut expected_bounds, _) = window_state(&mut cx);
9136        assert_eq!(scale_factor, 2.0);
9137
9138        for (scale_factor, resized_size) in [
9139            (1.0, size(px(800.), px(600.))),
9140            (1.25, size(px(640.), px(480.))),
9141            (2.0, size(px(1024.), px(768.))),
9142        ] {
9143            cx.simulate_window_scale_factor_change(handle, scale_factor);
9144            assert_eq!(
9145                window_state(&mut cx),
9146                (scale_factor, expected_bounds, expected_bounds.size)
9147            );
9148
9149            cx.simulate_window_resize(handle, resized_size);
9150            expected_bounds.size = resized_size;
9151            assert_eq!(
9152                window_state(&mut cx),
9153                (scale_factor, expected_bounds, resized_size)
9154            );
9155        }
9156    }
9157
9158    /// Platforms that stop requesting frames for idle windows (currently web)
9159    /// rely on the frame waker firing whenever frame demand arises; a demand
9160    /// source that skips the waker shows up there as a window that silently
9161    /// stops repainting until unrelated activity wakes it.
9162    #[gpui::test]
9163    fn test_frame_waker_fires_on_frame_demand(cx: &mut TestAppContext) {
9164        let window = cx.add_window(|_, _| EmptyView);
9165        let test_window = cx.test_window(window.into());
9166
9167        // Windows start dirty, and that can predate waker installation;
9168        // installing the waker must deliver the pending wake or the first
9169        // frame would never be requested.
9170        assert!(
9171            test_window.frame_wake_count() >= 1,
9172            "opening a window must wake the frame source for the initial frame"
9173        );
9174
9175        // Serve outstanding demand (present the frame drawn by `add_window`).
9176        test_window.simulate_frame_request(RequestFrameOptions::default());
9177
9178        // An idle window must not wake on clean frames or plain updates, or
9179        // the frame source could never stop.
9180        let baseline = test_window.frame_wake_count();
9181        test_window.simulate_frame_request(RequestFrameOptions::default());
9182        window.update(cx, |_, _, _| {}).unwrap();
9183        assert_eq!(
9184            test_window.frame_wake_count(),
9185            baseline,
9186            "clean frames and non-notifying updates must not wake the frame source"
9187        );
9188
9189        // Notifying a view in an idle window is the core demand signal.
9190        window.update(cx, |_, _, cx| cx.notify()).unwrap();
9191        assert!(
9192            test_window.frame_wake_count() > baseline,
9193            "notifying a view in an idle window must wake the frame source"
9194        );
9195
9196        // Serving that demand returns to idle without further wakes.
9197        test_window.simulate_frame_request(RequestFrameOptions::default());
9198        let baseline = test_window.frame_wake_count();
9199        test_window.simulate_frame_request(RequestFrameOptions::default());
9200        assert_eq!(
9201            test_window.frame_wake_count(),
9202            baseline,
9203            "serving demand must return the window to idle"
9204        );
9205
9206        // Next-frame callbacks create demand without dirtying the window.
9207        window
9208            .update(cx, |_, window, _| window.on_next_frame(|_, _| {}))
9209            .unwrap();
9210        assert!(
9211            test_window.frame_wake_count() > baseline,
9212            "scheduling a next-frame callback in an idle window must wake the frame source"
9213        );
9214    }
9215
9216    /// A frame request that arrives while next-frame callbacks are pending
9217    /// must never strand them: either the frame runs them, or (when the
9218    /// inactive-window frame-rate throttle defers the frame) the waker fires
9219    /// so another request is delivered.
9220    #[gpui::test]
9221    fn test_pending_next_frame_callbacks_are_not_stranded(cx: &mut TestAppContext) {
9222        let window = cx.add_window(|_, _| EmptyView);
9223        let test_window = cx.test_window(window.into());
9224        // Establish a recent last-frame time so the inactive-window throttle
9225        // can engage on the next request.
9226        test_window.simulate_frame_request(RequestFrameOptions::default());
9227
9228        let callback_ran = Rc::new(Cell::new(false));
9229        window
9230            .update(cx, {
9231                let callback_ran = callback_ran.clone();
9232                move |_, window, _| {
9233                    window.on_next_frame(move |_, _| callback_ran.set(true));
9234                }
9235            })
9236            .unwrap();
9237
9238        let baseline = test_window.frame_wake_count();
9239        test_window.simulate_frame_request(RequestFrameOptions::default());
9240        // The test window is inactive, so this request throttles to ~30fps
9241        // when it lands within the throttle interval of the previous frame
9242        // (the common case here, but timing-dependent): the callback is
9243        // deferred and the waker must re-arm the frame source. On a slow run
9244        // the request instead lands outside the interval and runs the
9245        // callback directly.
9246        assert!(
9247            test_window.frame_wake_count() > baseline || callback_ran.get(),
9248            "a frame request with pending next-frame callbacks must either run them or re-arm the frame source"
9249        );
9250    }
9251
9252    #[gpui::test]
9253    fn color_mode_default_platform_is_compatible_and_rejects_drawing(cx: &mut TestAppContext) {
9254        let handle = cx.add_window(|_, _| EmptyView);
9255        handle
9256            .update(cx, |_, window, _| {
9257                let original = window.color_status();
9258                assert_eq!(original, crate::WindowColorStatus::default());
9259                assert_eq!(
9260                    window
9261                        .set_color_mode(crate::WindowColorMode::Default)
9262                        .unwrap(),
9263                    original
9264                );
9265                assert!(
9266                    window
9267                        .set_color_mode(crate::WindowColorMode::WideGamutSdr)
9268                        .is_err()
9269                );
9270                assert_eq!(window.color_status(), original);
9271                for phase in [
9272                    super::DrawPhase::Prepaint,
9273                    super::DrawPhase::Paint,
9274                    super::DrawPhase::Focus,
9275                ] {
9276                    window.invalidator.set_phase(phase);
9277                    assert!(
9278                        window
9279                            .set_color_mode(crate::WindowColorMode::Default)
9280                            .is_err()
9281                    );
9282                    assert_eq!(window.color_status(), original);
9283                }
9284                window.invalidator.set_phase(super::DrawPhase::None);
9285            })
9286            .unwrap();
9287    }
9288
9289    #[gpui::test]
9290    fn test_window_reports_no_raw_handle_instead_of_panicking(cx: &mut TestAppContext) {
9291        use raw_window_handle::{HandleError, HasDisplayHandle as _, HasWindowHandle as _};
9292
9293        let window = cx.add_window(|_, _| EmptyView);
9294        window
9295            .update(cx, |_, window, _| {
9296                assert!(matches!(
9297                    window.window_handle(),
9298                    Err(HandleError::NotSupported)
9299                ));
9300                assert!(matches!(
9301                    window.display_handle(),
9302                    Err(HandleError::NotSupported)
9303                ));
9304            })
9305            .unwrap();
9306    }
9307
9308    #[gpui::test]
9309    fn test_appearance_change_runs_after_app_update(cx: &mut TestAppContext) {
9310        let window = cx.add_window(|_, _| EmptyView);
9311        let observed_appearance = Rc::new(Cell::new(None));
9312        let _subscription = window
9313            .update(cx, {
9314                let observed_appearance = observed_appearance.clone();
9315                move |_, window, _| {
9316                    window.observe_window_appearance(move |window, _| {
9317                        observed_appearance.set(Some(window.appearance()));
9318                    })
9319                }
9320            })
9321            .unwrap();
9322        let test_window = cx.test_window(window.into());
9323
9324        cx.update(|_| {
9325            test_window.simulate_appearance_change(WindowAppearance::Dark);
9326            assert_eq!(observed_appearance.get(), None);
9327        });
9328        cx.run_until_parked();
9329
9330        assert_eq!(observed_appearance.get(), Some(WindowAppearance::Dark));
9331    }
9332
9333    #[gpui::test]
9334    fn queued_frame_callback_wakes_a_parked_render_loop(cx: &mut TestAppContext) {
9335        let window = cx.add_window(|_, _| Empty);
9336        let test_window = cx.test_window(window.into());
9337
9338        assert!(test_window.simulate_scheduled_frame());
9339        assert!(test_window.simulate_scheduled_frame());
9340        assert!(!test_window.frame_scheduled());
9341
9342        cx.update_window(window.into(), |_, window, _| {
9343            window.active.set(true);
9344            window.on_next_frame(|_, _| {});
9345        })
9346        .unwrap();
9347        assert!(
9348            test_window.frame_scheduled(),
9349            "queuing work on a parked window must wake the render loop"
9350        );
9351
9352        assert!(test_window.simulate_scheduled_frame());
9353        assert!(
9354            test_window.frame_scheduled(),
9355            "presenting the frame must await one compositor callback"
9356        );
9357        assert!(test_window.simulate_scheduled_frame());
9358        assert!(!test_window.frame_scheduled());
9359    }
9360
9361    #[gpui::test]
9362    fn pending_presentation_wakes_a_parked_render_loop(cx: &mut TestAppContext) {
9363        let window = cx.add_window(|_, _| Empty);
9364        let test_window = cx.test_window(window.into());
9365
9366        assert!(test_window.simulate_scheduled_frame());
9367        assert!(test_window.simulate_scheduled_frame());
9368        assert!(!test_window.frame_scheduled());
9369
9370        cx.update_window(window.into(), |_, window, cx| window.draw(cx).clear(cx))
9371            .unwrap();
9372
9373        assert!(
9374            test_window.frame_scheduled(),
9375            "a rendered scene awaiting presentation must wake the render loop"
9376        );
9377    }
9378
9379    #[gpui::test]
9380    fn callback_queued_during_a_frame_requests_a_follow_up(cx: &mut TestAppContext) {
9381        let window = cx.add_window(|_, _| Empty);
9382        let test_window = cx.test_window(window.into());
9383
9384        let callback_ran = Rc::new(Cell::new(false));
9385        cx.update_window(window.into(), |_, window, _| {
9386            // Inactive windows are frame-rate throttled, which would defer the
9387            // ticks this test drives manually.
9388            window.active.set(true);
9389            let callback_ran = callback_ran.clone();
9390            window.on_next_frame(move |window, _| {
9391                window.on_next_frame(move |_, _| callback_ran.set(true));
9392            });
9393        })
9394        .unwrap();
9395
9396        assert!(test_window.simulate_scheduled_frame());
9397        assert!(!callback_ran.get());
9398        assert!(
9399            test_window.frame_scheduled(),
9400            "a callback queued mid-frame must schedule a follow-up before the loop parks"
9401        );
9402
9403        assert!(test_window.simulate_scheduled_frame());
9404        assert!(callback_ran.get());
9405    }
9406
9407    struct RootView {
9408        explicit_size: bool,
9409        child_bounds: Rc<Cell<Bounds<Pixels>>>,
9410    }
9411
9412    impl Render for RootView {
9413        fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
9414            let child_bounds = self.child_bounds.clone();
9415            let root = div().flex().flex_col().child(
9416                canvas(
9417                    move |bounds, _, _| child_bounds.set(bounds),
9418                    |_, _, _, _| {},
9419                )
9420                .size_full(),
9421            );
9422            if self.explicit_size {
9423                root.w(px(300.)).h(px(200.))
9424            } else {
9425                root
9426            }
9427        }
9428    }
9429
9430    #[test]
9431    fn auto_sized_window_root_fills_the_window() {
9432        let mut cx = TestAppContext::single();
9433        let child_bounds = Rc::new(Cell::new(Bounds::default()));
9434        let window = cx.add_window({
9435            let child_bounds = child_bounds.clone();
9436            move |_, _| RootView {
9437                explicit_size: false,
9438                child_bounds,
9439            }
9440        });
9441
9442        let viewport_size = cx
9443            .update_window(window.into(), |_, window, cx| {
9444                window.draw(cx).clear(cx);
9445                window.viewport_size()
9446            })
9447            .unwrap();
9448
9449        assert_eq!(child_bounds.get().size, viewport_size);
9450    }
9451
9452    #[test]
9453    fn explicitly_sized_window_root_keeps_its_size() {
9454        let mut cx = TestAppContext::single();
9455        let child_bounds = Rc::new(Cell::new(Bounds::default()));
9456        let window = cx.add_window({
9457            let child_bounds = child_bounds.clone();
9458            move |_, _| RootView {
9459                explicit_size: true,
9460                child_bounds,
9461            }
9462        });
9463
9464        cx.update_window(window.into(), |_, window, cx| {
9465            window.draw(cx).clear(cx);
9466        })
9467        .unwrap();
9468
9469        assert_eq!(child_bounds.get().size, size(px(300.), px(200.)));
9470    }
9471
9472    struct FileDragView {
9473        path: PathBuf,
9474        observed_drag_moves: Rc<RefCell<Vec<Point<Pixels>>>>,
9475        observed_drops: Rc<RefCell<Vec<PathBuf>>>,
9476    }
9477
9478    struct FileDropExitView(Rc<Cell<usize>>);
9479
9480    impl Render for FileDropExitView {
9481        fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
9482            div().size_full().on_file_drop_exit({
9483                let observed_file_drop_exit = self.0.clone();
9484                move |_, _, _| observed_file_drop_exit.set(observed_file_drop_exit.get() + 1)
9485            })
9486        }
9487    }
9488
9489    impl Render for FileDragView {
9490        fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
9491            div()
9492                .id("file-drag")
9493                .size_full()
9494                .on_drag(self.path.clone(), |_, _, _, cx| cx.new(|_| Empty))
9495                .external_drag_payload(|path: &PathBuf, _, _| {
9496                    Some(ExternalDragPayload::Files(FileDragPaths::new([(
9497                        path.clone(),
9498                        true,
9499                    )])))
9500                })
9501                .on_drag_move({
9502                    let observed_drag_moves = self.observed_drag_moves.clone();
9503                    move |event: &DragMoveEvent<PathBuf>, _, _| {
9504                        observed_drag_moves.borrow_mut().push(event.event.position);
9505                    }
9506                })
9507                .on_drop({
9508                    let observed_drops = self.observed_drops.clone();
9509                    move |path: &PathBuf, _, _| observed_drops.borrow_mut().push(path.clone())
9510                })
9511        }
9512    }
9513
9514    #[gpui::test]
9515    fn file_drag_is_promoted_once_and_restored_in_source_window(cx: &mut TestAppContext) {
9516        struct Drag {
9517            window: AnyWindowHandle,
9518            observed_drag_moves: Rc<RefCell<Vec<Point<Pixels>>>>,
9519            observed_drops: Rc<RefCell<Vec<PathBuf>>>,
9520        }
9521
9522        fn start_drag(cx: &mut TestAppContext, path: PathBuf, platform_result: bool) -> Drag {
9523            let observed_drag_moves = Rc::new(RefCell::new(Vec::new()));
9524            let observed_drops = Rc::new(RefCell::new(Vec::new()));
9525            let window: AnyWindowHandle = cx
9526                .add_window({
9527                    let observed_drag_moves = observed_drag_moves.clone();
9528                    let observed_drops = observed_drops.clone();
9529                    move |_, _| FileDragView {
9530                        path,
9531                        observed_drag_moves,
9532                        observed_drops,
9533                    }
9534                })
9535                .into();
9536            cx.test_window(window)
9537                .set_start_external_drag_result(platform_result);
9538
9539            let update_result = cx.update_window(window, |_, window, cx| {
9540                window.draw(cx).clear(cx);
9541                window.dispatch_event(
9542                    MouseDownEvent {
9543                        position: point(px(10.), px(10.)),
9544                        button: MouseButton::Left,
9545                        modifiers: Default::default(),
9546                        click_count: 1,
9547                        first_mouse: false,
9548                    }
9549                    .to_platform_input(),
9550                    cx,
9551                );
9552                window.dispatch_event(
9553                    MouseMoveEvent {
9554                        position: point(px(20.), px(20.)),
9555                        pressed_button: Some(MouseButton::Left),
9556                        modifiers: Default::default(),
9557                    }
9558                    .to_platform_input(),
9559                    cx,
9560                );
9561                assert!(cx.active_drag.is_some());
9562            });
9563            assert!(
9564                update_result.is_ok(),
9565                "failed to start drag: {update_result:?}"
9566            );
9567
9568            assert!(cx.test_window(window).external_drag_files().is_empty());
9569            Drag {
9570                window,
9571                observed_drag_moves,
9572                observed_drops,
9573            }
9574        }
9575
9576        let successful_path = PathBuf::from("/tmp/successful-drag");
9577        let successful = start_drag(cx, successful_path.clone(), true);
9578        let outside_position = point(px(-1.), px(20.));
9579        let update_result = cx.update_window(successful.window, |_, window, cx| {
9580            window.dispatch_event(
9581                MouseMoveEvent {
9582                    position: outside_position,
9583                    pressed_button: Some(MouseButton::Left),
9584                    modifiers: Default::default(),
9585                }
9586                .to_platform_input(),
9587                cx,
9588            );
9589            assert!(cx.active_drag.is_none());
9590        });
9591        assert!(
9592            update_result.is_ok(),
9593            "failed to promote drag: {update_result:?}"
9594        );
9595        assert_eq!(
9596            cx.test_window(successful.window).external_drag_files(),
9597            [(successful_path.clone(), true)]
9598        );
9599        // Views must still see the move that leaves the window, otherwise they never learn to tear
9600        // down the drag state they built up while the pointer was inside.
9601        assert_eq!(
9602            successful.observed_drag_moves.borrow().last(),
9603            Some(&outside_position)
9604        );
9605
9606        let first_destination_exit_count = Rc::new(Cell::new(0));
9607        let first_destination: AnyWindowHandle = cx
9608            .add_window({
9609                let first_destination_exit_count = first_destination_exit_count.clone();
9610                move |_, _| FileDropExitView(first_destination_exit_count)
9611            })
9612            .into();
9613        let second_destination_exit_count = Rc::new(Cell::new(0));
9614        let second_destination: AnyWindowHandle = cx
9615            .add_window({
9616                let second_destination_exit_count = second_destination_exit_count.clone();
9617                move |_, _| FileDropExitView(second_destination_exit_count)
9618            })
9619            .into();
9620        let reentry_position = point(px(30.), px(30.));
9621        let external_paths = || ExternalPaths([successful_path.clone()].into_iter().collect());
9622        let update_result = cx.update_window(first_destination, |_, window, cx| {
9623            window.draw(cx).clear(cx);
9624            window.dispatch_event(
9625                FileDropEvent::Entered {
9626                    position: reentry_position,
9627                    paths: external_paths(),
9628                }
9629                .to_platform_input(),
9630                cx,
9631            );
9632            assert!(
9633                cx.active_drag
9634                    .as_ref()
9635                    .is_some_and(|drag| drag.value.downcast_ref::<ExternalPaths>().is_some())
9636            );
9637            window.dispatch_event(FileDropEvent::Exited.to_platform_input(), cx);
9638            assert!(cx.active_drag.is_none());
9639            assert_eq!(first_destination_exit_count.get(), 1);
9640            assert_eq!(second_destination_exit_count.get(), 0);
9641        });
9642        assert!(
9643            update_result.is_ok(),
9644            "failed to handle drag in first destination window: {update_result:?}"
9645        );
9646
9647        let update_result = cx.update_window(second_destination, |_, window, cx| {
9648            window.draw(cx).clear(cx);
9649            window.dispatch_event(
9650                PlatformInput::KeyDown(KeyDownEvent {
9651                    keystroke: Keystroke::parse("down").expect("valid keystroke"),
9652                    is_held: false,
9653                    prefer_character_input: false,
9654                }),
9655                cx,
9656            );
9657            window.dispatch_event(
9658                FileDropEvent::Entered {
9659                    position: reentry_position,
9660                    paths: external_paths(),
9661                }
9662                .to_platform_input(),
9663                cx,
9664            );
9665            assert!(
9666                cx.active_drag
9667                    .as_ref()
9668                    .is_some_and(|drag| drag.value.downcast_ref::<ExternalPaths>().is_some())
9669            );
9670            assert_eq!(first_destination_exit_count.get(), 1);
9671            assert_eq!(second_destination_exit_count.get(), 0);
9672
9673            window.dispatch_event(FileDropEvent::Exited.to_platform_input(), cx);
9674            assert!(cx.active_drag.is_none());
9675            assert_eq!(first_destination_exit_count.get(), 1);
9676            assert_eq!(second_destination_exit_count.get(), 1);
9677        });
9678        assert!(
9679            update_result.is_ok(),
9680            "failed to handle drag in second destination window: {update_result:?}"
9681        );
9682
9683        let update_result = cx.update_window(successful.window, |_, window, cx| {
9684            window.dispatch_event(
9685                FileDropEvent::Entered {
9686                    position: reentry_position,
9687                    paths: external_paths(),
9688                }
9689                .to_platform_input(),
9690                cx,
9691            );
9692            assert!(
9693                cx.active_drag
9694                    .as_ref()
9695                    .is_some_and(|drag| drag.value.downcast_ref::<PathBuf>().is_some())
9696            );
9697            assert_eq!(
9698                successful.observed_drag_moves.borrow().last(),
9699                Some(&reentry_position)
9700            );
9701
9702            window.dispatch_event(FileDropEvent::Exited.to_platform_input(), cx);
9703            assert!(cx.active_drag.is_none());
9704
9705            window.dispatch_event(
9706                FileDropEvent::Entered {
9707                    position: reentry_position,
9708                    paths: external_paths(),
9709                }
9710                .to_platform_input(),
9711                cx,
9712            );
9713            assert!(
9714                cx.active_drag
9715                    .as_ref()
9716                    .is_some_and(|drag| drag.value.downcast_ref::<PathBuf>().is_some())
9717            );
9718
9719            window.dispatch_event(
9720                FileDropEvent::Submit {
9721                    position: reentry_position,
9722                }
9723                .to_platform_input(),
9724                cx,
9725            );
9726            assert_eq!(
9727                successful.observed_drops.borrow().as_slice(),
9728                std::slice::from_ref(&successful_path)
9729            );
9730            assert!(cx.active_drag.is_none());
9731
9732            window.dispatch_event(FileDropEvent::Exited.to_platform_input(), cx);
9733            assert!(cx.active_drag.is_none());
9734            window.dispatch_event(FileDropEvent::Ended.to_platform_input(), cx);
9735            assert!(cx.active_drag.is_none());
9736
9737            window.dispatch_event(
9738                FileDropEvent::Entered {
9739                    position: reentry_position,
9740                    paths: external_paths(),
9741                }
9742                .to_platform_input(),
9743                cx,
9744            );
9745            assert!(
9746                cx.active_drag
9747                    .as_ref()
9748                    .is_some_and(|drag| drag.value.downcast_ref::<ExternalPaths>().is_some())
9749            );
9750            window.dispatch_event(FileDropEvent::Exited.to_platform_input(), cx);
9751        });
9752        assert!(
9753            update_result.is_ok(),
9754            "failed to restore drag in source window: {update_result:?}"
9755        );
9756
9757        let cancelled_path = PathBuf::from("/tmp/cancelled-drag");
9758        let cancelled = start_drag(cx, cancelled_path.clone(), true);
9759        let update_result = cx.update_window(cancelled.window, |_, window, cx| {
9760            window.dispatch_event(
9761                MouseMoveEvent {
9762                    position: outside_position,
9763                    pressed_button: Some(MouseButton::Left),
9764                    modifiers: Default::default(),
9765                }
9766                .to_platform_input(),
9767                cx,
9768            );
9769            assert!(cx.active_drag.is_none());
9770
9771            window.dispatch_event(
9772                FileDropEvent::Entered {
9773                    position: reentry_position,
9774                    paths: ExternalPaths([cancelled_path].into_iter().collect()),
9775                }
9776                .to_platform_input(),
9777                cx,
9778            );
9779            assert!(
9780                cx.active_drag
9781                    .as_ref()
9782                    .is_some_and(|drag| drag.value.downcast_ref::<PathBuf>().is_some())
9783            );
9784            assert!(cx.stop_active_drag(window));
9785            assert!(cx.active_drag.is_none());
9786        });
9787        assert!(
9788            update_result.is_ok(),
9789            "failed to cancel restored drag: {update_result:?}"
9790        );
9791        assert!(!cx.update(|cx| cx.end_platform_drag(cancelled.window.window_id())));
9792
9793        let removed_path = PathBuf::from("/tmp/removed-window-drag");
9794        let removed = start_drag(cx, removed_path, true);
9795        let removed_window_id = removed.window.window_id();
9796        let update_result = cx.update_window(removed.window, |_, window, cx| {
9797            window.dispatch_event(
9798                MouseMoveEvent {
9799                    position: outside_position,
9800                    pressed_button: Some(MouseButton::Left),
9801                    modifiers: Default::default(),
9802                }
9803                .to_platform_input(),
9804                cx,
9805            );
9806            assert!(cx.active_drag.is_none());
9807            window.remove_window();
9808        });
9809        assert!(
9810            update_result.is_ok(),
9811            "failed to remove drag source window: {update_result:?}"
9812        );
9813        assert!(!cx.update(|cx| cx.end_platform_drag(removed_window_id)));
9814
9815        let failed_path = PathBuf::from("/tmp/failed-drag");
9816        let failed = start_drag(cx, failed_path.clone(), false);
9817        let update_result = cx.update_window(failed.window, |_, window, cx| {
9818            for x_position in [-1., -2.] {
9819                window.dispatch_event(
9820                    MouseMoveEvent {
9821                        position: point(px(x_position), px(20.)),
9822                        pressed_button: Some(MouseButton::Left),
9823                        modifiers: Default::default(),
9824                    }
9825                    .to_platform_input(),
9826                    cx,
9827                );
9828            }
9829            assert!(cx.active_drag.is_some());
9830        });
9831        assert!(
9832            update_result.is_ok(),
9833            "failed to retain drag after platform failure: {update_result:?}"
9834        );
9835        assert_eq!(
9836            cx.test_window(failed.window).external_drag_files(),
9837            [(failed_path, true)]
9838        );
9839    }
9840
9841    struct FocusForwarder {
9842        a: FocusHandle,
9843        b: FocusHandle,
9844    }
9845
9846    impl Render for FocusForwarder {
9847        fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
9848            div()
9849                .size_full()
9850                .child(div().w(px(50.)).h(px(50.)).track_focus(&self.a))
9851                .child(div().w(px(50.)).h(px(50.)).track_focus(&self.b))
9852        }
9853    }
9854
9855    /// When a focus listener moves focus again (e.g. a dock forwarding focus to its
9856    /// active panel), the resulting focus events must be dispatched without waiting
9857    /// for an unrelated redraw of the window.
9858    #[gpui::test]
9859    fn test_focus_moved_by_focus_listener_is_dispatched(cx: &mut TestAppContext) {
9860        let b_focus_count = Rc::new(Cell::new(0));
9861        let window = cx.add_window({
9862            let b_focus_count = b_focus_count.clone();
9863            move |window, cx| {
9864                let a = cx.focus_handle();
9865                let b = cx.focus_handle();
9866                cx.on_focus(&a, window, |this: &mut FocusForwarder, window, cx| {
9867                    let b = this.b.clone();
9868                    window.focus(&b, cx);
9869                })
9870                .detach();
9871                cx.on_focus(&b, window, move |_, _, _| {
9872                    b_focus_count.set(b_focus_count.get() + 1);
9873                })
9874                .detach();
9875                FocusForwarder { a, b }
9876            }
9877        });
9878
9879        window
9880            .update(cx, |_, window, _| window.activate_window())
9881            .unwrap();
9882        cx.executor().run_until_parked();
9883
9884        window
9885            .update(cx, |this, window, cx| {
9886                let a = this.a.clone();
9887                window.focus(&a, cx);
9888            })
9889            .unwrap();
9890        cx.executor().run_until_parked();
9891
9892        window
9893            .update(cx, |this, window, _| {
9894                assert!(this.b.is_focused(window));
9895            })
9896            .unwrap();
9897        assert_eq!(b_focus_count.get(), 1);
9898    }
9899
9900    #[gpui::test]
9901    fn claimed_touch_drag_receives_movement_and_release(cx: &mut TestAppContext) {
9902        let events = Rc::new(RefCell::new(Vec::new()));
9903        let window = cx.add_window({
9904            let events = events.clone();
9905            move |_, _| TouchDragListener { events }
9906        });
9907        let touch = TouchId(1);
9908
9909        dispatch_touch(window, cx, touch, TouchPhase::Started, 10.);
9910        dispatch_touch(window, cx, touch, TouchPhase::Moved, 30.);
9911        dispatch_touch(window, cx, touch, TouchPhase::Ended, 40.);
9912
9913        assert_eq!(
9914            events.borrow().as_slice(),
9915            [
9916                (TouchPhase::Started, px(10.)),
9917                (TouchPhase::Moved, px(30.)),
9918                (TouchPhase::Ended, px(40.)),
9919            ]
9920        );
9921    }
9922
9923    #[gpui::test]
9924    fn back_gesture_is_claimed_by_the_innermost_listener(cx: &mut TestAppContext) {
9925        let claims = Rc::new(RefCell::new(Vec::new()));
9926        let window = cx.add_window({
9927            let claims = claims.clone();
9928            move |_, _| BackListeners { claims }
9929        });
9930        let dispatch_back = |cx: &mut TestAppContext, x: f32| {
9931            window
9932                .update(cx, |_, window, cx| {
9933                    window
9934                        .dispatch_event(
9935                            BackGestureEvent {
9936                                phase: BackGesturePhase::Started,
9937                                start_position: point(px(x), px(10.)),
9938                                progress: 0.,
9939                            }
9940                            .to_platform_input(),
9941                            cx,
9942                        )
9943                        .default_prevented
9944                })
9945                .unwrap()
9946        };
9947        assert!(dispatch_back(cx, 10.));
9948        assert!(dispatch_back(cx, 80.));
9949        assert!(!dispatch_back(cx, 150.));
9950        assert_eq!(claims.borrow().as_slice(), ["inner", "outer"]);
9951    }
9952
9953    struct BackListeners {
9954        claims: Rc<RefCell<Vec<&'static str>>>,
9955    }
9956
9957    impl Render for BackListeners {
9958        fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
9959            let claim = |name: &'static str| {
9960                let claims = self.claims.clone();
9961                move |_: &BackGestureEvent, _: &mut Window, _: &mut crate::App| {
9962                    claims.borrow_mut().push(name)
9963                }
9964            };
9965            div().size_full().child(
9966                div()
9967                    .w(px(100.))
9968                    .h_full()
9969                    .on_back_gesture(claim("outer"))
9970                    .child(div().w(px(50.)).h_full().on_back_gesture(claim("inner"))),
9971            )
9972        }
9973    }
9974
9975    struct TouchDragListener {
9976        events: Rc<RefCell<Vec<(TouchPhase, Pixels)>>>,
9977    }
9978
9979    impl Render for TouchDragListener {
9980        fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
9981            let events = self.events.clone();
9982            canvas(
9983                |_, _, _| {},
9984                move |_, _, window, _| {
9985                    window.on_mouse_event(move |event: &TouchDragEvent, phase, window, _cx| {
9986                        if phase != DispatchPhase::Bubble {
9987                            return;
9988                        }
9989                        events.borrow_mut().push((event.phase, event.position.x));
9990                        if event.phase == TouchPhase::Started {
9991                            window.prevent_default();
9992                        }
9993                    });
9994                },
9995            )
9996        }
9997    }
9998
9999    #[gpui::test]
10000    fn long_press_is_claimed_only_when_started_prevents_default(cx: &mut TestAppContext) {
10001        for response in [
10002            LongPressResponse::PreventDefault,
10003            LongPressResponse::StopPropagation,
10004            LongPressResponse::None,
10005        ] {
10006            let phases = Rc::new(RefCell::new(Vec::new()));
10007            let window = cx.add_window({
10008                let phases = phases.clone();
10009                move |_, _| LongPressListener { phases, response }
10010            });
10011            dispatch_touch(window, cx, TouchId(1), TouchPhase::Started, 0.);
10012            cx.executor().advance_clock(Duration::from_millis(501));
10013            cx.executor().run_until_parked();
10014            window
10015                .update(cx, |_, window, _| {
10016                    assert_eq!(
10017                        window.long_press_capture.is_some(),
10018                        response == LongPressResponse::PreventDefault
10019                    );
10020                })
10021                .unwrap();
10022            dispatch_touch(window, cx, TouchId(1), TouchPhase::Moved, 2.);
10023            dispatch_touch(window, cx, TouchId(1), TouchPhase::Ended, 2.);
10024            window
10025                .update(cx, |_, window, _| {
10026                    assert!(window.long_press_capture.is_none());
10027                })
10028                .unwrap();
10029
10030            let phases = phases.borrow();
10031            if response == LongPressResponse::PreventDefault {
10032                assert_eq!(
10033                    phases.as_slice(),
10034                    [TouchPhase::Started, TouchPhase::Moved, TouchPhase::Ended]
10035                );
10036            } else {
10037                assert_eq!(phases.as_slice(), [TouchPhase::Started]);
10038            }
10039        }
10040    }
10041
10042    #[gpui::test]
10043    fn stale_default_prevention_does_not_claim_long_press(cx: &mut TestAppContext) {
10044        let phases = Rc::new(RefCell::new(Vec::new()));
10045        let window = cx.add_window({
10046            let phases = phases.clone();
10047            move |_, _| LongPressListener {
10048                phases,
10049                response: LongPressResponse::None,
10050            }
10051        });
10052        window
10053            .update(cx, |_, window, _| {
10054                window.prevent_default();
10055            })
10056            .unwrap();
10057
10058        dispatch_touch(window, cx, TouchId(1), TouchPhase::Started, 0.);
10059        cx.executor().advance_clock(Duration::from_millis(501));
10060        cx.executor().run_until_parked();
10061        dispatch_touch(window, cx, TouchId(1), TouchPhase::Moved, 2.);
10062
10063        assert_eq!(phases.borrow().as_slice(), [TouchPhase::Started]);
10064    }
10065
10066    #[gpui::test]
10067    fn resolved_touch_cancels_scheduled_long_press(cx: &mut TestAppContext) {
10068        for (phase, position) in [
10069            (TouchPhase::Ended, 0.),
10070            (TouchPhase::Cancelled, 0.),
10071            (TouchPhase::Moved, 20.),
10072        ] {
10073            let phases = Rc::new(RefCell::new(Vec::new()));
10074            let window = cx.add_window({
10075                let phases = phases.clone();
10076                move |_, _| LongPressListener {
10077                    phases,
10078                    response: LongPressResponse::PreventDefault,
10079                }
10080            });
10081            dispatch_touch(window, cx, TouchId(1), TouchPhase::Started, 0.);
10082            dispatch_touch(window, cx, TouchId(1), phase, position);
10083            cx.executor().advance_clock(Duration::from_millis(501));
10084            cx.executor().run_until_parked();
10085
10086            assert!(phases.borrow().is_empty(), "{phase:?} allowed long press");
10087        }
10088    }
10089
10090    #[gpui::test]
10091    fn stale_long_press_timer_cannot_affect_replacement_touch(cx: &mut TestAppContext) {
10092        let phases = Rc::new(RefCell::new(Vec::new()));
10093        let window = cx.add_window({
10094            let phases = phases.clone();
10095            move |_, _| LongPressListener {
10096                phases,
10097                response: LongPressResponse::PreventDefault,
10098            }
10099        });
10100        let first_touch = TouchId(1);
10101        dispatch_touch(window, cx, first_touch, TouchPhase::Started, 0.);
10102        cx.executor().advance_clock(Duration::from_millis(250));
10103        dispatch_touch(window, cx, first_touch, TouchPhase::Cancelled, 0.);
10104        dispatch_touch(window, cx, TouchId(2), TouchPhase::Started, 10.);
10105
10106        cx.executor().advance_clock(Duration::from_millis(251));
10107        cx.executor().run_until_parked();
10108        assert!(phases.borrow().is_empty());
10109
10110        cx.executor().advance_clock(Duration::from_millis(250));
10111        cx.executor().run_until_parked();
10112        assert_eq!(phases.borrow().as_slice(), [TouchPhase::Started]);
10113    }
10114
10115    #[gpui::test]
10116    fn test_underline_exclusions_preserve_device_geometry(cx: &mut TestAppContext) {
10117        test_underline_paint_at_scales(cx, |window| {
10118            let (numerator, denominator) = match window.scale_factor() {
10119                1.0 => (1, 1),
10120                1.25 => (5, 4),
10121                1.5 => (3, 2),
10122                2.0 => (2, 1),
10123                3.0 => (3, 1),
10124                scale => panic!("unexpected scale {scale}"),
10125            };
10126            let snap = |quarters: i32| {
10127                let scaled = quarters * numerator;
10128                let divisor = 4 * denominator;
10129                let rounded =
10130                    scaled.abs() / divisor + i32::from(2 * (scaled.abs() % divisor) > divisor);
10131                ScaledPixels((scaled.signum() * rounded) as f32)
10132            };
10133            let stroke = |quarters| {
10134                if quarters == 0 {
10135                    ScaledPixels(0.)
10136                } else {
10137                    snap(quarters).max(ScaledPixels(1.))
10138                }
10139            };
10140
10141            for origin in [-101, -3, -2, -1, 0, 1, 2, 3, 101] {
10142                for width in [0, 1, 3, 84] {
10143                    for thickness in [0, 1, 4, 7] {
10144                        for wavy in [false, true] {
10145                            let style = UnderlineStyle {
10146                                thickness: px(thickness as f32 / 4.),
10147                                color: Some(hsla(0.25, 0.5, 0.75, 0.5)),
10148                                wavy,
10149                            };
10150                            let bounds = Bounds::new(
10151                                point(snap(origin), snap(-origin)),
10152                                size(
10153                                    stroke(width),
10154                                    stroke(thickness) * if wavy { 3. } else { 1. },
10155                                ),
10156                            );
10157                            let origin = point(px(origin as f32 / 4.), px(-origin as f32 / 4.));
10158                            let width = px(width as f32 / 4.);
10159                            assert_eq!(window.underline_bounds(origin, width, &style), bounds);
10160                            let original = paint_test_underlines(window, |window| {
10161                                window.paint_underline(origin, width, &style);
10162                            })
10163                            .to_vec();
10164                            assert_eq!(original.len(), usize::from(!bounds.is_empty()));
10165                            if let Some(underline) = original.first() {
10166                                assert_eq!(underline.bounds, bounds);
10167                                assert_eq!(underline.thickness, stroke(thickness));
10168                                assert_eq!(underline.wavy, wavy.into());
10169                                assert_eq!(underline.color, hsla(0.25, 0.5, 0.75, 0.5));
10170                            }
10171
10172                            let underlines = paint_test_underlines(window, |window| {
10173                                window.paint_underline_with_exclusions(origin, width, &style, &[]);
10174                            });
10175                            assert_eq!(underlines.len(), original.len());
10176                            for (actual, original) in underlines.iter().zip(&original) {
10177                                assert_same_underline_geometry(actual, original);
10178                                assert_eq!(actual.content_mask, original.content_mask);
10179                            }
10180
10181                            let left = bounds.left().0 as i32;
10182                            let right = bounds.right().0 as i32;
10183                            let exclusions = [
10184                                (15, 25),
10185                                (3, 7),
10186                                (5, 10),
10187                                (10, 12),
10188                                (0, 0),
10189                                (4, 2),
10190                                (-50, -1),
10191                                (70, 100),
10192                            ]
10193                            .map(|(start, end)| {
10194                                ScaledPixels((left + start) as f32)
10195                                    ..ScaledPixels((left + end) as f32)
10196                            });
10197                            let underlines = paint_test_underlines(window, |window| {
10198                                window.paint_underline_with_exclusions(
10199                                    origin,
10200                                    width,
10201                                    &style,
10202                                    &exclusions,
10203                                );
10204                            });
10205                            let expected = (left..right)
10206                                .filter(|column| {
10207                                    !bounds.is_empty()
10208                                        && !exclusions.iter().any(|span| {
10209                                            span.contains(&ScaledPixels(*column as f32))
10210                                        })
10211                                })
10212                                .collect::<Vec<_>>();
10213                            assert_eq!(underline_device_columns(underlines), expected);
10214                            for underline in underlines {
10215                                assert_same_underline_geometry(underline, &original[0]);
10216                            }
10217                        }
10218                    }
10219                }
10220            }
10221        });
10222    }
10223
10224    #[gpui::test]
10225    fn test_underline_exclusions_preserve_helvetica_warning_edge(cx: &mut TestAppContext) {
10226        test_underline_paint_at_scales(cx, |window| {
10227            if window.scale_factor() != 2.0 {
10228                return;
10229            }
10230            let style = UnderlineStyle {
10231                thickness: px(1.),
10232                color: None,
10233                wavy: true,
10234            };
10235            let origin = point(px(2.888_183_8), px(15.357_917));
10236            let width = px(23.848_145) - origin.x;
10237            let original = paint_test_underlines(window, |window| {
10238                window.paint_underline(origin, width, &style);
10239            })[0];
10240            assert_eq!(original.bounds.left(), ScaledPixels(6.));
10241            assert_eq!(original.bounds.right(), ScaledPixels(48.));
10242            let point_bounds = window.underline_bounds(origin, px(10.829_102), &style);
10243            assert_eq!(point_bounds.left(), ScaledPixels(6.));
10244            assert_eq!(point_bounds.right(), ScaledPixels(28.));
10245
10246            let underlines = paint_test_underlines(window, |window| {
10247                window.paint_underline_with_exclusions(
10248                    origin,
10249                    width,
10250                    &style,
10251                    &[point_bounds.left()..point_bounds.right()],
10252                );
10253            });
10254            assert_eq!(underlines.len(), 1);
10255            assert_same_underline_geometry(&underlines[0], &original);
10256            assert_eq!(
10257                underline_device_columns(underlines),
10258                (28..48).collect::<Vec<_>>()
10259            );
10260        });
10261    }
10262
10263    #[gpui::test]
10264    fn test_underline_exclusions_preserve_content_mask_and_opacity(cx: &mut TestAppContext) {
10265        test_underline_paint_at_scales(cx, |window| {
10266            let scale = window.scale_factor();
10267            let original_mask = window.content_mask();
10268            let original_opacity = window.element_opacity();
10269            let mask = ContentMask {
10270                bounds: Bounds::from_corners(point(px(4.), px(10.)), point(px(16.), px(12.))),
10271            };
10272            let style = UnderlineStyle {
10273                thickness: px(2.),
10274                color: Some(hsla(0.25, 0.5, 0.75, 0.5)),
10275                wavy: true,
10276            };
10277            let origin = point(px(-1.25), px(9.25));
10278            let width = px(24.);
10279            window.with_content_mask(Some(mask), |window| {
10280                window.with_element_opacity(Some(0.5), |window| {
10281                    window.with_element_opacity(Some(0.5), |window| {
10282                        let original = paint_test_underlines(window, |window| {
10283                            window.paint_underline(origin, width, &style);
10284                        })[0];
10285                        assert_eq!(original.color, hsla(0.25, 0.5, 0.75, 0.125));
10286                        let underlines = paint_test_underlines(window, |window| {
10287                            window.paint_underline_with_exclusions(
10288                                origin,
10289                                width,
10290                                &style,
10291                                &[ScaledPixels(6. * scale)..ScaledPixels(8. * scale)],
10292                            );
10293                        });
10294                        assert_eq!(underlines.len(), 2);
10295                        let expected = [(4. * scale, 6. * scale), (8. * scale, 16. * scale)].map(
10296                            |(left, right)| {
10297                                Bounds::from_corners(
10298                                    point(ScaledPixels(left), ScaledPixels((10. * scale).floor())),
10299                                    point(ScaledPixels(right), ScaledPixels((12. * scale).ceil())),
10300                                )
10301                            },
10302                        );
10303                        assert_eq!(
10304                            underlines
10305                                .iter()
10306                                .map(|underline| underline.content_mask.bounds)
10307                                .collect::<Vec<_>>(),
10308                            expected
10309                        );
10310                        for underline in underlines {
10311                            assert_same_underline_geometry(underline, &original);
10312                        }
10313                    });
10314                });
10315            });
10316            assert_eq!(window.content_mask(), original_mask);
10317            assert_eq!(window.element_opacity(), original_opacity);
10318        });
10319    }
10320
10321    #[gpui::test]
10322    fn test_underline_exclusions_adversarial_permutations(cx: &mut TestAppContext) {
10323        test_underline_paint_at_scales(cx, |window| {
10324            let style = UnderlineStyle {
10325                thickness: px(1.),
10326                color: None,
10327                wavy: true,
10328            };
10329            let origin = point(px(-4.), px(-1.));
10330            let width = px(8.);
10331            let left = (-4. * window.scale_factor()) as i32;
10332            let right = (4. * window.scale_factor()) as i32;
10333            let endpoints = [-16, -8, -1, 0, 1, 8, 16];
10334            for first_start in endpoints {
10335                for first_end in endpoints {
10336                    for second_start in endpoints {
10337                        for second_end in endpoints {
10338                            let exclusions = [first_start..first_end, second_start..second_end];
10339                            let expected = (left..right)
10340                                .filter(|column| {
10341                                    !exclusions.iter().any(|span| span.contains(column))
10342                                })
10343                                .collect::<Vec<_>>();
10344                            let exclusions = exclusions.map(|span| {
10345                                ScaledPixels(span.start as f32)..ScaledPixels(span.end as f32)
10346                            });
10347                            let underlines = paint_test_underlines(window, |window| {
10348                                window.paint_underline_with_exclusions(
10349                                    origin,
10350                                    width,
10351                                    &style,
10352                                    &exclusions,
10353                                );
10354                            });
10355                            assert_eq!(
10356                                underline_device_columns(underlines),
10357                                expected,
10358                                "{exclusions:?}"
10359                            );
10360                        }
10361                    }
10362                }
10363            }
10364        });
10365    }
10366
10367    #[derive(Clone, Copy, PartialEq)]
10368    enum LongPressResponse {
10369        PreventDefault,
10370        StopPropagation,
10371        None,
10372    }
10373
10374    struct LongPressListener {
10375        phases: Rc<RefCell<Vec<TouchPhase>>>,
10376        response: LongPressResponse,
10377    }
10378
10379    impl Render for LongPressListener {
10380        fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
10381            let entity = cx.entity();
10382            let phases = self.phases.clone();
10383            let response = self.response;
10384            canvas(
10385                |_, _, _| {},
10386                move |_, _, window, _| {
10387                    window.on_mouse_event(move |event: &LongPressEvent, phase, window, cx| {
10388                        if phase != DispatchPhase::Bubble {
10389                            return;
10390                        }
10391                        phases.borrow_mut().push(event.phase);
10392                        match response {
10393                            LongPressResponse::PreventDefault => {
10394                                window.capture_long_press(&entity);
10395                                window.prevent_default();
10396                            }
10397                            LongPressResponse::StopPropagation => cx.stop_propagation(),
10398                            LongPressResponse::None => {}
10399                        }
10400                    });
10401                },
10402            )
10403        }
10404    }
10405
10406    struct UnderlineTestView(Rc<dyn Fn(&mut Window)>);
10407
10408    #[gpui::test]
10409    fn preparation_window_geometry_survives_scaling_and_clipping(cx: &mut TestAppContext) {
10410        #[derive(Debug)]
10411        struct Probe;
10412        impl crate::CustomContent for Probe {
10413            fn prepare(
10414                &self,
10415                _: &dyn std::any::Any,
10416                _: crate::Size<crate::DevicePixels>,
10417            ) -> anyhow::Result<Box<dyn std::any::Any>> {
10418                panic!("request-aware preparation expected")
10419            }
10420
10421            fn prepare_with_request(
10422                &self,
10423                _: &dyn std::any::Any,
10424                request: &crate::PreparationRequest,
10425            ) -> anyhow::Result<Box<dyn std::any::Any>> {
10426                Ok(Box::new(*request))
10427            }
10428        }
10429        test_underline_paint_at_scales(cx, |window| {
10430            let bounds = Bounds::new(point(px(10.3), px(20.7)), size(px(100.3), px(50.7)));
10431            let content: std::sync::Arc<dyn crate::CustomContent> = std::sync::Arc::new(Probe);
10432            let mut path = crate::PathBuilder::fill();
10433            path.move_to(bounds.origin);
10434            path.line_to(bounds.top_right());
10435            path.line_to(bounds.bottom_right());
10436            path.line_to(bounds.bottom_left());
10437            path.close();
10438            let path = path.build().unwrap();
10439            let mut full_requests = Vec::new();
10440            for clipped in [false, true] {
10441                window.next_frame.scene.clear();
10442                if clipped {
10443                    window.content_mask_stack.push(ContentMask {
10444                        bounds: Bounds::new(point(px(30.), px(30.)), size(px(20.), px(15.))),
10445                    });
10446                }
10447                window.paint_custom(
10448                    crate::CustomGeometry::RoundedRect {
10449                        bounds,
10450                        corner_radii: crate::Corners::default(),
10451                    },
10452                    content.clone(),
10453                );
10454                window.paint_custom(
10455                    crate::CustomGeometry::Border(crate::quad(
10456                        bounds,
10457                        crate::Corners::default(),
10458                        crate::transparent_black(),
10459                        crate::Edges::all(px(2.)),
10460                        crate::transparent_black(),
10461                        crate::BorderStyle::Solid,
10462                    )),
10463                    content.clone(),
10464                );
10465                window.paint_custom(crate::CustomGeometry::Path(path.clone()), content.clone());
10466                if clipped {
10467                    window.content_mask_stack.pop();
10468                }
10469                let draws = &window.next_frame.scene.custom_draws;
10470                assert_eq!(draws.len(), 3);
10471                for (index, draw) in draws.iter().enumerate() {
10472                    let raster = draw
10473                        .bounds
10474                        .size
10475                        .map(|v| crate::DevicePixels(v.0.ceil() as i32));
10476                    let default_request = crate::PreparationRequest::new(
10477                        draw.bounds.size.map(|v| px(v.0)),
10478                        raster,
10479                        1.,
10480                    )
10481                    .unwrap();
10482                    let output = draw
10483                        .content
10484                        .prepare_with_request(&(), &default_request)
10485                        .unwrap();
10486                    let request = *output.downcast::<crate::PreparationRequest>().unwrap();
10487                    let logical = if index == 2 {
10488                        path.bounds.size
10489                    } else {
10490                        bounds.size
10491                    };
10492                    assert_eq!(request.logical_size(), logical);
10493                    assert_eq!(request.scale_factor(), window.scale_factor());
10494                    assert_eq!(request.raster_size(), raster);
10495                    if clipped {
10496                        assert_eq!(request, full_requests[index]);
10497                    } else {
10498                        full_requests.push(request);
10499                    }
10500                }
10501            }
10502        });
10503    }
10504
10505    impl Render for UnderlineTestView {
10506        fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
10507            let paint = self.0.clone();
10508            canvas(
10509                |_, _, _| {},
10510                move |_, _, window, _| {
10511                    window.content_mask_stack.push(ContentMask {
10512                        bounds: Bounds::from_corners(
10513                            point(px(-1000.), px(-1000.)),
10514                            point(px(1000.), px(1000.)),
10515                        ),
10516                    });
10517                    paint(window);
10518                    window.content_mask_stack.pop();
10519                },
10520            )
10521            .size_full()
10522        }
10523    }
10524
10525    fn test_underline_paint_at_scales(
10526        cx: &mut TestAppContext,
10527        paint: impl Fn(&mut Window) + 'static,
10528    ) {
10529        let window = cx.add_window(move |_, _| UnderlineTestView(Rc::new(paint)));
10530        for scale in [1., 1.25, 1.5, 2., 3.] {
10531            cx.simulate_window_scale_factor_change(window.into(), scale);
10532            cx.update_window(window.into(), |_, window, cx| window.draw(cx).clear(cx))
10533                .unwrap();
10534        }
10535    }
10536
10537    fn paint_test_underlines(window: &mut Window, paint: impl FnOnce(&mut Window)) -> &[Underline] {
10538        window.next_frame.scene.clear();
10539        paint(window);
10540        &window.next_frame.scene.underlines
10541    }
10542
10543    fn assert_same_underline_geometry(actual: &Underline, expected: &Underline) {
10544        assert_eq!(actual.bounds, expected.bounds);
10545        assert_eq!(actual.thickness, expected.thickness);
10546        assert_eq!(actual.wavy, expected.wavy);
10547        assert_eq!(actual.color, expected.color);
10548        assert_eq!(actual.pad, expected.pad);
10549    }
10550
10551    fn underline_device_columns(underlines: &[Underline]) -> Vec<i32> {
10552        underlines
10553            .iter()
10554            .flat_map(|underline| {
10555                let bounds = underline.bounds.intersect(&underline.content_mask.bounds);
10556                bounds.left().0 as i32..bounds.right().0 as i32
10557            })
10558            .collect()
10559    }
10560
10561    fn dispatch_touch<T: 'static>(
10562        window: crate::WindowHandle<T>,
10563        cx: &mut TestAppContext,
10564        id: TouchId,
10565        phase: TouchPhase,
10566        x: f32,
10567    ) {
10568        window
10569            .update(cx, |_, window, cx| {
10570                window.dispatch_event(
10571                    TouchEvent {
10572                        id,
10573                        phase,
10574                        position: point(px(x), px(0.)),
10575                        predicted_position: None,
10576                        force: None,
10577                    }
10578                    .to_platform_input(),
10579                    cx,
10580                );
10581            })
10582            .unwrap();
10583    }
10584}
10585
10586#[cfg(all(test, debug_assertions))]
10587mod inspector_tests {
10588    use super::*;
10589    use crate::{
10590        DivInspectorState, InspectorElementId, MouseDownEvent, StyleRefinement, TestAppContext, div,
10591    };
10592
10593    #[gpui::test]
10594    fn inspector_only_tracks_its_open_window(cx: &mut TestAppContext) {
10595        let windows = [
10596            cx.add_window(|_, cx| InspectorTestRoot {
10597                child: cx.new(|_| InspectorTestView::default()),
10598            }),
10599            cx.add_window(|_, cx| InspectorTestRoot {
10600                child: cx.new(|_| InspectorTestView::default()),
10601            }),
10602        ];
10603        for window in windows {
10604            assert_closed_inspector(window.into(), cx);
10605        }
10606        for _ in 0..2 {
10607            cx.update_window(windows[0].into(), |root, window, cx| {
10608                let root = root.downcast::<InspectorTestRoot>().expect("test root");
10609                let child_widths = root.read(cx).child.read(cx).child_widths.clone();
10610                window.toggle_inspector(cx);
10611                window.draw(cx).clear(cx);
10612                assert_eq!(child_widths.borrow().as_slice(), &[px(10.); 3]);
10613                let path = window
10614                    .rendered_frame
10615                    .next_inspector_instance_ids
10616                    .iter()
10617                    .find_map(|(path, count)| (*count == 3).then(|| path.clone()))
10618                    .expect("anonymous siblings share an inspector path");
10619                let selected_id = InspectorElementId {
10620                    path,
10621                    instance_id: 1,
10622                };
10623                let position = window
10624                    .rendered_frame
10625                    .hitboxes
10626                    .iter()
10627                    .find(|hitbox| {
10628                        window.rendered_frame.inspector_hitboxes.get(&hitbox.id)
10629                            == Some(&selected_id)
10630                    })
10631                    .expect("middle sibling is pickable")
10632                    .bounds
10633                    .center();
10634                window.simulate_mouse_move(position, cx);
10635                window.dispatch_event(
10636                    PlatformInput::MouseDown(MouseDownEvent {
10637                        position,
10638                        button: MouseButton::Left,
10639                        modifiers: Modifiers::default(),
10640                        click_count: 1,
10641                        first_mouse: false,
10642                    }),
10643                    cx,
10644                );
10645                window.dispatch_event(
10646                    PlatformInput::MouseUp(MouseUpEvent {
10647                        position,
10648                        button: MouseButton::Left,
10649                        modifiers: Modifiers::default(),
10650                        click_count: 1,
10651                    }),
10652                    cx,
10653                );
10654                assert!(!window.is_inspector_picking(cx));
10655                assert_eq!(
10656                    window
10657                        .inspector
10658                        .as_ref()
10659                        .expect("open inspector")
10660                        .read(cx)
10661                        .active_element_id(),
10662                    Some(&selected_id)
10663                );
10664                window.draw(cx).clear(cx);
10665                window.with_inspector_state::<DivInspectorState, _>(
10666                    Some(&selected_id),
10667                    cx,
10668                    |state, _| {
10669                        let state = state.as_mut().expect("selected div has style state");
10670                        assert_eq!(
10671                            state.base_style.size.width,
10672                            Some(crate::Length::from(px(10.)))
10673                        );
10674                        state.base_style.size.width = Some(crate::Length::from(px(25.)));
10675                    },
10676                );
10677                window.refresh();
10678                window.draw(cx).clear(cx);
10679                assert_eq!(
10680                    child_widths.borrow().as_slice(),
10681                    &[px(10.), px(25.), px(10.)]
10682                );
10683            })
10684            .expect("pick and edit a cached child");
10685            assert_closed_inspector(windows[1].into(), cx);
10686            windows[0]
10687                .update(cx, |_, window, cx| window.toggle_inspector(cx))
10688                .expect("close inspector");
10689            assert_closed_inspector(windows[0].into(), cx);
10690        }
10691    }
10692
10693    struct InspectorTestRoot {
10694        child: Entity<InspectorTestView>,
10695    }
10696
10697    impl Render for InspectorTestRoot {
10698        fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
10699            self.child
10700                .clone()
10701                .cached(StyleRefinement::default().size(px(100.)))
10702        }
10703    }
10704
10705    #[derive(Default)]
10706    struct InspectorTestView {
10707        child_widths: Rc<RefCell<Vec<Pixels>>>,
10708    }
10709
10710    impl Render for InspectorTestView {
10711        fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
10712            let child_widths = self.child_widths.clone();
10713            div()
10714                .on_children_prepainted(move |bounds, _, _| {
10715                    *child_widths.borrow_mut() =
10716                        bounds.iter().map(|bounds| bounds.size.width).collect();
10717                })
10718                .with_dynamic_prepaint_order(|_, _| SmallVec::from_iter([2, 0, 1]))
10719                .id("inspector-root")
10720                .flex()
10721                .children((0..3).map(|_| div().size(px(10.)).flex_shrink_0()))
10722        }
10723    }
10724
10725    fn assert_closed_inspector(window: AnyWindowHandle, cx: &mut TestAppContext) {
10726        cx.update_window(window, |root, window, cx| {
10727            window.draw(cx).clear(cx);
10728            window.draw(cx).clear(cx);
10729            let root = root.downcast::<InspectorTestRoot>().expect("test root");
10730            assert_eq!(
10731                root.read(cx)
10732                    .child
10733                    .read(cx)
10734                    .child_widths
10735                    .borrow()
10736                    .as_slice(),
10737                &[px(10.); 3]
10738            );
10739            for frame in [&window.rendered_frame, &window.next_frame] {
10740                assert_eq!(frame.next_inspector_instance_ids.capacity(), 0);
10741                assert_eq!(frame.inspector_hitboxes.capacity(), 0);
10742            }
10743        })
10744        .expect("closed inspector has no bookkeeping and no style overrides");
10745    }
10746}