Skip to main content

gpui/
window.rs

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