Skip to main content

gpui/
window.rs

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