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