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    /// Synchronously re-render the last painted scene and read its associated
2897    /// extended linear-P3 FP16 composition, before display color management.
2898    /// Metal WideGamutSdr only. This waits for GPU completion; use on demand.
2899    #[cfg(any(test, feature = "test-support"))]
2900    pub fn render_to_linear_p3(&self) -> anyhow::Result<crate::LinearP3Image> {
2901        self.platform_window
2902            .render_to_linear_p3(&self.rendered_frame.scene)
2903    }
2904
2905    /// Returns the quads in the most recently rendered frame's scene, so tests can assert on
2906    /// painted output without rasterizing the frame. Quad bounds are in scaled pixels and are
2907    /// not clipped; each quad carries the content mask it will be clipped to when drawn. Quads
2908    /// whose bounds don't intersect their content mask are culled at paint time and won't appear.
2909    #[cfg(any(test, feature = "test-support"))]
2910    pub fn painted_quads(&self) -> Vec<Quad> {
2911        self.rendered_frame.scene.quads.clone()
2912    }
2913
2914    /// Returns the underlines in the most recently rendered frame's scene.
2915    #[cfg(any(test, feature = "test-support"))]
2916    pub fn painted_underlines(&self) -> Vec<Underline> {
2917        self.rendered_frame.scene.underlines.clone()
2918    }
2919
2920    /// Set the content size of the window.
2921    pub fn resize(&mut self, size: Size<Pixels>) {
2922        self.platform_window.resize(size);
2923    }
2924
2925    /// Returns whether or not the window is currently fullscreen
2926    pub fn is_fullscreen(&self) -> bool {
2927        self.platform_window.is_fullscreen()
2928    }
2929
2930    /// Returns whether the window is currently in simple (borderless) fullscreen,
2931    /// where it covers the entire screen including the menu bar and notch area.
2932    /// Always `false` on platforms other than macOS.
2933    pub fn is_simple_fullscreen(&self) -> bool {
2934        self.platform_window.is_simple_fullscreen()
2935    }
2936
2937    pub(crate) fn appearance_changed(&mut self, cx: &mut App) {
2938        self.appearance = self.platform_window.appearance();
2939
2940        self.appearance_observers
2941            .clone()
2942            .retain(&(), |callback| callback(self, cx));
2943    }
2944
2945    pub(crate) fn button_layout_changed(&mut self, cx: &mut App) {
2946        self.button_layout_observers
2947            .clone()
2948            .retain(&(), |callback| callback(self, cx));
2949    }
2950
2951    /// Returns the appearance of the current window.
2952    pub fn appearance(&self) -> WindowAppearance {
2953        self.appearance
2954    }
2955
2956    /// Returns the size of the drawable area within the window.
2957    pub fn viewport_size(&self) -> Size<Pixels> {
2958        self.viewport_size
2959    }
2960
2961    /// Returns the platform's visible viewport in window-local logical pixels.
2962    ///
2963    /// Unlike `viewport_size`, this can shrink or move when the keyboard opens.
2964    /// During drawing this is a consistent frame snapshot. Outside drawing it
2965    /// reflects the latest platform sample, not a synchronous geometry query.
2966    pub fn visual_viewport_bounds(&self) -> Bounds<Pixels> {
2967        self.platform_window.visual_viewport_bounds()
2968    }
2969
2970    /// Returns a conservative rectangle avoiding platform-known obscured content.
2971    ///
2972    /// Intersects the visual viewport with the full layout area inset by system
2973    /// safe areas and keyboard occlusion. Unknown overlays cannot be excluded.
2974    pub fn fully_visible_bounds(&self) -> Bounds<Pixels> {
2975        let insets = self.platform_window.insets().effective();
2976        let viewport = self.viewport_size();
2977        let left = insets.left.max(Pixels::ZERO).min(viewport.width);
2978        let top = insets.top.max(Pixels::ZERO).min(viewport.height);
2979        let right = (viewport.width - insets.right.max(Pixels::ZERO)).max(left);
2980        let bottom = (viewport.height - insets.bottom.max(Pixels::ZERO)).max(top);
2981        let safe_bounds = Bounds::from_corners(point(left, top), point(right, bottom));
2982        let mut visible = safe_bounds.intersect(&self.visual_viewport_bounds());
2983        visible.size.width = visible.size.width.max(Pixels::ZERO);
2984        visible.size.height = visible.size.height.max(Pixels::ZERO);
2985        visible
2986    }
2987
2988    /// Requests the virtual keyboard for the currently focused text input.
2989    ///
2990    /// Call from a user gesture on platforms that require one. The platform may
2991    /// decline the request; this does not change focus or the layout viewport.
2992    pub fn request_virtual_keyboard(&self) {
2993        self.platform_window.show_soft_keyboard();
2994    }
2995
2996    /// Requests dismissal of the virtual keyboard without changing GPUI focus.
2997    pub fn dismiss_virtual_keyboard(&self) {
2998        self.platform_window.hide_soft_keyboard();
2999    }
3000
3001    /// Returns whether this window is focused by the operating system (receiving key events).
3002    pub fn is_window_active(&self) -> bool {
3003        self.active.get()
3004    }
3005
3006    /// Returns whether this window is considered to be the window
3007    /// that currently owns the mouse cursor.
3008    /// On mac, this is equivalent to `is_window_active`.
3009    pub fn is_window_hovered(&self) -> bool {
3010        if cfg!(any(
3011            target_os = "windows",
3012            target_os = "linux",
3013            target_os = "freebsd"
3014        )) {
3015            self.hovered.get()
3016        } else {
3017            self.is_window_active()
3018        }
3019    }
3020
3021    /// Toggle zoom on the window.
3022    pub fn zoom_window(&self) {
3023        self.platform_window.zoom();
3024    }
3025
3026    /// Opens the native title bar context menu, useful when implementing client side decorations (Wayland and X11)
3027    pub fn show_window_menu(&self, position: Point<Pixels>) {
3028        self.platform_window.show_window_menu(position)
3029    }
3030
3031    /// Handle window movement for Linux and macOS.
3032    /// Tells the compositor to take control of window movement (Wayland and X11)
3033    ///
3034    /// Events may not be received during a move operation.
3035    pub fn start_window_move(&self) {
3036        self.platform_window.start_window_move()
3037    }
3038
3039    /// When using client side decorations, set this to the width of the invisible decorations (Wayland and X11)
3040    pub fn set_client_inset(&mut self, inset: Pixels) {
3041        self.client_inset = Some(inset);
3042        self.platform_window.set_client_inset(inset);
3043    }
3044
3045    /// Returns the client_inset value by [`Self::set_client_inset`].
3046    pub fn client_inset(&self) -> Option<Pixels> {
3047        self.client_inset
3048    }
3049
3050    /// Returns whether the title bar window controls need to be rendered by the application (Wayland and X11)
3051    pub fn window_decorations(&self) -> Decorations {
3052        self.platform_window.window_decorations()
3053    }
3054
3055    /// Returns whether this window is resizable.
3056    pub fn is_resizable(&self) -> bool {
3057        self.is_resizable
3058    }
3059
3060    /// Returns whether this window is minimizable.
3061    pub fn is_minimizable(&self) -> bool {
3062        self.is_minimizable
3063    }
3064
3065    /// Returns the controls supported by the platform.
3066    pub fn window_controls(&self) -> WindowControls {
3067        self.platform_window.window_controls()
3068    }
3069
3070    /// Updates the window's title at the platform level.
3071    pub fn set_window_title(&mut self, title: &str) {
3072        self.platform_window.set_title(title);
3073        self.a11y.set_window_title(title.to_string());
3074    }
3075
3076    /// Sets the position of the macOS traffic light buttons.
3077    #[cfg(target_os = "macos")]
3078    pub fn set_traffic_light_position(&self, position: Point<Pixels>) {
3079        self.platform_window.set_traffic_light_position(position);
3080    }
3081
3082    /// Sets the application identifier.
3083    pub fn set_app_id(&mut self, app_id: &str) {
3084        self.platform_window.set_app_id(app_id);
3085    }
3086
3087    /// Negotiate this window's color presentation without reinterpreting UI colors.
3088    /// Call during construction or an event update, outside layout/prepaint/paint.
3089    /// Unsupported requests and negotiation failures leave the previous state intact.
3090    pub fn set_color_mode(
3091        &mut self,
3092        mode: crate::WindowColorMode,
3093    ) -> anyhow::Result<crate::WindowColorStatus> {
3094        anyhow::ensure!(
3095            self.invalidator.not_drawing(),
3096            "cannot change color presentation during drawing"
3097        );
3098        let status = self.platform_window.set_color_mode(mode)?;
3099        self.refresh();
3100        Ok(status)
3101    }
3102
3103    /// Inspect this window's last negotiated color configuration.
3104    pub fn color_status(&self) -> crate::WindowColorStatus {
3105        self.platform_window.color_status()
3106    }
3107
3108    /// Sets the window background appearance. Native Metal wide-SDR mode requires
3109    /// opacity: disable it before requesting transparency. While it is enabled,
3110    /// transparent requests preserve the opaque window and emit a warning.
3111    pub fn set_background_appearance(&self, background_appearance: WindowBackgroundAppearance) {
3112        self.platform_window
3113            .set_background_appearance(background_appearance);
3114    }
3115
3116    /// Mark the window as dirty at the platform level.
3117    pub fn set_window_edited(&mut self, edited: bool) {
3118        self.platform_window.set_edited(edited);
3119    }
3120
3121    /// Set the path of the file this window represents.
3122    /// On macOS, this sets the window's accessibility document property (AXDocument).
3123    pub fn set_document_path(&self, path: Option<&std::path::Path>) {
3124        self.platform_window.set_document_path(path);
3125    }
3126
3127    /// Determine the display on which the window is visible.
3128    pub fn display(&self, cx: &App) -> Option<Rc<dyn PlatformDisplay>> {
3129        cx.platform
3130            .displays()
3131            .into_iter()
3132            .find(|display| Some(display.id()) == self.display_id)
3133    }
3134
3135    /// Show the platform character palette.
3136    pub fn show_character_palette(&self) {
3137        self.platform_window.show_character_palette();
3138    }
3139
3140    /// The scale factor of the display associated with the window. For example, it could
3141    /// return 2.0 for a "retina" display, indicating that each logical pixel should actually
3142    /// be rendered as two pixels on screen.
3143    pub fn scale_factor(&self) -> f32 {
3144        self.scale_factor
3145    }
3146
3147    /// Overrides the display scale factor for tests.
3148    #[cfg(any(test, feature = "test-support"))]
3149    pub fn set_scale_factor(&mut self, scale_factor: f32) {
3150        self.scale_factor = scale_factor;
3151        self.refresh();
3152    }
3153
3154    /// 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 rem_size(&self) -> Pixels {
3157        self.rem_size_override_stack
3158            .last()
3159            .copied()
3160            .unwrap_or(self.rem_size)
3161    }
3162
3163    /// Sets the size of an em for the base font of the application. Adjusting this value allows the
3164    /// UI to scale, just like zooming a web page.
3165    pub fn set_rem_size(&mut self, rem_size: impl Into<Pixels>) {
3166        self.rem_size = rem_size.into();
3167    }
3168
3169    /// Acquire a globally unique identifier for the given ElementId.
3170    /// Only valid for the duration of the provided closure.
3171    pub fn with_global_id<R>(
3172        &mut self,
3173        element_id: ElementId,
3174        f: impl FnOnce(&GlobalElementId, &mut Self) -> R,
3175    ) -> R {
3176        self.with_id(element_id, |this| {
3177            let global_id = this.element_id_stack.global_id();
3178
3179            f(&global_id, this)
3180        })
3181    }
3182
3183    /// Calls the provided closure with the element ID pushed on the stack.
3184    #[inline]
3185    pub fn with_id<R>(
3186        &mut self,
3187        element_id: impl Into<ElementId>,
3188        f: impl FnOnce(&mut Self) -> R,
3189    ) -> R {
3190        self.element_id_stack.push(element_id.into());
3191        let result = f(self);
3192        self.element_id_stack.pop();
3193        result
3194    }
3195
3196    /// Executes the provided function with the specified rem size.
3197    ///
3198    /// This method must only be called as part of element drawing.
3199    // This function is called in a highly recursive manner in editor
3200    // prepainting, make sure its inlined to reduce the stack burden
3201    #[inline]
3202    pub fn with_rem_size<F, R>(&mut self, rem_size: Option<impl Into<Pixels>>, f: F) -> R
3203    where
3204        F: FnOnce(&mut Self) -> R,
3205    {
3206        self.invalidator.debug_assert_paint_or_prepaint();
3207
3208        if let Some(rem_size) = rem_size {
3209            self.rem_size_override_stack.push(rem_size.into());
3210            let result = f(self);
3211            self.rem_size_override_stack.pop();
3212            result
3213        } else {
3214            f(self)
3215        }
3216    }
3217
3218    /// The line height associated with the current text style.
3219    pub fn line_height(&self) -> Pixels {
3220        self.text_style().line_height_in_pixels(self.rem_size())
3221    }
3222
3223    /// Rounds a logical value to the nearest device pixel.
3224    #[inline]
3225    pub fn pixel_snap(&self, value: Pixels) -> Pixels {
3226        px(round_to_device_pixel(value.0, self.scale_factor()) / self.scale_factor())
3227    }
3228
3229    /// f64 variant of [`Self::pixel_snap`].
3230    #[inline]
3231    pub fn pixel_snap_f64(&self, value: f64) -> f64 {
3232        let scale_factor = f64::from(self.scale_factor());
3233        round_half_toward_zero_f64(value * scale_factor) / scale_factor
3234    }
3235
3236    /// Snaps a bounds' origin and size to the nearest device pixel.
3237    #[inline]
3238    pub fn pixel_snap_bounds(&self, bounds: Bounds<Pixels>) -> Bounds<Pixels> {
3239        bounds.map(|c| self.pixel_snap(c))
3240    }
3241
3242    /// Snaps a point's coordinates to the nearest device pixel.
3243    #[inline]
3244    pub fn pixel_snap_point(&self, position: Point<Pixels>) -> Point<Pixels> {
3245        position.map(|c| self.pixel_snap(c))
3246    }
3247
3248    /// Returns the snapped device-space bounds used to paint an underline.
3249    pub fn underline_bounds(
3250        &self,
3251        origin: Point<Pixels>,
3252        width: Pixels,
3253        style: &UnderlineStyle,
3254    ) -> Bounds<ScaledPixels> {
3255        let scale_factor = self.scale_factor();
3256        let thickness = self.snap_stroke(style.thickness);
3257        let height = if style.wavy {
3258            ScaledPixels(thickness.0 * 3.)
3259        } else {
3260            thickness
3261        };
3262        Bounds {
3263            origin: origin.map(|c| ScaledPixels(round_to_device_pixel(c.0, scale_factor))),
3264            size: size(self.snap_stroke(width), height),
3265        }
3266    }
3267
3268    /// Paints an underline excluding absolute device-space horizontal spans.
3269    pub fn paint_underline_with_exclusions(
3270        &mut self,
3271        origin: Point<Pixels>,
3272        width: Pixels,
3273        style: &UnderlineStyle,
3274        exclusions: &[Range<ScaledPixels>],
3275    ) {
3276        self.invalidator.debug_assert_paint();
3277        let underline = self.underline(origin, width, style);
3278        if exclusions.is_empty() {
3279            self.next_frame.scene.insert_primitive(underline);
3280            return;
3281        }
3282
3283        let bounds = underline.bounds.intersect(&underline.content_mask.bounds);
3284        if bounds.is_empty() {
3285            return;
3286        }
3287
3288        let mut exclusions = exclusions
3289            .iter()
3290            .filter_map(|span| {
3291                let start = span.start.max(bounds.left());
3292                let end = span.end.min(bounds.right());
3293                (start < end).then_some(start..end)
3294            })
3295            .collect::<SmallVec<[_; 4]>>();
3296        if exclusions.is_empty() {
3297            self.next_frame.scene.insert_primitive(underline);
3298            return;
3299        }
3300        exclusions.sort_unstable_by_key(|span| span.start);
3301
3302        let mut paint_span = |start, end| {
3303            self.next_frame.scene.insert_primitive(Underline {
3304                content_mask: ContentMask {
3305                    bounds: Bounds::from_corners(
3306                        point(start, bounds.top()),
3307                        point(end, bounds.bottom()),
3308                    ),
3309                },
3310                ..underline
3311            });
3312        };
3313        let mut start = bounds.left();
3314        for exclusion in exclusions {
3315            if start < exclusion.start {
3316                paint_span(start, exclusion.start);
3317            }
3318            start = start.max(exclusion.end);
3319        }
3320        if start < bounds.right() {
3321            paint_span(start, bounds.right());
3322        }
3323    }
3324
3325    fn underline(&self, origin: Point<Pixels>, width: Pixels, style: &UnderlineStyle) -> Underline {
3326        Underline {
3327            order: 0,
3328            pad: 0,
3329            bounds: self.underline_bounds(origin, width, style),
3330            content_mask: self.snapped_content_mask(),
3331            color: style
3332                .color
3333                .unwrap_or_default()
3334                .opacity(self.element_opacity()),
3335            thickness: self.snap_stroke(style.thickness),
3336            wavy: style.wavy.into(),
3337        }
3338    }
3339
3340    #[inline]
3341    fn snap_bounds(&self, bounds: Bounds<Pixels>) -> Bounds<ScaledPixels> {
3342        let scale_factor = self.scale_factor();
3343        let left = round_to_device_pixel(bounds.left().0, scale_factor);
3344        let top = round_to_device_pixel(bounds.top().0, scale_factor);
3345        let right = round_to_device_pixel(bounds.right().0, scale_factor).max(left);
3346        let bottom = round_to_device_pixel(bounds.bottom().0, scale_factor).max(top);
3347        Bounds::from_corners(
3348            point(ScaledPixels(left), ScaledPixels(top)),
3349            point(ScaledPixels(right), ScaledPixels(bottom)),
3350        )
3351    }
3352
3353    /// Rounds half-to-zero but clamps any non-zero input up to 1 dp so thin strokes do not disappear.
3354    #[inline]
3355    fn snap_stroke(&self, value: Pixels) -> ScaledPixels {
3356        ScaledPixels(round_stroke_to_device_pixel(value.0, self.scale_factor()))
3357    }
3358
3359    #[inline]
3360    fn snap_border_widths(&self, edges: Edges<Pixels>) -> Edges<ScaledPixels> {
3361        edges.map(|e| self.snap_stroke(*e))
3362    }
3363
3364    /// Floors the near edge and ceils the far edge, producing a strict superset of the raw region.
3365    #[inline]
3366    fn cover_bounds(&self, bounds: Bounds<Pixels>) -> Bounds<ScaledPixels> {
3367        let scale_factor = self.scale_factor();
3368        // Rounding a zero-width fractional clip outward can invent a pixel
3369        // outside a layer capture when the clipped glyph lies beyond its tile.
3370        if bounds.is_empty() {
3371            return Bounds::new(bounds.origin.scale(scale_factor), Size::default());
3372        }
3373        let left = floor_to_device_pixel(bounds.left().0, scale_factor);
3374        let top = floor_to_device_pixel(bounds.top().0, scale_factor);
3375        let right = ceil_to_device_pixel(bounds.right().0, scale_factor).max(left);
3376        let bottom = ceil_to_device_pixel(bounds.bottom().0, scale_factor).max(top);
3377        Bounds::from_corners(
3378            point(ScaledPixels(left), ScaledPixels(top)),
3379            point(ScaledPixels(right), ScaledPixels(bottom)),
3380        )
3381    }
3382
3383    #[inline]
3384    fn snapped_content_mask(&self) -> ContentMask<ScaledPixels> {
3385        ContentMask {
3386            bounds: self.cover_bounds(self.content_mask().bounds),
3387        }
3388    }
3389
3390    /// Call to prevent the default action of an event. Currently only used to prevent
3391    /// parent elements from becoming focused on mouse down.
3392    pub fn prevent_default(&mut self) {
3393        self.default_prevented = true;
3394    }
3395
3396    /// Obtain whether default has been prevented for the event currently being dispatched.
3397    pub fn default_prevented(&self) -> bool {
3398        self.default_prevented
3399    }
3400
3401    /// Determine whether the given action is available along the dispatch path to the currently focused element.
3402    pub fn is_action_available(&self, action: &dyn Action, cx: &App) -> bool {
3403        let node_id =
3404            self.focus_node_id_in_rendered_frame(self.focused(cx).map(|handle| handle.id));
3405        self.rendered_frame
3406            .dispatch_tree
3407            .is_action_available(action, node_id)
3408    }
3409
3410    /// Determine whether the given action is available along the dispatch path to the given focus_handle.
3411    pub fn is_action_available_in(&self, action: &dyn Action, focus_handle: &FocusHandle) -> bool {
3412        let node_id = self.focus_node_id_in_rendered_frame(Some(focus_handle.id));
3413        self.rendered_frame
3414            .dispatch_tree
3415            .is_action_available(action, node_id)
3416    }
3417
3418    /// The position of the mouse relative to the window.
3419    pub fn mouse_position(&self) -> Point<Pixels> {
3420        self.mouse_position
3421    }
3422
3423    /// Captures the pointer for the given hitbox. While captured, all mouse move and mouse up
3424    /// events will be routed to listeners that check this hitbox's `is_hovered` status,
3425    /// regardless of actual hit testing. This enables drag operations that continue
3426    /// even when the pointer moves outside the element's bounds.
3427    ///
3428    /// The capture is automatically released on mouse up.
3429    pub fn capture_pointer(&mut self, hitbox_id: HitboxId) {
3430        self.captured_hitbox = Some(hitbox_id);
3431    }
3432
3433    /// Releases any active pointer capture.
3434    pub fn release_pointer(&mut self) {
3435        self.captured_hitbox = None;
3436    }
3437
3438    /// Returns the hitbox that has captured the pointer, if any.
3439    pub fn captured_hitbox(&self) -> Option<HitboxId> {
3440        self.captured_hitbox
3441    }
3442
3443    /// Captures the current long press for the given entity.
3444    ///
3445    /// The capture is released when the gesture ends or is cancelled, or when
3446    /// a replacement touch begins. A listener must also call
3447    /// [`Self::prevent_default`] on the started event to claim the gesture.
3448    pub fn capture_long_press<T: 'static>(&mut self, entity: &Entity<T>) {
3449        self.long_press_capture = Some(entity.entity_id());
3450    }
3451
3452    /// Returns whether the given entity has captured the current long press.
3453    pub fn has_long_press_capture<T: 'static>(&self, entity: &Entity<T>) -> bool {
3454        self.long_press_capture == Some(entity.entity_id())
3455    }
3456
3457    /// The current state of the keyboard's modifiers
3458    pub fn modifiers(&self) -> Modifiers {
3459        self.modifiers
3460    }
3461
3462    /// Returns true if the last input event was keyboard-based (key press, tab navigation, etc.)
3463    /// This is used for focus-visible styling to show focus indicators only for keyboard navigation.
3464    pub fn last_input_was_keyboard(&self) -> bool {
3465        self.last_input_modality == InputModality::Keyboard
3466    }
3467
3468    pub(crate) fn last_input_was_touch(&self) -> bool {
3469        self.last_input_modality == InputModality::Touch
3470    }
3471
3472    /// The current state of the keyboard's capslock
3473    pub fn capslock(&self) -> Capslock {
3474        self.capslock
3475    }
3476
3477    /// Produces a new frame and assigns it to `rendered_frame`. To actually show
3478    /// the contents of the new [`Scene`], use [`Self::present`].
3479    #[profiling::function]
3480    pub fn draw(&mut self, cx: &mut App) -> ArenaClearNeeded {
3481        // Drain every draw in profiler builds so a previous frame's
3482        // first-invalidation timestamp can't be attributed to this one.
3483        #[cfg(feature = "profiler")]
3484        let frame_dirty = self.invalidator.take_frame_dirty();
3485        #[cfg(feature = "profiler")]
3486        self.window_profiler.begin_draw();
3487
3488        // Set up the per-App arena for element allocation during this draw.
3489        // This ensures that multiple test Apps have isolated arenas.
3490        let arena_scope = ElementArenaScope::enter(&cx.element_arena);
3491
3492        if self.platform_window.prepare_frame() {
3493            self.refresh();
3494        }
3495        self.invalidate_entities();
3496        cx.entities.clear_accessed();
3497        debug_assert!(self.rendered_entity_stack.is_empty());
3498        self.invalidator.set_dirty(false);
3499        self.requested_autoscroll = None;
3500
3501        // Restore the previously-used input handler.
3502        // Place it back into a None slot (left by a previous .take()) so that
3503        // cached paint_range indices in reuse_paint find the handler at the
3504        // expected position.
3505        if let Some(input_handler) = self.platform_window.take_input_handler() {
3506            if let Some(slot) = self
3507                .rendered_frame
3508                .input_handlers
3509                .iter_mut()
3510                .rev()
3511                .find(|h| h.is_none())
3512            {
3513                *slot = Some(input_handler);
3514            } else {
3515                self.rendered_frame.input_handlers.push(Some(input_handler));
3516            }
3517        }
3518        if !cx.mode.skip_drawing() {
3519            self.draw_roots(cx);
3520            #[cfg(feature = "profiler")]
3521            {
3522                let viewport_size = self.viewport_size;
3523                let scale_factor = self.scale_factor();
3524                self.debug_frame_overlay.paint(
3525                    &mut self.next_frame.scene,
3526                    viewport_size,
3527                    scale_factor,
3528                );
3529            }
3530        }
3531        self.dirty_views.clear();
3532        self.next_frame.window_active = self.active.get();
3533
3534        // Register requested input handler with the platform window.
3535        // Use .take() instead of .pop() to preserve Vec length, so that cached
3536        // paint_range indices remain valid for reuse_paint on the next frame.
3537        // Search backwards to find the last Some entry, since reuse_paint may
3538        // have copied None slots from the previous frame. (Fixes #50456)
3539        let focused_text_input_active = if let Some(mut input_handler) = self
3540            .next_frame
3541            .input_handlers
3542            .iter_mut()
3543            .rev()
3544            .find_map(|h| h.take())
3545        {
3546            let accepts_text_input = input_handler.accepts_text_input(self, cx);
3547            self.platform_window.set_input_handler(input_handler);
3548            accepts_text_input
3549        } else {
3550            false
3551        };
3552        self.apply_text_input_configuration(cx);
3553        if focused_text_input_active != self.focused_text_input_active {
3554            self.focused_text_input_active = focused_text_input_active;
3555            self.platform_window
3556                .text_input_state_changed(if focused_text_input_active {
3557                    TextInputStateChange::FocusGained
3558                } else {
3559                    TextInputStateChange::FocusLost
3560                });
3561        }
3562
3563        self.layout_engine.as_mut().unwrap().clear();
3564        self.text_system().finish_frame();
3565        self.next_frame.finish(&mut self.rendered_frame);
3566
3567        self.invalidator.set_phase(DrawPhase::Focus);
3568        let previous_focus_path = self.rendered_frame.focus_path();
3569        let previous_window_active = self.rendered_frame.window_active;
3570        mem::swap(&mut self.rendered_frame, &mut self.next_frame);
3571        self.next_frame.clear();
3572        let current_focus_path = self.rendered_frame.focus_path();
3573        let current_window_active = self.rendered_frame.window_active;
3574        let mut focus_before_listeners = self.focus;
3575
3576        if previous_focus_path != current_focus_path
3577            || previous_window_active != current_window_active
3578        {
3579            if !previous_focus_path.is_empty() && current_focus_path.is_empty() {
3580                self.focus_lost_path = previous_focus_path.clone();
3581                self.focus_lost_listeners
3582                    .clone()
3583                    .retain(&(), |listener| listener(self, cx));
3584                self.focus_lost_path = SmallVec::new();
3585                // The focus-lost fallback (e.g. a workspace refocusing itself) may target
3586                // an element that isn't part of the element tree, in which case scheduling
3587                // a redraw below would dispatch focus-lost again, looping forever. Only
3588                // track focus movement caused by the focus listeners.
3589                focus_before_listeners = self.focus;
3590            }
3591
3592            let event = WindowFocusEvent {
3593                previous_focus_path: if previous_window_active {
3594                    previous_focus_path
3595                } else {
3596                    Default::default()
3597                },
3598                current_focus_path: if current_window_active {
3599                    current_focus_path
3600                } else {
3601                    Default::default()
3602                },
3603            };
3604            self.focus_listeners
3605                .clone()
3606                .retain(&(), |listener| listener(&event, self, cx));
3607        }
3608
3609        debug_assert!(self.rendered_entity_stack.is_empty());
3610        self.record_entities_accessed(cx);
3611        self.reset_cursor_style(cx);
3612        self.refreshing = false;
3613        self.invalidator.set_phase(DrawPhase::None);
3614        // Focus listeners may move focus (e.g. a dock forwarding focus to its active
3615        // panel). `Window::focus` suppresses `refresh` while a draw is in progress, so
3616        // schedule another frame here to render the new focus state and dispatch the
3617        // resulting focus events.
3618        if self.focus != focus_before_listeners {
3619            self.refresh();
3620        }
3621        self.needs_present.set(true);
3622
3623        #[cfg(feature = "profiler")]
3624        {
3625            self.window_profiler
3626                .set_refresh_interval(self.refresh_interval(cx));
3627            let draw_duration = self
3628                .window_profiler
3629                .end_draw(frame_dirty.dirty_at, frame_dirty.invalidations);
3630            self.debug_frame_overlay.record_frame(draw_duration);
3631        }
3632
3633        // Exit the scope to obtain the arena-clear token this draw owes; the
3634        // scope's teardown itself happens in `ElementArenaScope::drop`.
3635        arena_scope.exit(&cx.element_arena)
3636    }
3637
3638    fn record_entities_accessed(&mut self, cx: &mut App) {
3639        let mut entities_ref = cx.entities.accessed_entities.get_mut();
3640        let mut entities = mem::take(entities_ref.deref_mut());
3641        let handle = self.handle;
3642        cx.record_entities_accessed(
3643            handle,
3644            // Try moving window invalidator into the Window
3645            self.invalidator.clone(),
3646            &entities,
3647        );
3648        let mut entities_ref = cx.entities.accessed_entities.get_mut();
3649        mem::swap(&mut entities, entities_ref.deref_mut());
3650    }
3651
3652    fn invalidate_entities(&mut self) {
3653        let mut views = self.invalidator.take_views();
3654        for entity in views.drain() {
3655            self.mark_view_dirty(entity);
3656        }
3657        self.invalidator.replace_views(views);
3658    }
3659
3660    /// Submit the recorded scene on this window's actual native renderer.
3661    /// Native lifecycle tests use this instead of presentation/readback waits.
3662    #[cfg(any(test, feature = "test-support"))]
3663    pub fn submit_frame_for_validation(&self) -> anyhow::Result<()> {
3664        self.platform_window
3665            .submit_scene_for_validation(&self.rendered_frame.scene)
3666    }
3667
3668    #[profiling::function]
3669    fn present(&mut self) {
3670        #[cfg(feature = "profiler")]
3671        let _foreground_turn = profiler::journal::foreground_turn();
3672        #[cfg(feature = "profiler")]
3673        let present_start = Instant::now();
3674        self.platform_window.draw(&self.rendered_frame.scene);
3675        #[cfg(feature = "profiler")]
3676        self.window_profiler.record_present(
3677            present_start,
3678            Instant::now(),
3679            self.active.get(),
3680            !self.next_frame_callbacks.borrow().is_empty(),
3681        );
3682        self.needs_present.set(false);
3683        profiling::finish_frame!();
3684    }
3685
3686    /// Presents the most recently drawn frame if it hasn't been presented yet.
3687    #[cfg(all(test, feature = "profiler"))]
3688    pub fn present_if_needed(&mut self) {
3689        if self.needs_present.get() {
3690            self.present();
3691        }
3692    }
3693
3694    /// Returns a snapshot of the current input-latency histograms.
3695    #[cfg(feature = "profiler")]
3696    pub fn input_latency_snapshot(&self) -> profiler::InputLatencySnapshot {
3697        self.window_profiler.input_latency_snapshot()
3698    }
3699
3700    /// Returns a snapshot of the current frame-duration histograms.
3701    #[cfg(feature = "profiler")]
3702    pub fn frame_duration_snapshot(&self) -> profiler::FrameDurationSnapshot {
3703        self.window_profiler.frame_duration_snapshot()
3704    }
3705
3706    /// Returns the current mode of the debug frame overlay.
3707    #[cfg(feature = "profiler")]
3708    pub fn debug_frame_overlay_mode(&self) -> DebugFrameOverlayMode {
3709        self.debug_frame_overlay.mode()
3710    }
3711
3712    /// Sets the mode of the debug frame overlay and schedules a redraw.
3713    #[cfg(feature = "profiler")]
3714    pub fn set_debug_frame_overlay_mode(&mut self, mode: DebugFrameOverlayMode) {
3715        self.debug_frame_overlay.set_mode(mode);
3716        self.refresh();
3717    }
3718
3719    /// Advances the debug frame overlay through its hidden, frame-time-only,
3720    /// and detailed modes.
3721    #[cfg(feature = "profiler")]
3722    pub fn cycle_debug_frame_overlay_mode(&mut self) {
3723        self.set_debug_frame_overlay_mode(self.debug_frame_overlay.mode().next());
3724    }
3725
3726    /// Clears the debug frame overlay's frame-time statistics, except for the
3727    /// total frame count, and schedules a redraw.
3728    #[cfg(feature = "profiler")]
3729    pub fn reset_debug_frame_overlay_stats(&mut self) {
3730        self.debug_frame_overlay.reset_stats();
3731        self.refresh();
3732    }
3733
3734    fn draw_roots(&mut self, cx: &mut App) {
3735        self.invalidator.set_phase(DrawPhase::Prepaint);
3736        self.tooltip_bounds.take();
3737
3738        self.a11y.sync_active_flag();
3739        if self.a11y.is_active() {
3740            self.a11y.begin_frame();
3741        }
3742
3743        let _inspector_width: Pixels = rems(30.0).to_pixels(self.rem_size());
3744        let root_size = {
3745            #[cfg(debug_assertions)]
3746            {
3747                if self.inspector.is_some() {
3748                    let mut size = self.viewport_size;
3749                    size.width = (size.width - _inspector_width).max(px(0.0));
3750                    size
3751                } else {
3752                    self.viewport_size
3753                }
3754            }
3755            #[cfg(not(debug_assertions))]
3756            {
3757                self.viewport_size
3758            }
3759        };
3760
3761        // Layout all root elements. Like the root element on the web, which
3762        // stretches to fill the viewport unless explicitly sized, window roots
3763        // fill the window when their size is `auto`.
3764        let scale_factor = self.scale_factor();
3765        #[cfg(feature = "profiler")]
3766        let request_layout_start = Instant::now();
3767        let mut root_element = self.root.as_ref().unwrap().clone().into_any_element();
3768        let root_layout_id = root_element.request_layout(self, cx);
3769        #[cfg(feature = "profiler")]
3770        let prepaint_start = Instant::now();
3771        self.layout_engine
3772            .as_mut()
3773            .unwrap()
3774            .stretch_auto_size_to_fill(root_layout_id, root_size, scale_factor);
3775        root_element.prepaint_as_root(Point::default(), root_size.into(), self, cx);
3776
3777        #[cfg(debug_assertions)]
3778        let inspector_element = self.prepaint_inspector(_inspector_width, cx);
3779
3780        self.prepaint_deferred_draws(cx);
3781
3782        let mut prompt_element = None;
3783        let mut active_drag_element = None;
3784        let mut tooltip_element = None;
3785        if let Some(prompt) = self.prompt.take() {
3786            let mut element = prompt.view.any_view().into_any_element();
3787            let prompt_layout_id = element.request_layout(self, cx);
3788            self.layout_engine
3789                .as_mut()
3790                .unwrap()
3791                .stretch_auto_size_to_fill(prompt_layout_id, root_size, scale_factor);
3792            element.prepaint_as_root(Point::default(), root_size.into(), self, cx);
3793            prompt_element = Some(element);
3794            self.prompt = Some(prompt);
3795        } else if let Some(active_drag) = cx.active_drag.take() {
3796            let mut element = active_drag.view.clone().into_any_element();
3797            let offset = self.mouse_position() - active_drag.cursor_offset;
3798            element.prepaint_as_root(offset, AvailableSpace::min_size(), self, cx);
3799            active_drag_element = Some(element);
3800            cx.active_drag = Some(active_drag);
3801        } else {
3802            tooltip_element = self.prepaint_tooltip(cx);
3803        }
3804
3805        self.mouse_hit_test = self.next_frame.hit_test(self.mouse_position);
3806
3807        // Now actually paint the elements.
3808        #[cfg(feature = "profiler")]
3809        let paint_start = Instant::now();
3810        self.invalidator.set_phase(DrawPhase::Paint);
3811        root_element.paint(self, cx);
3812
3813        #[cfg(debug_assertions)]
3814        self.paint_inspector(inspector_element, cx);
3815
3816        self.paint_deferred_draws(cx);
3817
3818        if let Some(mut prompt_element) = prompt_element {
3819            prompt_element.paint(self, cx);
3820        } else if let Some(mut drag_element) = active_drag_element {
3821            drag_element.paint(self, cx);
3822        } else if let Some(mut tooltip_element) = tooltip_element {
3823            tooltip_element.paint(self, cx);
3824        }
3825
3826        #[cfg(debug_assertions)]
3827        self.paint_inspector_hitbox(cx);
3828
3829        #[cfg(feature = "profiler")]
3830        self.window_profiler
3831            .record_draw_phases(profiler::DrawPhases {
3832                request_layout: prepaint_start.duration_since(request_layout_start),
3833                prepaint: paint_start.duration_since(prepaint_start),
3834                paint: Instant::now().duration_since(paint_start),
3835            });
3836
3837        // a11y may have been activated/deactivated halfway through the frame
3838        let a11y_active_start_of_frame = self.a11y.is_active();
3839        self.a11y.sync_active_flag();
3840        let a11y_active_end_of_frame = self.a11y.is_active();
3841
3842        let should_send_a11y_update = a11y_active_start_of_frame && a11y_active_end_of_frame;
3843
3844        if a11y_active_start_of_frame {
3845            // Harvest frame metadata for the debug dump while the live window
3846            // and frame are still in scope.
3847            let frame_info = crate::window::a11y::debug::FrameDebugInfo {
3848                viewport_size: self.viewport_size,
3849                scale_factor: self.scale_factor,
3850                tab_stop_count: self.next_frame.tab_stops.tab_stop_count(),
3851            };
3852            // clear the builder state regardless
3853            let tree_update = self.a11y.end_frame(frame_info);
3854
3855            if should_send_a11y_update {
3856                log::debug!(
3857                    "Sending a11y tree update: {} nodes",
3858                    tree_update.nodes.len()
3859                );
3860                self.platform_window.a11y_tree_update(tree_update);
3861            }
3862        }
3863    }
3864
3865    fn prepaint_tooltip(&mut self, cx: &mut App) -> Option<AnyElement> {
3866        // Use indexing instead of iteration to avoid borrowing self for the duration of the loop.
3867        for tooltip_request_index in (0..self.next_frame.tooltip_requests.len()).rev() {
3868            let Some(Some(tooltip_request)) = self
3869                .next_frame
3870                .tooltip_requests
3871                .get(tooltip_request_index)
3872                .cloned()
3873            else {
3874                log::error!("Unexpectedly absent TooltipRequest");
3875                continue;
3876            };
3877            let mut element = tooltip_request.tooltip.view.clone().into_any_element();
3878            let mouse_position = tooltip_request.tooltip.mouse_position;
3879            let tooltip_size = element.layout_as_root(AvailableSpace::min_size(), self, cx);
3880
3881            let mut tooltip_bounds =
3882                Bounds::new(mouse_position + point(px(1.), px(1.)), tooltip_size);
3883            let window_bounds = Bounds {
3884                origin: Point::default(),
3885                size: self.viewport_size(),
3886            };
3887
3888            if tooltip_bounds.right() > window_bounds.right() {
3889                let new_x = mouse_position.x - tooltip_bounds.size.width - px(1.);
3890                if new_x >= Pixels::ZERO {
3891                    tooltip_bounds.origin.x = new_x;
3892                } else {
3893                    tooltip_bounds.origin.x = cmp::max(
3894                        Pixels::ZERO,
3895                        tooltip_bounds.origin.x - tooltip_bounds.right() - window_bounds.right(),
3896                    );
3897                }
3898            }
3899
3900            if tooltip_bounds.bottom() > window_bounds.bottom() {
3901                let new_y = mouse_position.y - tooltip_bounds.size.height - px(1.);
3902                if new_y >= Pixels::ZERO {
3903                    tooltip_bounds.origin.y = new_y;
3904                } else {
3905                    tooltip_bounds.origin.y = cmp::max(
3906                        Pixels::ZERO,
3907                        tooltip_bounds.origin.y - tooltip_bounds.bottom() - window_bounds.bottom(),
3908                    );
3909                }
3910            }
3911
3912            // It's possible for an element to have an active tooltip while not being painted (e.g.
3913            // via the `visible_on_hover` method). Since mouse listeners are not active in this
3914            // case, instead update the tooltip's visibility here.
3915            let is_visible =
3916                (tooltip_request.tooltip.check_visible_and_update)(tooltip_bounds, self, cx);
3917            if !is_visible {
3918                continue;
3919            }
3920
3921            self.with_absolute_element_offset(tooltip_bounds.origin, |window| {
3922                element.prepaint(window, cx)
3923            });
3924
3925            self.tooltip_bounds = Some(TooltipBounds {
3926                id: tooltip_request.id,
3927                bounds: tooltip_bounds,
3928            });
3929            return Some(element);
3930        }
3931        None
3932    }
3933
3934    fn prepaint_deferred_draws(&mut self, cx: &mut App) {
3935        assert_eq!(self.element_id_stack.len(), 0);
3936
3937        // Process deferred draws in multiple rounds to support nesting.
3938        // Each round processes all current deferred draws, which may push new ones.
3939        //
3940        // The draws are processed in place rather than being moved out of
3941        // `next_frame.deferred_draws`: `prepaint_index` snapshots that vector's
3942        // length, so any prepaint range recorded during a round (view caches,
3943        // nested deferred draws) must index the same vector `reuse_prepaint`
3944        // slices on the next frame. Moving the draws out and re-appending them
3945        // shifts the indices of nested draws, causing reused subtrees to graft
3946        // the wrong deferred draws and panic in the dispatch tree.
3947        let mut round_start = 0;
3948        let mut depth = 0;
3949        loop {
3950            let round_end = self.next_frame.deferred_draws.len();
3951            if round_start == round_end {
3952                break;
3953            }
3954            // Limit maximum nesting depth to prevent infinite loops.
3955            assert!(depth < 10, "Exceeded maximum (10) deferred depth");
3956            depth += 1;
3957
3958            // Sort this round by priority.
3959            let mut traversal_order = (round_start..round_end).collect::<SmallVec<[usize; 8]>>();
3960            traversal_order.sort_by_key(|ix| self.next_frame.deferred_draws[*ix].priority);
3961
3962            for deferred_draw_ix in traversal_order {
3963                let (element, parent_node, current_view, rem_size, absolute_offset, prepaint_range) = {
3964                    let deferred_draw = &mut self.next_frame.deferred_draws[deferred_draw_ix];
3965                    self.element_id_stack
3966                        .clone_from(&deferred_draw.element_id_stack);
3967                    self.text_style_stack
3968                        .clone_from(&deferred_draw.text_style_stack);
3969                    self.glyph_brush_stack
3970                        .clone_from(&deferred_draw.glyph_brush_stack);
3971                    (
3972                        deferred_draw.element.take(),
3973                        deferred_draw.parent_node,
3974                        deferred_draw.current_view,
3975                        deferred_draw.rem_size,
3976                        deferred_draw.absolute_offset,
3977                        deferred_draw.prepaint_range.clone(),
3978                    )
3979                };
3980                self.next_frame.dispatch_tree.set_active_node(parent_node);
3981
3982                let prepaint_start = self.prepaint_index();
3983                if let Some(mut element) = element {
3984                    self.with_rendered_view(current_view, |window| {
3985                        window.with_rem_size(Some(rem_size), |window| {
3986                            window.with_absolute_element_offset(absolute_offset, |window| {
3987                                element.prepaint(window, cx);
3988                            });
3989                        });
3990                    });
3991                    self.next_frame.deferred_draws[deferred_draw_ix].element = Some(element);
3992                } else {
3993                    self.reuse_prepaint(prepaint_range);
3994                }
3995                let prepaint_end = self.prepaint_index();
3996                self.next_frame.deferred_draws[deferred_draw_ix].prepaint_range =
3997                    prepaint_start..prepaint_end;
3998            }
3999
4000            self.element_id_stack.clear();
4001            self.text_style_stack.clear();
4002            self.glyph_brush_stack.clear();
4003            round_start = round_end;
4004        }
4005    }
4006
4007    fn paint_deferred_draws(&mut self, cx: &mut App) {
4008        assert_eq!(self.element_id_stack.len(), 0);
4009
4010        // Paint all deferred draws in priority order.
4011        // Since prepaint has already processed nested deferreds, we just paint them all.
4012        if self.next_frame.deferred_draws.len() == 0 {
4013            return;
4014        }
4015
4016        let traversal_order = self.deferred_draw_traversal_order();
4017        let mut deferred_draws = mem::take(&mut self.next_frame.deferred_draws);
4018        for deferred_draw_ix in traversal_order {
4019            let mut deferred_draw = &mut deferred_draws[deferred_draw_ix];
4020            self.element_id_stack
4021                .clone_from(&deferred_draw.element_id_stack);
4022            self.glyph_brush_stack
4023                .clone_from(&deferred_draw.glyph_brush_stack);
4024            self.next_frame
4025                .dispatch_tree
4026                .set_active_node(deferred_draw.parent_node);
4027
4028            let paint_start = self.paint_index();
4029            let content_mask = deferred_draw.content_mask;
4030            if let Some(element) = deferred_draw.element.as_mut() {
4031                self.with_rendered_view(deferred_draw.current_view, |window| {
4032                    window.with_content_mask(content_mask, |window| {
4033                        window.with_rem_size(Some(deferred_draw.rem_size), |window| {
4034                            element.paint(window, cx);
4035                        });
4036                    })
4037                })
4038            } else {
4039                self.reuse_paint(deferred_draw.paint_range.clone());
4040            }
4041            let paint_end = self.paint_index();
4042            deferred_draw.paint_range = paint_start..paint_end;
4043        }
4044        self.next_frame.deferred_draws = deferred_draws;
4045        self.element_id_stack.clear();
4046        self.glyph_brush_stack.clear();
4047    }
4048
4049    fn deferred_draw_traversal_order(&mut self) -> SmallVec<[usize; 8]> {
4050        let deferred_count = self.next_frame.deferred_draws.len();
4051        let mut sorted_indices = (0..deferred_count).collect::<SmallVec<[_; 8]>>();
4052        sorted_indices.sort_by_key(|ix| self.next_frame.deferred_draws[*ix].priority);
4053        sorted_indices
4054    }
4055
4056    pub(crate) fn prepaint_index(&self) -> PrepaintStateIndex {
4057        PrepaintStateIndex {
4058            hitboxes_index: self.next_frame.hitboxes.len(),
4059            tooltips_index: self.next_frame.tooltip_requests.len(),
4060            deferred_draws_index: self.next_frame.deferred_draws.len(),
4061            dispatch_tree_index: self.next_frame.dispatch_tree.len(),
4062            accessed_element_states_index: self.next_frame.accessed_element_states.len(),
4063            line_layout_index: self.text_system.layout_index(),
4064        }
4065    }
4066
4067    pub(crate) fn reuse_prepaint(&mut self, range: Range<PrepaintStateIndex>) {
4068        self.next_frame.hitboxes.extend(
4069            self.rendered_frame.hitboxes[range.start.hitboxes_index..range.end.hitboxes_index]
4070                .iter()
4071                .cloned(),
4072        );
4073        self.next_frame.tooltip_requests.extend(
4074            self.rendered_frame.tooltip_requests
4075                [range.start.tooltips_index..range.end.tooltips_index]
4076                .iter_mut()
4077                .map(|request| request.take()),
4078        );
4079        self.next_frame.accessed_element_states.extend(
4080            self.rendered_frame.accessed_element_states[range.start.accessed_element_states_index
4081                ..range.end.accessed_element_states_index]
4082                .iter()
4083                .map(|(id, type_id)| (id.clone(), *type_id)),
4084        );
4085        self.text_system
4086            .reuse_layouts(range.start.line_layout_index..range.end.line_layout_index);
4087
4088        let reused_subtree = self.next_frame.dispatch_tree.reuse_subtree(
4089            range.start.dispatch_tree_index..range.end.dispatch_tree_index,
4090            &mut self.rendered_frame.dispatch_tree,
4091            self.focus,
4092        );
4093
4094        if reused_subtree.contains_focus() {
4095            self.next_frame.focus = self.focus;
4096        }
4097
4098        self.next_frame.deferred_draws.extend(
4099            self.rendered_frame.deferred_draws
4100                [range.start.deferred_draws_index..range.end.deferred_draws_index]
4101                .iter()
4102                .map(|deferred_draw| DeferredDraw {
4103                    current_view: deferred_draw.current_view,
4104                    parent_node: reused_subtree.refresh_node_id(deferred_draw.parent_node),
4105                    element_id_stack: deferred_draw.element_id_stack.clone(),
4106                    text_style_stack: deferred_draw.text_style_stack.clone(),
4107                    glyph_brush_stack: deferred_draw.glyph_brush_stack.clone(),
4108                    content_mask: deferred_draw.content_mask,
4109                    rem_size: deferred_draw.rem_size,
4110                    priority: deferred_draw.priority,
4111                    element: None,
4112                    absolute_offset: deferred_draw.absolute_offset,
4113                    prepaint_range: deferred_draw.prepaint_range.clone(),
4114                    paint_range: deferred_draw.paint_range.clone(),
4115                }),
4116        );
4117    }
4118
4119    pub(crate) fn paint_index(&self) -> PaintIndex {
4120        PaintIndex {
4121            scene_index: self.next_frame.scene.len(),
4122            #[cfg(any(test, feature = "test-support"))]
4123            debug_bounds_index: self.next_frame.debug_bounds_records.len(),
4124            mouse_listeners_index: self.next_frame.mouse_listeners.len(),
4125            input_handlers_index: self.next_frame.input_handlers.len(),
4126            cursor_styles_index: self.next_frame.cursor_styles.len(),
4127            accessed_element_states_index: self.next_frame.accessed_element_states.len(),
4128            tab_handle_index: self.next_frame.tab_stops.paint_index(),
4129            line_layout_index: self.text_system.layout_index(),
4130        }
4131    }
4132
4133    pub(crate) fn reuse_paint(&mut self, range: Range<PaintIndex>) {
4134        // Cached elements still exist in the frame even when their paint methods don't run.
4135        #[cfg(any(test, feature = "test-support"))]
4136        for (selector, bounds) in &self.rendered_frame.debug_bounds_records
4137            [range.start.debug_bounds_index..range.end.debug_bounds_index]
4138        {
4139            self.next_frame
4140                .record_debug_bounds(selector.clone(), *bounds);
4141        }
4142        self.next_frame.cursor_styles.extend(
4143            self.rendered_frame.cursor_styles
4144                [range.start.cursor_styles_index..range.end.cursor_styles_index]
4145                .iter()
4146                .cloned(),
4147        );
4148        self.next_frame.input_handlers.extend(
4149            self.rendered_frame.input_handlers
4150                [range.start.input_handlers_index..range.end.input_handlers_index]
4151                .iter_mut()
4152                .map(|handler| handler.take()),
4153        );
4154        self.next_frame.mouse_listeners.extend(
4155            self.rendered_frame.mouse_listeners
4156                [range.start.mouse_listeners_index..range.end.mouse_listeners_index]
4157                .iter_mut()
4158                .map(|listener| listener.take()),
4159        );
4160        self.next_frame.accessed_element_states.extend(
4161            self.rendered_frame.accessed_element_states[range.start.accessed_element_states_index
4162                ..range.end.accessed_element_states_index]
4163                .iter()
4164                .map(|(id, type_id)| (id.clone(), *type_id)),
4165        );
4166        self.next_frame.tab_stops.replay(
4167            &self.rendered_frame.tab_stops.insertion_history
4168                [range.start.tab_handle_index..range.end.tab_handle_index],
4169        );
4170
4171        self.text_system
4172            .reuse_layouts(range.start.line_layout_index..range.end.line_layout_index);
4173        self.next_frame.scene.replay(
4174            range.start.scene_index..range.end.scene_index,
4175            &self.rendered_frame.scene,
4176        );
4177    }
4178
4179    /// Push a text style onto the stack, and call a function with that style active.
4180    /// Use [`Window::text_style`] to get the current, combined text style. This method
4181    /// should only be called as part of element drawing.
4182    pub fn with_text_style<F, R>(&mut self, style: Option<TextStyleRefinement>, f: F) -> R
4183    where
4184        F: FnOnce(&mut Self) -> R,
4185    {
4186        self.invalidator.debug_assert_paint_or_prepaint();
4187        if let Some(style) = style {
4188            self.text_style_stack.push(style);
4189            let result = f(self);
4190            self.text_style_stack.pop();
4191            result
4192        } else {
4193            f(self)
4194        }
4195    }
4196
4197    /// Updates the cursor style at the platform level. This method should only be called
4198    /// during the paint phase of element drawing.
4199    pub fn set_cursor_style(&mut self, style: CursorStyle, hitbox: &Hitbox) {
4200        self.invalidator.debug_assert_paint();
4201        self.next_frame.cursor_styles.push(CursorStyleRequest {
4202            hitbox_id: Some(hitbox.id),
4203            style,
4204        });
4205    }
4206
4207    /// Updates the cursor style for the entire window at the platform level. A cursor
4208    /// style using this method will have precedence over any cursor style set using
4209    /// `set_cursor_style`. This method should only be called during the paint
4210    /// phase of element drawing.
4211    pub fn set_window_cursor_style(&mut self, style: CursorStyle) {
4212        self.invalidator.debug_assert_paint();
4213        self.next_frame.cursor_styles.push(CursorStyleRequest {
4214            hitbox_id: None,
4215            style,
4216        })
4217    }
4218
4219    /// Sets a tooltip to be rendered for the upcoming frame. This method should only be called
4220    /// during the paint phase of element drawing.
4221    pub fn set_tooltip(&mut self, tooltip: AnyTooltip) -> TooltipId {
4222        self.invalidator.debug_assert_prepaint();
4223        let id = TooltipId(post_inc(&mut self.next_tooltip_id.0));
4224        self.next_frame
4225            .tooltip_requests
4226            .push(Some(TooltipRequest { id, tooltip }));
4227        id
4228    }
4229
4230    /// Invoke the given function with the given content mask after intersecting it
4231    /// with the current mask. This method should only be called during element drawing.
4232    // This function is called in a highly recursive manner in editor
4233    // prepainting, make sure its inlined to reduce the stack burden
4234    #[inline]
4235    pub fn with_content_mask<R>(
4236        &mut self,
4237        mask: Option<ContentMask<Pixels>>,
4238        f: impl FnOnce(&mut Self) -> R,
4239    ) -> R {
4240        self.invalidator.debug_assert_paint_or_prepaint();
4241        if let Some(mask) = mask {
4242            let mask = mask.intersect(&self.content_mask());
4243            self.content_mask_stack.push(mask);
4244            let result = f(self);
4245            self.content_mask_stack.pop();
4246            result
4247        } else {
4248            f(self)
4249        }
4250    }
4251
4252    /// Updates the global element offset relative to the current offset. This is used to implement
4253    /// scrolling. This method should only be called during the prepaint phase of element drawing.
4254    pub fn with_element_offset<R>(
4255        &mut self,
4256        offset: Point<Pixels>,
4257        f: impl FnOnce(&mut Self) -> R,
4258    ) -> R {
4259        self.invalidator.debug_assert_prepaint();
4260
4261        if offset.is_zero() {
4262            return f(self);
4263        };
4264
4265        let abs_offset = self.element_offset() + offset;
4266        self.with_absolute_element_offset(abs_offset, f)
4267    }
4268
4269    /// Updates the global element offset based on the given offset. This is used to implement
4270    /// drag handles and other manual painting of elements. This method should only be called during
4271    /// the prepaint phase of element drawing.
4272    pub fn with_absolute_element_offset<R>(
4273        &mut self,
4274        offset: Point<Pixels>,
4275        f: impl FnOnce(&mut Self) -> R,
4276    ) -> R {
4277        self.invalidator.debug_assert_prepaint();
4278        self.element_offset_stack.push(offset);
4279        let result = f(self);
4280        self.element_offset_stack.pop();
4281        result
4282    }
4283
4284    /// Multiply inherited opacity while painting or prepainting a custom element.
4285    pub fn with_element_opacity<R>(
4286        &mut self,
4287        opacity: Option<f32>,
4288        f: impl FnOnce(&mut Self) -> R,
4289    ) -> R {
4290        self.invalidator.debug_assert_paint_or_prepaint();
4291
4292        let Some(opacity) = opacity else {
4293            return f(self);
4294        };
4295
4296        let previous_opacity = self.element_opacity;
4297        self.element_opacity = previous_opacity * opacity;
4298        let result = f(self);
4299        self.element_opacity = previous_opacity;
4300        result
4301    }
4302
4303    /// Perform prepaint on child elements in a "retryable" manner, so that any side effects
4304    /// of prepaints can be discarded before prepainting again. This is used to support autoscroll
4305    /// where we need to prepaint children to detect the autoscroll bounds, then adjust the
4306    /// element offset and prepaint again. See [`crate::List`] for an example. This method should only be
4307    /// called during the prepaint phase of element drawing.
4308    pub fn transact<T, U>(&mut self, f: impl FnOnce(&mut Self) -> Result<T, U>) -> Result<T, U> {
4309        self.invalidator.debug_assert_prepaint();
4310        let index = self.prepaint_index();
4311        let result = f(self);
4312        if result.is_err() {
4313            self.next_frame.hitboxes.truncate(index.hitboxes_index);
4314            self.next_frame
4315                .tooltip_requests
4316                .truncate(index.tooltips_index);
4317            self.next_frame
4318                .deferred_draws
4319                .truncate(index.deferred_draws_index);
4320            self.next_frame
4321                .dispatch_tree
4322                .truncate(index.dispatch_tree_index);
4323            self.next_frame
4324                .accessed_element_states
4325                .truncate(index.accessed_element_states_index);
4326            self.text_system.truncate_layouts(index.line_layout_index);
4327        }
4328        result
4329    }
4330
4331    /// When you call this method during [`Element::prepaint`], containing elements will attempt to
4332    /// scroll to cause the specified bounds to become visible. When they decide to autoscroll, they will call
4333    /// [`Element::prepaint`] again with a new set of bounds. See [`crate::List`] for an example of an element
4334    /// that supports this method being called on the elements it contains. This method should only be
4335    /// called during the prepaint phase of element drawing.
4336    pub fn request_autoscroll(&mut self, bounds: Bounds<Pixels>) {
4337        self.invalidator.debug_assert_prepaint();
4338        self.requested_autoscroll = Some(bounds);
4339    }
4340
4341    /// This method can be called from a containing element such as [`crate::List`] to support the autoscroll behavior
4342    /// described in [`Self::request_autoscroll`].
4343    pub fn take_autoscroll(&mut self) -> Option<Bounds<Pixels>> {
4344        self.invalidator.debug_assert_prepaint();
4345        self.requested_autoscroll.take()
4346    }
4347
4348    /// Asynchronously load an asset, if the asset hasn't finished loading this will return None.
4349    /// Your view will be re-drawn once the asset has finished loading.
4350    ///
4351    /// Note that the multiple calls to this method will only result in one `Asset::load` call at a
4352    /// time.
4353    pub fn use_asset<A: Asset>(&mut self, source: &A::Source, cx: &mut App) -> Option<A::Output> {
4354        cx.asset_entry::<A>(source).use_by(self.current_view())
4355    }
4356
4357    /// Asynchronously load an asset, if the asset hasn't finished loading or doesn't exist this will return None.
4358    /// Your view will not be re-drawn once the asset has finished loading.
4359    ///
4360    /// Note that the multiple calls to this method will only result in one `Asset::load` call at a
4361    /// time.
4362    pub fn get_asset<A: Asset>(&mut self, source: &A::Source, cx: &mut App) -> Option<A::Output> {
4363        cx.fetch_asset::<A>(source)
4364    }
4365    /// Obtain the current element offset. This method should only be called during the
4366    /// prepaint phase of element drawing.
4367    pub fn element_offset(&self) -> Point<Pixels> {
4368        self.invalidator.debug_assert_prepaint();
4369        self.element_offset_stack
4370            .last()
4371            .copied()
4372            .unwrap_or_default()
4373    }
4374
4375    /// Obtain the current inherited element opacity during element drawing.
4376    /// Asynchronous producers can avoid requesting frames for fully hidden content.
4377    #[inline]
4378    pub fn element_opacity(&self) -> f32 {
4379        self.invalidator.debug_assert_paint_or_prepaint();
4380        self.element_opacity
4381    }
4382
4383    /// Obtain the current content mask. This method should only be called during element drawing.
4384    pub fn content_mask(&self) -> ContentMask<Pixels> {
4385        self.invalidator.debug_assert_paint_or_prepaint();
4386        self.content_mask_stack
4387            .last()
4388            .cloned()
4389            .unwrap_or_else(|| ContentMask {
4390                bounds: Bounds {
4391                    origin: Point::default(),
4392                    size: self.viewport_size,
4393                },
4394            })
4395    }
4396
4397    /// Provide elements in the called function with a new namespace in which their identifiers must be unique.
4398    /// This can be used within a custom element to distinguish multiple sets of child elements.
4399    pub fn with_element_namespace<R>(
4400        &mut self,
4401        element_id: impl Into<ElementId>,
4402        f: impl FnOnce(&mut Self) -> R,
4403    ) -> R {
4404        self.element_id_stack.push(element_id.into());
4405        let result = f(self);
4406        self.element_id_stack.pop();
4407        result
4408    }
4409
4410    /// Use a piece of state that exists as long this element is being rendered in consecutive frames.
4411    pub fn use_keyed_state<S: 'static>(
4412        &mut self,
4413        key: impl Into<ElementId>,
4414        cx: &mut App,
4415        init: impl FnOnce(&mut Self, &mut Context<S>) -> S,
4416    ) -> Entity<S> {
4417        let current_view = self.current_view();
4418        self.with_global_id(key.into(), |global_id, window| {
4419            window.with_element_state(global_id, |state: Option<Entity<S>>, window| {
4420                if let Some(state) = state {
4421                    (state.clone(), state)
4422                } else {
4423                    let new_state = cx.new(|cx| init(window, cx));
4424                    Self::observe_keyed_state(&new_state, current_view, cx);
4425                    (new_state.clone(), new_state)
4426                }
4427            })
4428        })
4429    }
4430
4431    /// Use a piece of state that exists as long this element is being rendered in consecutive frames, without needing to specify a key
4432    ///
4433    /// NOTE: This method uses the location of the caller to generate an ID for this state.
4434    ///       If this is not sufficient to identify your state (e.g. you're rendering a list item),
4435    ///       you can provide a custom ElementID using the `use_keyed_state` method.
4436    #[track_caller]
4437    pub fn use_state<S: 'static>(
4438        &mut self,
4439        cx: &mut App,
4440        init: impl FnOnce(&mut Self, &mut Context<S>) -> S,
4441    ) -> Entity<S> {
4442        self.use_keyed_state(
4443            ElementId::CodeLocation(*core::panic::Location::caller()),
4444            cx,
4445            init,
4446        )
4447    }
4448
4449    /// Updates or initializes state for an element with the given id that lives across multiple
4450    /// frames. If an element with this ID existed in the rendered frame, its state will be passed
4451    /// to the given closure. The state returned by the closure will be stored so it can be referenced
4452    /// when drawing the next frame. This method should only be called as part of element drawing.
4453    #[inline(always)]
4454    pub fn with_element_state<S, R>(
4455        &mut self,
4456        global_id: &GlobalElementId,
4457        f: impl FnOnce(Option<S>, &mut Self) -> (R, S),
4458    ) -> R
4459    where
4460        S: 'static,
4461    {
4462        self.invalidator.debug_assert_paint_or_prepaint();
4463
4464        let (key, state) = self.take_element_state(global_id, TypeId::of::<S>());
4465
4466        if let Some(any) = state {
4467            let ElementStateBox {
4468                inner,
4469                #[cfg(debug_assertions)]
4470                type_name,
4471            } = any;
4472            // Using the extra inner option to avoid needing to reallocate a new box.
4473            let mut state_box = inner
4474                .downcast::<Option<S>>()
4475                .map_err(|_| {
4476                    #[cfg(debug_assertions)]
4477                    {
4478                        anyhow::anyhow!(
4479                            "invalid element state type for id, requested {:?}, actual: {:?}",
4480                            std::any::type_name::<S>(),
4481                            type_name
4482                        )
4483                    }
4484
4485                    #[cfg(not(debug_assertions))]
4486                    {
4487                        anyhow::anyhow!(
4488                            "invalid element state type for id, requested {:?}",
4489                            std::any::type_name::<S>(),
4490                        )
4491                    }
4492                })
4493                .unwrap();
4494
4495            let state = state_box.take().expect(
4496                "reentrant call to with_element_state for the same state type and element id",
4497            );
4498            let (result, state) = f(Some(state), self);
4499            state_box.replace(state);
4500            self.insert_element_state(
4501                key,
4502                ElementStateBox {
4503                    inner: state_box,
4504                    #[cfg(debug_assertions)]
4505                    type_name,
4506                },
4507            );
4508            result
4509        } else {
4510            let (result, state) = f(None, self);
4511            self.insert_element_state(
4512                key,
4513                ElementStateBox {
4514                    inner: Box::new(Some(state)),
4515                    #[cfg(debug_assertions)]
4516                    type_name: std::any::type_name::<S>(),
4517                },
4518            );
4519            result
4520        }
4521    }
4522
4523    /// A variant of `with_element_state` that allows the element's id to be optional. This is a convenience
4524    /// method for elements where the element id may or may not be assigned. Prefer using `with_element_state`
4525    /// when the element is guaranteed to have an id.
4526    ///
4527    /// The first option means 'no ID provided'
4528    /// The second option means 'not yet initialized'
4529    pub fn with_optional_element_state<S, R>(
4530        &mut self,
4531        global_id: Option<&GlobalElementId>,
4532        f: impl FnOnce(Option<Option<S>>, &mut Self) -> (R, Option<S>),
4533    ) -> R
4534    where
4535        S: 'static,
4536    {
4537        self.invalidator.debug_assert_paint_or_prepaint();
4538
4539        if let Some(global_id) = global_id {
4540            self.with_element_state(global_id, |state, cx| {
4541                let (result, state) = f(Some(state), cx);
4542                let state =
4543                    state.expect("you must return some state when you pass some element id");
4544                (result, state)
4545            })
4546        } else {
4547            let (result, state) = f(None, self);
4548            debug_assert!(
4549                state.is_none(),
4550                "you must not return an element state when passing None for the global id"
4551            );
4552            result
4553        }
4554    }
4555
4556    /// Executes the given closure within the context of a tab group.
4557    #[inline]
4558    pub fn with_tab_group<R>(&mut self, index: Option<isize>, f: impl FnOnce(&mut Self) -> R) -> R {
4559        if let Some(index) = index {
4560            self.next_frame.tab_stops.begin_group(index);
4561            let result = f(self);
4562            self.next_frame.tab_stops.end_group();
4563            result
4564        } else {
4565            f(self)
4566        }
4567    }
4568
4569    /// Defers the drawing of the given element, scheduling it to be painted on top of the currently-drawn tree
4570    /// at a later time. The `priority` parameter determines the drawing order relative to other deferred elements,
4571    /// with higher values being drawn on top.
4572    ///
4573    /// When `content_mask` is provided, the deferred element will be clipped to that region during
4574    /// both prepaint and paint. When `None`, no additional clipping is applied.
4575    ///
4576    /// This method should only be called as part of the prepaint phase of element drawing.
4577    pub fn defer_draw(
4578        &mut self,
4579        element: AnyElement,
4580        absolute_offset: Point<Pixels>,
4581        priority: usize,
4582        content_mask: Option<ContentMask<Pixels>>,
4583    ) {
4584        self.invalidator.debug_assert_prepaint();
4585        let parent_node = self.next_frame.dispatch_tree.active_node_id().unwrap();
4586        self.next_frame.deferred_draws.push(DeferredDraw {
4587            current_view: self.current_view(),
4588            parent_node,
4589            element_id_stack: self.element_id_stack.clone(),
4590            text_style_stack: self.text_style_stack.clone(),
4591            glyph_brush_stack: self.glyph_brush_stack.clone(),
4592            content_mask,
4593            rem_size: self.rem_size(),
4594            priority,
4595            element: Some(element),
4596            absolute_offset,
4597            prepaint_range: PrepaintStateIndex::default()..PrepaintStateIndex::default(),
4598            paint_range: PaintIndex::default()..PaintIndex::default(),
4599        });
4600    }
4601
4602    /// Creates a new painting layer for the specified bounds. A "layer" is a batch
4603    /// of geometry that are non-overlapping and have the same draw order. This is typically used
4604    /// for performance reasons.
4605    ///
4606    /// This method should only be called as part of the paint phase of element drawing.
4607    pub fn paint_layer<R>(&mut self, bounds: Bounds<Pixels>, f: impl FnOnce(&mut Self) -> R) -> R {
4608        self.invalidator.debug_assert_paint();
4609
4610        let content_mask = self.content_mask();
4611        let clipped_bounds = bounds.intersect(&content_mask.bounds);
4612        if !clipped_bounds.is_empty() {
4613            self.next_frame
4614                .scene
4615                .push_layer(self.cover_bounds(clipped_bounds));
4616        }
4617
4618        let result = f(self);
4619
4620        if !clipped_bounds.is_empty() {
4621            self.next_frame.scene.pop_layer();
4622        }
4623
4624        result
4625    }
4626
4627    /// Paint the drop (non-inset) shadows from `shadows` into the scene at the current
4628    /// z-index. Inset shadows are skipped; paint those with [`Self::paint_inset_shadows`]
4629    /// after the element's background so they layer on top of the fill.
4630    ///
4631    /// This method should only be called as part of the paint phase of element drawing.
4632    pub fn paint_drop_shadows(
4633        &mut self,
4634        bounds: Bounds<Pixels>,
4635        corner_radii: Corners<Pixels>,
4636        shadows: &[BoxShadow],
4637    ) {
4638        self.invalidator.debug_assert_paint();
4639
4640        let scale_factor = self.scale_factor();
4641        let content_mask = self.snapped_content_mask();
4642        let opacity = self.element_opacity();
4643        let element_bounds = self.cover_bounds(bounds);
4644        let element_corner_radii = corner_radii.scale(scale_factor);
4645        for shadow in shadows {
4646            if shadow.inset {
4647                continue;
4648            }
4649            let shadow_bounds = (bounds + shadow.offset).dilate(shadow.spread_radius);
4650            self.next_frame.scene.insert_primitive(Shadow {
4651                order: 0,
4652                blur_radius: shadow.blur_radius.scale(scale_factor),
4653                bounds: self.cover_bounds(shadow_bounds),
4654                content_mask,
4655                corner_radii: corner_radii.scale(scale_factor),
4656                color: shadow.color.opacity(opacity),
4657                element_bounds,
4658                element_corner_radii,
4659                inset: 0,
4660                pad: 0,
4661            });
4662        }
4663    }
4664
4665    /// Paint the inset shadows from `shadows` into the scene at the current z-index. Should
4666    /// be called after the element's background so the shadow layers on top of the fill.
4667    /// Drop shadows are skipped; paint those with [`Self::paint_drop_shadows`] before the background.
4668    pub fn paint_inset_shadows(
4669        &mut self,
4670        bounds: Bounds<Pixels>,
4671        corner_radii: Corners<Pixels>,
4672        shadows: &[BoxShadow],
4673    ) {
4674        self.invalidator.debug_assert_paint();
4675
4676        let scale_factor = self.scale_factor();
4677        let content_mask = self.snapped_content_mask();
4678        let opacity = self.element_opacity();
4679        let element_bounds = self.cover_bounds(bounds);
4680        let element_corner_radii = corner_radii.scale(scale_factor);
4681        for shadow in shadows {
4682            if !shadow.inset {
4683                continue;
4684            }
4685            let hole = (bounds + shadow.offset).dilate(-shadow.spread_radius);
4686            // Clamp at zero so a large spread can't produce negative radii, which would
4687            // break the SDF in the shader.
4688            let zero = Pixels::ZERO;
4689            let hole_corner_radii = Corners {
4690                top_left: (corner_radii.top_left - shadow.spread_radius).max(zero),
4691                top_right: (corner_radii.top_right - shadow.spread_radius).max(zero),
4692                bottom_right: (corner_radii.bottom_right - shadow.spread_radius).max(zero),
4693                bottom_left: (corner_radii.bottom_left - shadow.spread_radius).max(zero),
4694            };
4695            self.next_frame.scene.insert_primitive(Shadow {
4696                order: 0,
4697                blur_radius: shadow.blur_radius.scale(scale_factor),
4698                bounds: self.cover_bounds(hole),
4699                content_mask,
4700                corner_radii: hole_corner_radii.scale(scale_factor),
4701                color: shadow.color.opacity(opacity),
4702                element_bounds,
4703                element_corner_radii,
4704                inset: 1,
4705                pad: 0,
4706            });
4707        }
4708    }
4709
4710    fn largest_border_interior(quad: &Quad) -> Bounds<ScaledPixels> {
4711        let radii = &quad.corner_radii;
4712        let widths = &quad.border_widths;
4713        let edge_radii = Edges {
4714            top: radii.top_left.max(radii.top_right),
4715            right: radii.top_right.max(radii.bottom_right),
4716            bottom: radii.bottom_left.max(radii.bottom_right),
4717            left: radii.top_left.max(radii.bottom_left),
4718        };
4719
4720        let antialias_inset = point(ScaledPixels(1.0), ScaledPixels(1.0));
4721        let inset_bounds = |top_left_inset, bottom_right_inset| {
4722            Bounds::from_corners(
4723                quad.bounds.origin + top_left_inset + antialias_inset,
4724                quad.bounds.bottom_right() - bottom_right_inset - antialias_inset,
4725            )
4726        };
4727
4728        // Rounded corners need only be excluded on one axis. Either candidate
4729        // is empty of border pixels, so use the larger interior.
4730        let horizontal_band = inset_bounds(
4731            point(widths.left, widths.top.max(edge_radii.top)),
4732            point(widths.right, widths.bottom.max(edge_radii.bottom)),
4733        );
4734        let vertical_band = inset_bounds(
4735            point(widths.left.max(edge_radii.left), widths.top),
4736            point(widths.right.max(edge_radii.right), widths.bottom),
4737        );
4738
4739        let area = |bounds: &Bounds<ScaledPixels>| {
4740            bounds.size.width.0.max(0.) * bounds.size.height.0.max(0.)
4741        };
4742        if area(&horizontal_band) >= area(&vertical_band) {
4743            horizontal_band
4744        } else {
4745            vertical_band
4746        }
4747    }
4748
4749    /// Paint one or more quads into the scene for the next frame at the current stacking context.
4750    /// Quads are colored rectangular regions with an optional background, border, and corner radius.
4751    /// see [`fill`], [`outline`], and [`quad`] to construct this type.
4752    ///
4753    /// This method should only be called as part of the paint phase of element drawing.
4754    ///
4755    /// Note that the `quad.corner_radii` are allowed to exceed the bounds, creating sharp corners
4756    /// where the circular arcs meet. This will not display well when combined with dashed borders.
4757    /// Use `Corners::clamp_radii_for_quad_size` if the radii should fit within the bounds.
4758    pub fn paint_quad(&mut self, quad: PaintQuad) {
4759        self.invalidator.debug_assert_paint();
4760
4761        let opacity = self.element_opacity();
4762        let snapped_bounds = self.snap_bounds(quad.bounds);
4763        let snapped_border_widths = self.snap_border_widths(quad.border_widths);
4764        let quad = Quad {
4765            order: 0,
4766            bounds: snapped_bounds,
4767            content_mask: self.snapped_content_mask(),
4768            background: quad.background.opacity(opacity),
4769            border_color: quad.border_color.opacity(opacity),
4770            corner_radii: quad.corner_radii.scale(self.scale_factor()),
4771            border_widths: snapped_border_widths,
4772            border_style: quad.border_style,
4773        };
4774
4775        if !quad.background.is_transparent() {
4776            self.next_frame.scene.insert_primitive(quad);
4777            return;
4778        }
4779
4780        // Splitting a border-only quad around its empty interior avoids shading
4781        // every transparent pixel inside large outlines.
4782        let outer_bounds = quad.bounds;
4783        let inner_bounds = Self::largest_border_interior(&quad);
4784
4785        if inner_bounds.is_empty() {
4786            self.next_frame.scene.insert_primitive(quad);
4787            return;
4788        }
4789
4790        let strips = [
4791            // Top
4792            Bounds::from_corners(
4793                outer_bounds.origin,
4794                point(outer_bounds.right(), inner_bounds.top()),
4795            ),
4796            // Bottom
4797            Bounds::from_corners(
4798                point(outer_bounds.left(), inner_bounds.bottom()),
4799                outer_bounds.bottom_right(),
4800            ),
4801            // Left
4802            Bounds::from_corners(
4803                point(outer_bounds.left(), inner_bounds.top()),
4804                inner_bounds.bottom_left(),
4805            ),
4806            // Right
4807            Bounds::from_corners(
4808                inner_bounds.top_right(),
4809                point(outer_bounds.right(), inner_bounds.bottom()),
4810            ),
4811        ];
4812
4813        for strip in strips {
4814            let content_mask_bounds = quad.content_mask.bounds.intersect(&strip);
4815            if !content_mask_bounds.is_empty() {
4816                self.next_frame.scene.insert_primitive(Quad {
4817                    content_mask: ContentMask {
4818                        bounds: content_mask_bounds,
4819                    },
4820                    ..quad
4821                });
4822            }
4823        }
4824    }
4825
4826    /// Paint the given `Path` into the scene for the next frame at the current z-index.
4827    ///
4828    /// This method should only be called as part of the paint phase of element drawing.
4829    pub fn paint_path(&mut self, mut path: Path<Pixels>, color: impl Into<Background>) {
4830        self.invalidator.debug_assert_paint();
4831
4832        let scale_factor = self.scale_factor();
4833        let content_mask = self.content_mask();
4834        let opacity = self.element_opacity();
4835        path.content_mask = content_mask;
4836        let color: Background = color.into();
4837        path.color = color.opacity(opacity);
4838        self.next_frame
4839            .scene
4840            .insert_primitive(path.scale(scale_factor));
4841    }
4842
4843    /// Record a validated path brush. The host applies inherited opacity once.
4844    /// Programs may evaluate direct coverage or use retained native geometry.
4845    pub fn paint_brushed_path(&mut self, mut draw: crate::ShaderDraw) {
4846        self.invalidator.debug_assert_paint();
4847        draw.opacity *= self.element_opacity();
4848        draw.content_mask.bounds = draw
4849            .content_mask
4850            .bounds
4851            .intersect(&self.content_mask().scale(self.scale_factor()).bounds);
4852        if draw.opacity <= 0. || draw.bounds.intersect(&draw.content_mask.bounds).is_empty() {
4853            return;
4854        }
4855        self.next_frame
4856            .scene
4857            .insert_primitive(crate::Primitive::Shader(draw));
4858    }
4859
4860    /// Paint an underline into the scene for the next frame at the current z-index.
4861    ///
4862    /// This method should only be called as part of the paint phase of element drawing.
4863    pub fn paint_underline(
4864        &mut self,
4865        origin: Point<Pixels>,
4866        width: Pixels,
4867        style: &UnderlineStyle,
4868    ) {
4869        self.invalidator.debug_assert_paint();
4870        let underline = self.underline(origin, width, style);
4871        self.next_frame.scene.insert_primitive(underline);
4872    }
4873
4874    /// Paint a strikethrough into the scene for the next frame at the current z-index.
4875    ///
4876    /// This method should only be called as part of the paint phase of element drawing.
4877    pub fn paint_strikethrough(
4878        &mut self,
4879        origin: Point<Pixels>,
4880        width: Pixels,
4881        style: &StrikethroughStyle,
4882    ) {
4883        self.invalidator.debug_assert_paint();
4884
4885        let scale_factor = self.scale_factor();
4886        let height = style.thickness;
4887        let bounds = Bounds {
4888            origin: origin.map(|c| ScaledPixels(round_to_device_pixel(c.0, scale_factor))),
4889            size: size(self.snap_stroke(width), self.snap_stroke(height)),
4890        };
4891        let opacity = self.element_opacity();
4892
4893        self.next_frame.scene.insert_primitive(Underline {
4894            order: 0,
4895            pad: 0,
4896            bounds,
4897            content_mask: self.snapped_content_mask(),
4898            thickness: self.snap_stroke(style.thickness),
4899            color: style.color.unwrap_or_default().opacity(opacity),
4900            wavy: false.into(),
4901        });
4902    }
4903
4904    /// Paints a monochrome (non-emoji) glyph into the scene for the next frame at the current z-index.
4905    ///
4906    /// The y component of the origin is the baseline of the glyph.
4907    /// You should generally prefer to use the [`ShapedLine::paint`](crate::ShapedLine::paint) or
4908    /// [`WrappedLine::paint`](crate::WrappedLine::paint) methods in the [`TextSystem`](crate::TextSystem).
4909    /// This method is only useful if you need to paint a single glyph that has already been shaped.
4910    ///
4911    /// This method should only be called as part of the paint phase of element drawing.
4912    pub fn paint_glyph(
4913        &mut self,
4914        origin: Point<Pixels>,
4915        font_id: FontId,
4916        glyph_id: GlyphId,
4917        font_size: Pixels,
4918        color: Hsla,
4919    ) -> Result<()> {
4920        self.invalidator.debug_assert_paint();
4921
4922        let element_opacity = self.element_opacity();
4923        let scale_factor = self.scale_factor();
4924        let glyph_origin = origin.scale(scale_factor);
4925
4926        let quantized_origin = Point::new(
4927            round_half_toward_zero(glyph_origin.x.0 * SUBPIXEL_VARIANTS_X as f32)
4928                / SUBPIXEL_VARIANTS_X as f32,
4929            round_half_toward_zero(glyph_origin.y.0 * SUBPIXEL_VARIANTS_Y as f32)
4930                / SUBPIXEL_VARIANTS_Y as f32,
4931        );
4932        let subpixel_variant = Point::new(
4933            (quantized_origin.x.fract() * SUBPIXEL_VARIANTS_X as f32) as u8,
4934            (quantized_origin.y.fract() * SUBPIXEL_VARIANTS_Y as f32) as u8,
4935        );
4936        let integer_origin = quantized_origin.map(|c| ScaledPixels(c.trunc()));
4937        let glyph_brush = self.glyph_brush_stack.last().cloned();
4938        // Colored materials use grayscale coverage; ordinary text keeps its
4939        // platform-selected grayscale/subpixel pipeline and color dilation.
4940        let subpixel_rendering = glyph_brush.is_none()
4941            && self.layer_capture_depth == 0
4942            && self.should_use_subpixel_rendering(font_id, font_size);
4943        let dilation = self
4944            .text_system()
4945            .glyph_dilation_for_color(if glyph_brush.is_some() {
4946                crate::white()
4947            } else {
4948                color
4949            });
4950        let params = RenderGlyphParams {
4951            font_id,
4952            glyph_id,
4953            font_size,
4954            subpixel_variant,
4955            scale_factor,
4956            is_emoji: false,
4957            subpixel_rendering,
4958            dilation,
4959        };
4960
4961        let raster_bounds = self.text_system().raster_bounds(&params)?;
4962        if !raster_bounds.is_zero() {
4963            let tile = self
4964                .sprite_atlas
4965                .get_or_insert_with(params.clone().into(), &mut || {
4966                    let (size, bytes) = self.text_system().rasterize_glyph(&params)?;
4967                    Ok(Some((size, Cow::Owned(bytes))))
4968                })?
4969                .expect("Callback above only errors or returns Some");
4970            let bounds = Bounds {
4971                origin: integer_origin + raster_bounds.origin.map(Into::into),
4972                size: tile.bounds.size.map(Into::into),
4973            };
4974            let content_mask = self.snapped_content_mask();
4975
4976            if let Some((brush, brush_bounds)) = glyph_brush {
4977                brush.paint_glyph(
4978                    self,
4979                    MonochromeSprite {
4980                        order: 0,
4981                        pad: 0,
4982                        bounds,
4983                        content_mask,
4984                        color: crate::white(),
4985                        tile,
4986                        transformation: TransformationMatrix::unit(),
4987                    },
4988                    brush_bounds,
4989                    element_opacity,
4990                )?;
4991            } else if subpixel_rendering {
4992                self.next_frame.scene.insert_primitive(SubpixelSprite {
4993                    order: 0,
4994                    pad: 0,
4995                    bounds,
4996                    content_mask,
4997                    color: color.opacity(element_opacity),
4998                    tile,
4999                    transformation: TransformationMatrix::unit(),
5000                });
5001            } else {
5002                self.next_frame.scene.insert_primitive(MonochromeSprite {
5003                    order: 0,
5004                    pad: 0,
5005                    bounds,
5006                    content_mask,
5007                    color: color.opacity(element_opacity),
5008                    tile,
5009                    transformation: TransformationMatrix::unit(),
5010                });
5011            }
5012        }
5013        Ok(())
5014    }
5015
5016    fn should_use_subpixel_rendering(&self, font_id: FontId, font_size: Pixels) -> bool {
5017        if self.platform_window.background_appearance() != WindowBackgroundAppearance::Opaque {
5018            return false;
5019        }
5020
5021        if !self.platform_window.is_subpixel_rendering_supported() {
5022            return false;
5023        }
5024
5025        let mode = match self.text_rendering_mode.get() {
5026            TextRenderingMode::PlatformDefault => self
5027                .text_system()
5028                .recommended_rendering_mode(font_id, font_size),
5029            mode => mode,
5030        };
5031
5032        mode == TextRenderingMode::Subpixel
5033    }
5034
5035    /// Paints an emoji glyph into the scene for the next frame at the current z-index.
5036    ///
5037    /// The y component of the origin is the baseline of the glyph.
5038    /// You should generally prefer to use the [`ShapedLine::paint`](crate::ShapedLine::paint) or
5039    /// [`WrappedLine::paint`](crate::WrappedLine::paint) methods in the [`TextSystem`](crate::TextSystem).
5040    /// This method is only useful if you need to paint a single emoji that has already been shaped.
5041    ///
5042    /// This method should only be called as part of the paint phase of element drawing.
5043    pub fn paint_emoji(
5044        &mut self,
5045        origin: Point<Pixels>,
5046        font_id: FontId,
5047        glyph_id: GlyphId,
5048        font_size: Pixels,
5049    ) -> Result<()> {
5050        self.invalidator.debug_assert_paint();
5051
5052        let scale_factor = self.scale_factor();
5053        let glyph_origin = origin.scale(scale_factor);
5054        let integer_origin = glyph_origin.map(|c| ScaledPixels(round_half_toward_zero(c.0)));
5055        let params = RenderGlyphParams {
5056            font_id,
5057            glyph_id,
5058            font_size,
5059            subpixel_variant: Default::default(),
5060            scale_factor,
5061            is_emoji: true,
5062            subpixel_rendering: false,
5063            dilation: 0,
5064        };
5065
5066        let raster_bounds = self.text_system().raster_bounds(&params)?;
5067        if !raster_bounds.is_zero() {
5068            let tile = self
5069                .sprite_atlas
5070                .get_or_insert_with(params.clone().into(), &mut || {
5071                    let (size, bytes) = self.text_system().rasterize_glyph(&params)?;
5072                    Ok(Some((size, Cow::Owned(bytes))))
5073                })?
5074                .expect("Callback above only errors or returns Some");
5075
5076            let bounds = Bounds {
5077                origin: integer_origin + raster_bounds.origin.map(Into::into),
5078                size: tile.bounds.size.map(Into::into),
5079            };
5080            let content_mask = self.snapped_content_mask();
5081            let opacity = self.element_opacity();
5082
5083            self.next_frame.scene.insert_primitive(PolychromeSprite {
5084                order: 0,
5085                pad: 0,
5086                grayscale: false.into(),
5087                bounds,
5088                corner_radii: Default::default(),
5089                content_mask,
5090                tile,
5091                opacity,
5092            });
5093        }
5094        Ok(())
5095    }
5096
5097    /// Paint a monochrome SVG into the scene for the next frame at the current stacking context.
5098    ///
5099    /// This method should only be called as part of the paint phase of element drawing.
5100    pub fn paint_svg(
5101        &mut self,
5102        bounds: Bounds<Pixels>,
5103        path: SharedString,
5104        mut data: Option<&[u8]>,
5105        transformation: TransformationMatrix,
5106        color: Hsla,
5107        cx: &App,
5108    ) -> Result<()> {
5109        self.invalidator.debug_assert_paint();
5110
5111        let element_opacity = self.element_opacity();
5112        let bounds = self.snap_bounds(bounds);
5113
5114        let params = RenderSvgParams {
5115            path,
5116            size: bounds.size.map(|pixels| {
5117                DevicePixels::from((pixels.0 * SMOOTH_SVG_SCALE_FACTOR).ceil() as i32)
5118            }),
5119        };
5120
5121        let Some(tile) =
5122            self.sprite_atlas
5123                .get_or_insert_with(params.clone().into(), &mut || {
5124                    let Some((size, bytes)) = cx.svg_renderer.render_alpha_mask(&params, data)?
5125                    else {
5126                        return Ok(None);
5127                    };
5128                    Ok(Some((size, Cow::Owned(bytes))))
5129                })?
5130        else {
5131            return Ok(());
5132        };
5133        let content_mask = self.snapped_content_mask();
5134        let svg_bounds = Bounds {
5135            origin: bounds.center()
5136                - Point::new(
5137                    ScaledPixels(tile.bounds.size.width.0 as f32 / SMOOTH_SVG_SCALE_FACTOR / 2.),
5138                    ScaledPixels(tile.bounds.size.height.0 as f32 / SMOOTH_SVG_SCALE_FACTOR / 2.),
5139                ),
5140            size: tile
5141                .bounds
5142                .size
5143                .map(|value| ScaledPixels(value.0 as f32 / SMOOTH_SVG_SCALE_FACTOR)),
5144        };
5145        let final_bounds = svg_bounds
5146            .map_origin(|value| ScaledPixels(round_half_toward_zero(value.0)))
5147            .map_size(|size| size.ceil());
5148
5149        self.next_frame.scene.insert_primitive(MonochromeSprite {
5150            order: 0,
5151            pad: 0,
5152            bounds: final_bounds,
5153            content_mask,
5154            color: color.opacity(element_opacity),
5155            tile,
5156            transformation,
5157        });
5158
5159        Ok(())
5160    }
5161
5162    /// Paint an image into the scene for the next frame at the current z-index.
5163    /// This method will panic if the frame_index is not valid
5164    ///
5165    /// This method should only be called as part of the paint phase of element drawing.
5166    /// Paint an image into `bounds`, positioning and scaling it according to `image_bounds`.
5167    ///
5168    /// The visible region rendered is `bounds.intersect(&image_bounds)`, with `corner_radii`
5169    /// applied to `bounds`.
5170    pub fn paint_image(
5171        &mut self,
5172        bounds: Bounds<Pixels>,
5173        image_bounds: Bounds<Pixels>,
5174        corner_radii: Corners<Pixels>,
5175        data: Arc<RenderImage>,
5176        frame_index: usize,
5177        grayscale: bool,
5178    ) -> Result<()> {
5179        self.invalidator.debug_assert_paint();
5180
5181        let visible_bounds = bounds.intersect(&image_bounds);
5182        if visible_bounds.size.width <= Pixels::ZERO || visible_bounds.size.height <= Pixels::ZERO {
5183            return Ok(());
5184        }
5185        if image_bounds.size.width <= Pixels::ZERO || image_bounds.size.height <= Pixels::ZERO {
5186            return Ok(());
5187        }
5188
5189        let params = RenderImageParams {
5190            image_id: data.id,
5191            frame_index,
5192        };
5193
5194        let tile = self
5195            .sprite_atlas
5196            .get_or_insert_with(params.into(), &mut || {
5197                Ok(Some((
5198                    data.size(frame_index),
5199                    Cow::Borrowed(
5200                        data.as_bytes(frame_index)
5201                            .expect("It's the caller's job to pass a valid frame index"),
5202                    ),
5203                )))
5204            })?
5205            .expect("Callback above only returns Some");
5206
5207        let visible_bounds_snapped = self.snap_bounds(visible_bounds);
5208
5209        let sub_tile = if visible_bounds == image_bounds {
5210            tile
5211        } else {
5212            let x_offset_ratio =
5213                (visible_bounds.origin.x - image_bounds.origin.x) / image_bounds.size.width;
5214            let y_offset_ratio =
5215                (visible_bounds.origin.y - image_bounds.origin.y) / image_bounds.size.height;
5216            let width_ratio = visible_bounds.size.width / image_bounds.size.width;
5217            let height_ratio = visible_bounds.size.height / image_bounds.size.height;
5218
5219            let tile_origin_x = tile.bounds.origin.x.0;
5220            let tile_origin_y = tile.bounds.origin.y.0;
5221            let tile_width = tile.bounds.size.width.0;
5222            let tile_height = tile.bounds.size.height.0;
5223
5224            let sub_origin_x = tile_origin_x + (x_offset_ratio * tile_width as f32).round() as i32;
5225            let sub_origin_y = tile_origin_y + (y_offset_ratio * tile_height as f32).round() as i32;
5226            let sub_width = (width_ratio * tile_width as f32).round() as i32;
5227            let sub_height = (height_ratio * tile_height as f32).round() as i32;
5228
5229            let max_x = tile_origin_x + tile_width;
5230            let max_y = tile_origin_y + tile_height;
5231
5232            let clamped_origin_x = sub_origin_x.clamp(tile_origin_x, max_x);
5233            let clamped_origin_y = sub_origin_y.clamp(tile_origin_y, max_y);
5234            let clamped_width = sub_width.min(max_x - clamped_origin_x).max(0);
5235            let clamped_height = sub_height.min(max_y - clamped_origin_y).max(0);
5236
5237            AtlasTile {
5238                bounds: Bounds {
5239                    origin: point(
5240                        DevicePixels(clamped_origin_x),
5241                        DevicePixels(clamped_origin_y),
5242                    ),
5243                    size: size(DevicePixels(clamped_width), DevicePixels(clamped_height)),
5244                },
5245                ..tile
5246            }
5247        };
5248
5249        let content_mask = self.snapped_content_mask();
5250        let corner_radii = corner_radii
5251            .clamp_radii_for_quad_size(visible_bounds.size)
5252            .scale(self.scale_factor());
5253        let opacity = self.element_opacity();
5254
5255        self.next_frame.scene.insert_primitive(PolychromeSprite {
5256            order: 0,
5257            pad: 0,
5258            grayscale: grayscale.into(),
5259            bounds: visible_bounds_snapped,
5260            content_mask,
5261            corner_radii,
5262            tile: sub_tile,
5263            opacity,
5264        });
5265        Ok(())
5266    }
5267
5268    pub(crate) fn glyph_brush_cache_key(&self) -> Option<GlyphBrushCacheKey> {
5269        self.glyph_brush_stack
5270            .last()
5271            .map(|(brush, bounds)| GlyphBrushCacheKey {
5272                identity: brush.cache_key(),
5273                bounds: *bounds,
5274            })
5275    }
5276    /// Scope a glyph brush across descendants. Establish the same scope in
5277    /// prepaint so deferred children retain their brush and original coordinates.
5278    pub fn with_glyph_brush<R>(
5279        &mut self,
5280        brush: Arc<dyn crate::GlyphBrush>,
5281        bounds: Bounds<Pixels>,
5282        f: impl FnOnce(&mut Self) -> R,
5283    ) -> R {
5284        self.glyph_brush_stack.push((brush, bounds));
5285        let result = f(self);
5286        self.glyph_brush_stack.pop();
5287        result
5288    }
5289    /// Record an atlas-masked shader with the same clipping/opacity rules as a
5290    /// monochrome glyph. Payload interpretation belongs to the extension.
5291    pub fn paint_glyph_shader(
5292        &mut self,
5293        glyph: MonochromeSprite,
5294        program: Arc<crate::SceneShaderProgram>,
5295        data: [[f32; 4]; crate::SHADER_DATA_SLOTS],
5296        opacity: f32,
5297    ) {
5298        self.invalidator.debug_assert_paint();
5299        assert!(
5300            program.uses_glyph_mask(),
5301            "glyph drawing requires an atlas-masked program"
5302        );
5303        self.next_frame
5304            .scene
5305            .insert_primitive(crate::Primitive::Shader(crate::ShaderDraw {
5306                order: 0,
5307                bounds: glyph.bounds,
5308                content_mask: glyph.content_mask,
5309                opacity,
5310                scale_factor: self.scale_factor(),
5311                program,
5312                data,
5313                path_mask: None,
5314                glyph_mask: Some(glyph.tile),
5315            }));
5316    }
5317    /// Whether descendant text must use coverage suitable for isolated composition.
5318    pub fn is_layer_captured(&self) -> bool {
5319        self.layer_capture_depth > 0
5320    }
5321
5322    /// Prepaint/paint scope shared by explicit captured containers. Descendants
5323    /// use local opacity and cannot paint outside the bounded capture rectangle.
5324    pub fn with_layer_capture_scope<R>(
5325        &mut self,
5326        bounds: Bounds<Pixels>,
5327        f: impl FnOnce(&mut Self) -> R,
5328    ) -> R {
5329        let source = bounds.intersect(&self.content_mask().bounds);
5330        self.with_layer_capture_masks(source, source, f)
5331    }
5332
5333    /// Prepaint a captured subtree with a sampling halo and a separate visible clip.
5334    /// Reserve the supported remaining nesting budget so later radius edits and
5335    /// nested filters can reuse raw source pixels without painting past the crop.
5336    pub fn with_layer_effect_scope<R>(
5337        &mut self,
5338        bounds: Bounds<Pixels>,
5339        f: impl FnOnce(&mut Self) -> R,
5340    ) -> R {
5341        let (source, clip) = self.layer_capture_regions(bounds);
5342        self.with_layer_capture_masks(source, clip, f)
5343    }
5344    fn layer_capture_regions(&self, bounds: Bounds<Pixels>) -> (Bounds<Pixels>, Bounds<Pixels>) {
5345        let viewport = Bounds::new(Point::default(), self.viewport_size);
5346        let clip = bounds
5347            .intersect(&self.content_mask().bounds)
5348            .intersect(&viewport);
5349        if clip.is_empty() {
5350            return (clip, clip);
5351        }
5352        let levels = crate::MAX_LAYER_GROUPS
5353            .saturating_sub(self.layer_capture_depth)
5354            .max(1) as f32;
5355        // 16 logical pixels per Gaussian plus eight device pixels for area
5356        // downsampling, reconstruction and integer crop rounding per level.
5357        let halo = px((16. + 8. / self.scale_factor()) * levels);
5358        let mut source = clip.dilate(halo).intersect(&viewport);
5359        if let Some(parent) = self.layer_capture_sources.last() {
5360            source = source.intersect(parent);
5361        }
5362        (source, clip)
5363    }
5364    pub(crate) fn layer_capture_visible_bounds(&self) -> Option<Bounds<Pixels>> {
5365        self.layer_capture_clips.last().copied()
5366    }
5367    fn with_layer_capture_masks<R>(
5368        &mut self,
5369        source: Bounds<Pixels>,
5370        clip: Bounds<Pixels>,
5371        f: impl FnOnce(&mut Self) -> R,
5372    ) -> R {
5373        self.invalidator.debug_assert_paint_or_prepaint();
5374        let previous = self.element_opacity;
5375        self.element_opacity = 1.;
5376        self.layer_capture_depth += 1;
5377        self.layer_capture_sources.push(source);
5378        let visible = self
5379            .layer_capture_clips
5380            .last()
5381            .map_or(clip, |parent| clip.intersect(parent));
5382        self.layer_capture_clips.push(visible);
5383        // Bypass ancestor paint clips for source sampling; descendant clips still
5384        // intersect this mask. Interaction keeps the original final visible clip.
5385        self.content_mask_stack.push(ContentMask { bounds: source });
5386        let result = f(self);
5387        self.content_mask_stack.pop();
5388        self.layer_capture_clips.pop();
5389        self.layer_capture_sources.pop();
5390        self.layer_capture_depth -= 1;
5391        self.element_opacity = previous;
5392        result
5393    }
5394
5395    /// Capture a subtree and apply opacity once to its completed RGBA result.
5396    /// Deferred overlays remain outside this paint-time boundary.
5397    pub fn with_layer_opacity<R>(
5398        &mut self,
5399        bounds: Bounds<Pixels>,
5400        opacity: f32,
5401        program: Arc<crate::SceneShaderProgram>,
5402        f: impl FnOnce(&mut Self) -> R,
5403    ) -> R {
5404        self.with_layer_effect(bounds, opacity, 1., program, f)
5405    }
5406
5407    /// Capture a subtree, filter saturation, then apply opacity to the group.
5408    /// Saturation changes reuse raw retained child pixels when commands match.
5409    pub fn with_layer_effect<R>(
5410        &mut self,
5411        bounds: Bounds<Pixels>,
5412        opacity: f32,
5413        saturation: f32,
5414        program: Arc<crate::SceneShaderProgram>,
5415        f: impl FnOnce(&mut Self) -> R,
5416    ) -> R {
5417        self.with_layer_color_filter(
5418            bounds,
5419            opacity,
5420            crate::LayerColorFilter {
5421                saturation,
5422                ..Default::default()
5423            },
5424            program,
5425            f,
5426        )
5427    }
5428
5429    /// Capture a subtree and apply color filtering, group opacity and destination blending.
5430    /// Color operations reuse retained raw child pixels when commands match.
5431    pub fn with_layer_color_filter<R>(
5432        &mut self,
5433        bounds: Bounds<Pixels>,
5434        opacity: f32,
5435        color_filter: crate::LayerColorFilter,
5436        program: Arc<crate::SceneShaderProgram>,
5437        f: impl FnOnce(&mut Self) -> R,
5438    ) -> R {
5439        self.invalidator.debug_assert_paint();
5440        let viewport = Bounds::new(Point::default(), self.viewport_size);
5441        let (source, clipped) = self.layer_capture_regions(bounds);
5442        let effective = opacity * self.element_opacity();
5443        if clipped.is_empty() {
5444            return self.with_layer_capture_scope(clipped, f);
5445        }
5446        let scale = self.scale_factor();
5447        let capture = Arc::new(crate::LayerCapture {
5448            blur_quality: color_filter.blur_quality,
5449            blur_radius: crate::ScaledPixels(f32::from(color_filter.blur_radius) * scale),
5450            blend_mode: color_filter.blend_mode,
5451            bounds: source.scale(scale),
5452            clip: Some(clipped.scale(scale)),
5453            opacity: effective,
5454            saturation: color_filter.saturation,
5455            brightness: color_filter.brightness,
5456            contrast: color_filter.contrast,
5457            invert: color_filter.invert,
5458            program,
5459        });
5460        let fence = ContentMask {
5461            bounds: viewport.scale(scale),
5462        };
5463        self.next_frame
5464            .scene
5465            .begin_layer_capture(capture.clone(), fence);
5466        let result = self.with_layer_capture_masks(source, clipped, f);
5467        self.next_frame.scene.end_layer_capture(capture, fence);
5468        result
5469    }
5470
5471    /// Record an explicit backdrop filter before painting the receiving surface.
5472    /// Unlike paint_layer, this boundary may interrupt the host render pass.
5473    pub fn paint_backdrop_blur(
5474        &mut self,
5475        bounds: Bounds<Pixels>,
5476        radii: Corners<Pixels>,
5477        radius: Pixels,
5478        opacity: f32,
5479        program: Arc<crate::SceneShaderProgram>,
5480    ) {
5481        self.invalidator.debug_assert_paint();
5482        let viewport = Bounds::new(Point::default(), self.viewport_size);
5483        let clip = self.content_mask();
5484        if radius <= px(0.)
5485            || bounds
5486                .intersect(&clip.bounds)
5487                .intersect(&viewport)
5488                .is_empty()
5489            || opacity <= 0.
5490        {
5491            return;
5492        }
5493        let scale = self.scale_factor();
5494        let halo = radius + px(crate::BACKDROP_DOWNSAMPLE as f32 / scale);
5495        let footprint = Bounds::new(
5496            bounds.origin - point(halo, halo),
5497            bounds.size + size(halo * 2., halo * 2.),
5498        );
5499        self.next_frame
5500            .scene
5501            .insert_primitive(crate::Primitive::Backdrop(crate::BackdropDraw {
5502                order: 0,
5503                bounds: footprint.scale(scale),
5504                content_mask: ContentMask {
5505                    bounds: viewport.scale(scale),
5506                },
5507                surface_bounds: bounds.scale(scale),
5508                clip: clip.scale(scale),
5509                corner_radii: radii.scale(scale),
5510                radius: f32::from(radius) * scale,
5511                opacity: opacity * self.element_opacity(),
5512                program,
5513            }));
5514    }
5515    /// Record an instanced fragment shader in the current scene order.
5516    /// Bounds include the entire effect; the host applies clipping and opacity.
5517    pub fn paint_shader(
5518        &mut self,
5519        bounds: Bounds<Pixels>,
5520        program: std::sync::Arc<crate::SceneShaderProgram>,
5521        data: [[f32; 4]; crate::SHADER_DATA_SLOTS],
5522    ) {
5523        self.invalidator.debug_assert_paint();
5524        if bounds.is_empty() || self.element_opacity() <= 0.0 {
5525            return;
5526        }
5527        self.next_frame
5528            .scene
5529            .insert_primitive(crate::Primitive::Shader(crate::ShaderDraw {
5530                path_mask: None,
5531                glyph_mask: None,
5532                order: 0,
5533                bounds: bounds.scale(self.scale_factor()),
5534                content_mask: self.snapped_content_mask(),
5535                opacity: self.element_opacity(),
5536                scale_factor: self.scale_factor(),
5537                program,
5538                data,
5539            }));
5540    }
5541
5542    /// Record independent GPU content using native geometry at the current scene order.
5543    /// Producers span the full unclipped shape; GPUI applies clip, coverage and opacity.
5544    pub fn paint_custom(
5545        &mut self,
5546        geometry: crate::CustomGeometry,
5547        content: std::sync::Arc<dyn crate::CustomContent>,
5548    ) {
5549        self.invalidator.debug_assert_paint();
5550        if self.element_opacity() <= 0.0 {
5551            return;
5552        }
5553        let (bounds, corner_radii, coverage) = match geometry {
5554            crate::CustomGeometry::RoundedRect {
5555                bounds,
5556                corner_radii,
5557            } => (bounds, corner_radii, None),
5558            crate::CustomGeometry::Border(quad) => {
5559                if quad.border_widths == Edges::default() {
5560                    return;
5561                }
5562                let coverage = crate::CustomCoverage::Border {
5563                    widths: self.snap_border_widths(quad.border_widths),
5564                    style: quad.border_style,
5565                };
5566                (quad.bounds, quad.corner_radii, Some(coverage))
5567            }
5568            crate::CustomGeometry::Path(path) => {
5569                if path.bounds.is_empty() || path.vertices.is_empty() {
5570                    return;
5571                }
5572                let bounds = path.bounds;
5573                (
5574                    bounds,
5575                    Corners::default(),
5576                    Some(crate::CustomCoverage::Path(std::sync::Arc::new(
5577                        path.scale(self.scale_factor()),
5578                    ))),
5579                )
5580            }
5581        };
5582        if bounds.is_empty() {
5583            return;
5584        }
5585        // Path geometry retains its original scaled bounds. Rectangle/border bounds
5586        // use the same pixel snapping as native quads.
5587        let scaled_bounds = if matches!(&coverage, Some(crate::CustomCoverage::Path(_))) {
5588            bounds.scale(self.scale_factor())
5589        } else {
5590            self.snap_bounds(bounds)
5591        };
5592        self.next_frame.scene.insert_primitive(crate::CustomDraw {
5593            order: 0,
5594            bounds: scaled_bounds,
5595            content_mask: self.snapped_content_mask(),
5596            corner_radii: corner_radii
5597                .clamp_radii_for_quad_size(bounds.size)
5598                .scale(self.scale_factor()),
5599            opacity: self.element_opacity(),
5600            content: crate::scene::content_with_preparation_geometry(
5601                content,
5602                bounds.size,
5603                self.scale_factor(),
5604            ),
5605            coverage,
5606        });
5607    }
5608
5609    /// Paint a surface into the scene for the next frame at the current z-index.
5610    ///
5611    /// This method should only be called as part of the paint phase of element drawing.
5612    #[cfg(any(target_os = "macos", target_os = "ios"))]
5613    pub fn paint_surface(
5614        &mut self,
5615        bounds: Bounds<Pixels>,
5616        image_buffer: CFRetained<CVPixelBuffer>,
5617    ) {
5618        use crate::PaintSurface;
5619
5620        self.invalidator.debug_assert_paint();
5621
5622        let bounds = self.snap_bounds(bounds);
5623        let content_mask = self.snapped_content_mask();
5624        self.next_frame.scene.insert_primitive(PaintSurface {
5625            order: 0,
5626            bounds,
5627            content_mask,
5628            image_buffer,
5629        });
5630    }
5631
5632    /// Removes an image from the sprite atlas.
5633    pub fn drop_image(&mut self, data: Arc<RenderImage>) -> Result<()> {
5634        for frame_index in 0..data.frame_count() {
5635            let params = RenderImageParams {
5636                image_id: data.id,
5637                frame_index,
5638            };
5639
5640            self.sprite_atlas.remove(&params.clone().into());
5641        }
5642
5643        Ok(())
5644    }
5645
5646    /// Returns whether every frame of an image is present in the sprite atlas.
5647    #[cfg(any(test, feature = "test-support"))]
5648    pub fn has_image_atlas_entry(&self, data: &RenderImage) -> bool {
5649        data.frame_count() > 0
5650            && (0..data.frame_count()).all(|frame_index| {
5651                self.sprite_atlas.contains(
5652                    &RenderImageParams {
5653                        image_id: data.id,
5654                        frame_index,
5655                    }
5656                    .into(),
5657                )
5658            })
5659    }
5660
5661    /// Add a node to the layout tree for the current frame. Takes the `Style` of the element for which
5662    /// layout is being requested, along with the layout ids of any children. This method is called during
5663    /// calls to the [`Element::request_layout`] trait method and enables any element to participate in layout.
5664    ///
5665    /// This method should only be called as part of the request_layout or prepaint phase of element drawing.
5666    #[must_use]
5667    pub fn request_layout(
5668        &mut self,
5669        style: Style,
5670        children: impl IntoIterator<Item = LayoutId>,
5671        cx: &mut App,
5672    ) -> LayoutId {
5673        self.invalidator.debug_assert_prepaint();
5674
5675        cx.layout_id_buffer.clear();
5676        cx.layout_id_buffer.extend(children);
5677        let rem_size = self.rem_size();
5678        let scale_factor = self.scale_factor();
5679
5680        self.layout_engine.as_mut().unwrap().request_layout(
5681            style,
5682            rem_size,
5683            scale_factor,
5684            &cx.layout_id_buffer,
5685        )
5686    }
5687
5688    /// Add a node to the layout tree for the current frame. Instead of taking a `Style` and children,
5689    /// this variant takes a function that is invoked during layout so you can use arbitrary logic to
5690    /// determine the element's size. One place this is used internally is when measuring text.
5691    ///
5692    /// The given closure is invoked at layout time with the known dimensions and available space and
5693    /// returns a `Size`.
5694    ///
5695    /// This method should only be called as part of the request_layout or prepaint phase of element drawing.
5696    pub fn request_measured_layout<F>(&mut self, style: Style, measure: F) -> LayoutId
5697    where
5698        F: Fn(Size<Option<Pixels>>, Size<AvailableSpace>, &mut Window, &mut App) -> Size<Pixels>
5699            + 'static,
5700    {
5701        self.invalidator.debug_assert_prepaint();
5702
5703        let rem_size = self.rem_size();
5704        let scale_factor = self.scale_factor();
5705        self.layout_engine
5706            .as_mut()
5707            .unwrap()
5708            .request_measured_layout(style, rem_size, scale_factor, measure)
5709    }
5710
5711    /// Compute the layout for the given id within the given available space.
5712    /// This method is called for its side effect, typically by the framework prior to painting.
5713    /// After calling it, you can request the bounds of the given layout node id or any descendant.
5714    ///
5715    /// This method should only be called as part of the prepaint phase of element drawing.
5716    pub fn compute_layout(
5717        &mut self,
5718        layout_id: LayoutId,
5719        available_space: Size<AvailableSpace>,
5720        cx: &mut App,
5721    ) {
5722        self.invalidator.debug_assert_prepaint();
5723
5724        let mut layout_engine = self.layout_engine.take().unwrap();
5725        layout_engine.compute_layout(layout_id, available_space, self, cx);
5726        self.layout_engine = Some(layout_engine);
5727    }
5728
5729    /// Obtain the bounds computed for the given LayoutId relative to the window. This method will usually be invoked by
5730    /// GPUI itself automatically in order to pass your element its `Bounds` automatically.
5731    ///
5732    /// This method should only be called as part of element drawing.
5733    pub fn layout_bounds(&mut self, layout_id: LayoutId) -> Bounds<Pixels> {
5734        self.invalidator.debug_assert_prepaint();
5735
5736        let scale_factor = self.scale_factor();
5737        let mut bounds = self
5738            .layout_engine
5739            .as_mut()
5740            .unwrap()
5741            .layout_bounds(layout_id, scale_factor)
5742            .map(Into::into);
5743        let snapped_offset = self.pixel_snap_point(self.element_offset());
5744        bounds.origin += snapped_offset;
5745        bounds
5746    }
5747
5748    /// This method should be called during `prepaint`. You can use
5749    /// the returned [Hitbox] during `paint` or in an event handler
5750    /// to determine whether the inserted hitbox was the topmost.
5751    ///
5752    /// This method should only be called as part of the prepaint phase of element drawing.
5753    pub fn insert_hitbox(&mut self, bounds: Bounds<Pixels>, behavior: HitboxBehavior) -> Hitbox {
5754        self.invalidator.debug_assert_prepaint();
5755
5756        let mut content_mask = self.content_mask();
5757        if let Some(clip) = self.layer_capture_visible_bounds() {
5758            content_mask.bounds = content_mask.bounds.intersect(&clip);
5759        }
5760        let mut id = self.next_hitbox_id;
5761        self.next_hitbox_id = self.next_hitbox_id.next();
5762        let hitbox = Hitbox {
5763            id,
5764            bounds,
5765            content_mask,
5766            behavior,
5767        };
5768        self.next_frame.hitboxes.push(hitbox.clone());
5769        hitbox
5770    }
5771
5772    /// Set a hitbox which will act as a control area of the platform window.
5773    ///
5774    /// This method should only be called as part of the paint phase of element drawing.
5775    pub fn insert_window_control_hitbox(&mut self, area: WindowControlArea, hitbox: Hitbox) {
5776        self.invalidator.debug_assert_paint();
5777        self.next_frame.window_control_hitboxes.push((area, hitbox));
5778    }
5779
5780    /// Sets the key context for the current element. This context will be used to translate
5781    /// keybindings into actions.
5782    ///
5783    /// This method should only be called as part of the paint phase of element drawing.
5784    pub fn set_key_context(&mut self, context: KeyContext) {
5785        self.invalidator.debug_assert_paint();
5786        self.next_frame.dispatch_tree.set_key_context(context);
5787    }
5788
5789    /// Sets the focus handle for the current element. This handle will be used to manage focus state
5790    /// and keyboard event dispatch for the element.
5791    ///
5792    /// This method should only be called as part of the prepaint phase of element drawing.
5793    pub fn set_focus_handle(&mut self, focus_handle: &FocusHandle, _: &App) {
5794        self.invalidator.debug_assert_prepaint();
5795        if focus_handle.is_focused(self) {
5796            self.next_frame.focus = Some(focus_handle.id);
5797        }
5798        self.next_frame.dispatch_tree.set_focus_id(focus_handle.id);
5799    }
5800
5801    /// Sets the view id for the current element, which will be used to manage view caching.
5802    ///
5803    /// This method should only be called as part of element prepaint. We plan on removing this
5804    /// method eventually when we solve some issues that require us to construct editor elements
5805    /// directly instead of always using editors via views.
5806    pub fn set_view_id(&mut self, view_id: EntityId) {
5807        self.invalidator.debug_assert_prepaint();
5808        self.next_frame.dispatch_tree.set_view_id(view_id);
5809    }
5810
5811    /// Get the entity ID for the currently rendering view
5812    pub fn current_view(&self) -> EntityId {
5813        self.invalidator.debug_assert_paint_or_prepaint();
5814        self.rendered_entity_stack.last().copied().unwrap()
5815    }
5816
5817    #[inline]
5818    pub(crate) fn with_rendered_view<R>(
5819        &mut self,
5820        id: EntityId,
5821        f: impl FnOnce(&mut Self) -> R,
5822    ) -> R {
5823        self.rendered_entity_stack.push(id);
5824        let result = f(self);
5825        self.rendered_entity_stack.pop();
5826        result
5827    }
5828
5829    /// Executes the provided function with the specified image cache.
5830    pub fn with_image_cache<F, R>(&mut self, image_cache: Option<AnyImageCache>, f: F) -> R
5831    where
5832        F: FnOnce(&mut Self) -> R,
5833    {
5834        if let Some(image_cache) = image_cache {
5835            self.image_cache_stack.push(image_cache);
5836            let result = f(self);
5837            self.image_cache_stack.pop();
5838            result
5839        } else {
5840            f(self)
5841        }
5842    }
5843
5844    /// Sets an input handler, such as [`ElementInputHandler`][element_input_handler], which interfaces with the
5845    /// platform to receive textual input with proper integration with concerns such
5846    /// as IME interactions. This handler will be active for the upcoming frame until the following frame is
5847    /// rendered.
5848    ///
5849    /// This method should only be called as part of the paint phase of element drawing.
5850    ///
5851    /// [element_input_handler]: crate::ElementInputHandler
5852    pub fn handle_input(
5853        &mut self,
5854        focus_handle: &FocusHandle,
5855        input_handler: impl InputHandler,
5856        cx: &App,
5857    ) {
5858        self.invalidator.debug_assert_paint();
5859
5860        if focus_handle.is_focused(self) {
5861            let cx = self.to_async(cx);
5862            self.next_frame
5863                .input_handlers
5864                .push(Some(PlatformInputHandler::new(cx, Box::new(input_handler))));
5865        }
5866    }
5867
5868    /// Forwards the focused input handler's [`TextInputConfiguration`] to the
5869    /// platform window when it differs from the last forwarded value. With no
5870    /// input handler the default configuration applies, so a field's
5871    /// preferences don't outlive its focus.
5872    fn apply_text_input_configuration(&mut self, cx: &mut App) {
5873        let configuration = match self.platform_window.take_input_handler() {
5874            Some(mut input_handler) => {
5875                let configuration = input_handler.text_input_configuration(self, cx);
5876                self.platform_window.set_input_handler(input_handler);
5877                configuration
5878            }
5879            None => TextInputConfiguration::default(),
5880        };
5881        if self.last_text_input_configuration.as_ref() != Some(&configuration) {
5882            self.platform_window
5883                .set_text_input_configuration(configuration.clone());
5884            self.last_text_input_configuration = Some(configuration);
5885        }
5886    }
5887
5888    /// Register a mouse event listener on the window for the next frame. The type of event
5889    /// is determined by the first parameter of the given listener. When the next frame is rendered
5890    /// the listener will be cleared.
5891    ///
5892    /// This method should only be called as part of the paint phase of element drawing.
5893    pub fn on_mouse_event<Event: MouseEvent>(
5894        &mut self,
5895        mut listener: impl FnMut(&Event, DispatchPhase, &mut Window, &mut App) + 'static,
5896    ) {
5897        self.invalidator.debug_assert_paint();
5898
5899        self.next_frame.mouse_listeners.push(Some(Box::new(
5900            move |event: &dyn Any, phase: DispatchPhase, window: &mut Window, cx: &mut App| {
5901                if let Some(event) = event.downcast_ref() {
5902                    listener(event, phase, window, cx)
5903                }
5904            },
5905        )));
5906    }
5907
5908    /// Register a key event listener on this node for the next frame. The type of event
5909    /// is determined by the first parameter of the given listener. When the next frame is rendered
5910    /// the listener will be cleared.
5911    ///
5912    /// This is a fairly low-level method, so prefer using event handlers on elements unless you have
5913    /// a specific need to register a listener yourself.
5914    ///
5915    /// This method should only be called as part of the paint phase of element drawing.
5916    pub fn on_key_event<Event: KeyEvent>(
5917        &mut self,
5918        listener: impl Fn(&Event, DispatchPhase, &mut Window, &mut App) + 'static,
5919    ) {
5920        self.invalidator.debug_assert_paint();
5921
5922        self.next_frame.dispatch_tree.on_key_event(Rc::new(
5923            move |event: &dyn Any, phase, window: &mut Window, cx: &mut App| {
5924                if let Some(event) = event.downcast_ref::<Event>() {
5925                    listener(event, phase, window, cx)
5926                }
5927            },
5928        ));
5929    }
5930
5931    /// Register a modifiers changed event listener on the window for the next frame.
5932    ///
5933    /// This is a fairly low-level method, so prefer using event handlers on elements unless you have
5934    /// a specific need to register a global listener.
5935    ///
5936    /// This method should only be called as part of the paint phase of element drawing.
5937    pub fn on_modifiers_changed(
5938        &mut self,
5939        listener: impl Fn(&ModifiersChangedEvent, &mut Window, &mut App) + 'static,
5940    ) {
5941        self.invalidator.debug_assert_paint();
5942
5943        self.next_frame.dispatch_tree.on_modifiers_changed(Rc::new(
5944            move |event: &ModifiersChangedEvent, window: &mut Window, cx: &mut App| {
5945                listener(event, window, cx)
5946            },
5947        ));
5948    }
5949
5950    /// Register a listener to be called when the given focus handle or one of its descendants receives focus.
5951    /// This does not fire if the given focus handle - or one of its descendants - was previously focused.
5952    /// Returns a subscription and persists until the subscription is dropped.
5953    pub fn on_focus_in(
5954        &mut self,
5955        handle: &FocusHandle,
5956        cx: &mut App,
5957        mut listener: impl FnMut(&mut Window, &mut App) + 'static,
5958    ) -> Subscription {
5959        let focus_id = handle.id;
5960        let (subscription, activate) =
5961            self.new_focus_listener(Box::new(move |event, window, cx| {
5962                if event.is_focus_in(focus_id) {
5963                    listener(window, cx);
5964                }
5965                true
5966            }));
5967        cx.defer(move |_| activate());
5968        subscription
5969    }
5970
5971    /// Register a listener to be called when the given focus handle or one of its descendants loses focus.
5972    /// Returns a subscription and persists until the subscription is dropped.
5973    pub fn on_focus_out(
5974        &mut self,
5975        handle: &FocusHandle,
5976        cx: &mut App,
5977        mut listener: impl FnMut(FocusOutEvent, &mut Window, &mut App) + 'static,
5978    ) -> Subscription {
5979        let focus_id = handle.id;
5980        let (subscription, activate) =
5981            self.new_focus_listener(Box::new(move |event, window, cx| {
5982                if let Some(blurred_id) = event.previous_focus_path.last().copied()
5983                    && event.is_focus_out(focus_id)
5984                {
5985                    let event = FocusOutEvent {
5986                        blurred: WeakFocusHandle {
5987                            id: blurred_id,
5988                            handles: Arc::downgrade(&cx.focus_handles),
5989                        },
5990                    };
5991                    listener(event, window, cx)
5992                }
5993                true
5994            }));
5995        cx.defer(move |_| activate());
5996        subscription
5997    }
5998
5999    fn reset_cursor_style(&self, cx: &mut App) {
6000        // Set the cursor only if we're the active window.
6001        if self.is_window_hovered() {
6002            let style = self
6003                .rendered_frame
6004                .cursor_style(self)
6005                .unwrap_or(CursorStyle::Arrow);
6006            cx.platform.set_cursor_style(style);
6007        }
6008    }
6009
6010    /// Dispatch a given keystroke as though the user had typed it.
6011    /// You can create a keystroke with Keystroke::parse("").
6012    pub fn dispatch_keystroke(&mut self, keystroke: Keystroke, cx: &mut App) -> bool {
6013        let keystroke = keystroke.with_simulated_ime();
6014        let result = self.dispatch_event(
6015            PlatformInput::KeyDown(KeyDownEvent {
6016                keystroke: keystroke.clone(),
6017                is_held: false,
6018                prefer_character_input: false,
6019            }),
6020            cx,
6021        );
6022        if !result.propagate {
6023            return true;
6024        }
6025
6026        if let Some(input) = keystroke.key_char
6027            && let Some(mut input_handler) = self.platform_window.take_input_handler()
6028        {
6029            input_handler.dispatch_input(&input, self, cx);
6030            self.platform_window.set_input_handler(input_handler);
6031            return true;
6032        }
6033
6034        false
6035    }
6036
6037    /// Return a key binding string for an action, to display in the UI. Uses the highest precedence
6038    /// binding for the action (last binding added to the keymap).
6039    pub fn keystroke_text_for(&self, action: &dyn Action) -> String {
6040        self.highest_precedence_binding_for_action(action)
6041            .map(|binding| {
6042                binding
6043                    .keystrokes()
6044                    .iter()
6045                    .map(ToString::to_string)
6046                    .collect::<Vec<_>>()
6047                    .join(" ")
6048            })
6049            .unwrap_or_else(|| action.name().to_string())
6050    }
6051
6052    /// Dispatch a mouse, keyboard, or touch event on the window.
6053    #[profiling::function]
6054    pub fn dispatch_event(&mut self, event: PlatformInput, cx: &mut App) -> DispatchEventResult {
6055        #[cfg(feature = "profiler")]
6056        self.window_profiler.begin_input(event.kind_name());
6057        let update_count_before = self.invalidator.update_count();
6058        // Track input modality for focus-visible styling and hover suppression.
6059        // Hover is suppressed during keyboard modality so that keyboard navigation
6060        // doesn't show hover highlights on the item under the mouse cursor.
6061        let old_modality = self.last_input_modality;
6062        self.last_input_modality = match &event {
6063            PlatformInput::KeyDown(_) => InputModality::Keyboard,
6064            PlatformInput::MouseMove(_) | PlatformInput::MouseDown(_) => InputModality::Mouse,
6065            PlatformInput::Touch(_) => InputModality::Touch,
6066            _ => self.last_input_modality,
6067        };
6068        if self.last_input_modality != old_modality {
6069            self.refresh();
6070        }
6071
6072        // Handlers may set this to false by calling `stop_propagation`.
6073        cx.propagate_event = true;
6074        // Handlers may set this to true by calling `prevent_default`.
6075        self.default_prevented = false;
6076
6077        let event = match event {
6078            // Track the mouse position with our own state, since accessing the platform
6079            // API for the mouse position can only occur on the main thread.
6080            PlatformInput::MouseMove(mouse_move) => {
6081                self.mouse_position = mouse_move.position;
6082                self.modifiers = mouse_move.modifiers;
6083                PlatformInput::MouseMove(mouse_move)
6084            }
6085            PlatformInput::MouseDown(mouse_down) => {
6086                self.mouse_position = mouse_down.position;
6087                self.modifiers = mouse_down.modifiers;
6088                PlatformInput::MouseDown(mouse_down)
6089            }
6090            PlatformInput::MouseUp(mouse_up) => {
6091                self.mouse_position = mouse_up.position;
6092                self.modifiers = mouse_up.modifiers;
6093                PlatformInput::MouseUp(mouse_up)
6094            }
6095            PlatformInput::MousePressure(mouse_pressure) => {
6096                PlatformInput::MousePressure(mouse_pressure)
6097            }
6098            PlatformInput::MouseExited(mouse_exited) => {
6099                self.modifiers = mouse_exited.modifiers;
6100                PlatformInput::MouseExited(mouse_exited)
6101            }
6102            PlatformInput::ModifiersChanged(modifiers_changed) => {
6103                self.modifiers = modifiers_changed.modifiers;
6104                self.capslock = modifiers_changed.capslock;
6105                PlatformInput::ModifiersChanged(modifiers_changed)
6106            }
6107            PlatformInput::ScrollWheel(scroll_wheel) => {
6108                self.mouse_position = scroll_wheel.position;
6109                self.modifiers = scroll_wheel.modifiers;
6110                PlatformInput::ScrollWheel(scroll_wheel)
6111            }
6112            PlatformInput::Pinch(pinch) => {
6113                self.mouse_position = pinch.position;
6114                self.modifiers = pinch.modifiers;
6115                PlatformInput::Pinch(pinch)
6116            }
6117            // Translate dragging and dropping of external files from the operating system
6118            // to internal drag and drop events.
6119            PlatformInput::FileDrop(file_drop) => match file_drop {
6120                FileDropEvent::Entered { position, paths } => {
6121                    self.mouse_position = position;
6122                    let source_window = self.handle.window_id();
6123                    if !cx.restore_platform_drag(source_window) && cx.active_drag.is_none() {
6124                        cx.active_drag = Some(AnyDrag {
6125                            value: Arc::new(paths.clone()),
6126                            view: cx.new(|_| paths).into(),
6127                            cursor_offset: position,
6128                            cursor_style: None,
6129                            external_payload_source: None,
6130                        });
6131                    }
6132                    PlatformInput::MouseMove(MouseMoveEvent {
6133                        position,
6134                        pressed_button: Some(MouseButton::Left),
6135                        modifiers: Modifiers::default(),
6136                    })
6137                }
6138                FileDropEvent::Pending { position } => {
6139                    self.mouse_position = position;
6140                    PlatformInput::MouseMove(MouseMoveEvent {
6141                        position,
6142                        pressed_button: Some(MouseButton::Left),
6143                        modifiers: Modifiers::default(),
6144                    })
6145                }
6146                FileDropEvent::Submit { position } => {
6147                    cx.activate(true);
6148                    self.mouse_position = position;
6149                    PlatformInput::MouseUp(MouseUpEvent {
6150                        button: MouseButton::Left,
6151                        position,
6152                        modifiers: Modifiers::default(),
6153                        click_count: 1,
6154                    })
6155                }
6156                FileDropEvent::Exited => {
6157                    if !cx.hand_restored_drag_to_platform(self.handle.window_id()) {
6158                        cx.active_drag.take();
6159                    }
6160                    self.refresh();
6161                    PlatformInput::FileDrop(FileDropEvent::Exited)
6162                }
6163                FileDropEvent::Ended => {
6164                    cx.end_platform_drag(self.handle.window_id());
6165                    self.refresh();
6166                    PlatformInput::FileDrop(FileDropEvent::Ended)
6167                }
6168            },
6169            PlatformInput::Touch(touch) => PlatformInput::Touch(touch),
6170            PlatformInput::LongPress(long_press) => {
6171                self.mouse_position = if long_press.phase == crate::TouchPhase::Started {
6172                    long_press.start_position
6173                } else {
6174                    long_press.position
6175                };
6176                if long_press.phase == crate::TouchPhase::Started {
6177                    self.long_press_capture = None;
6178                }
6179                PlatformInput::LongPress(long_press)
6180            }
6181            PlatformInput::TouchDrag(touch_drag) => {
6182                self.mouse_position = touch_drag.start_position;
6183                PlatformInput::TouchDrag(touch_drag)
6184            }
6185            PlatformInput::KeyDown(_) | PlatformInput::KeyUp(_) => event,
6186        };
6187
6188        if let Some(any_mouse_event) = event.mouse_event() {
6189            self.dispatch_mouse_event(any_mouse_event, cx);
6190        } else if let Some(any_key_event) = event.keyboard_event() {
6191            self.dispatch_key_event(any_key_event, cx);
6192        } else if let Some(touch_event) = event.touch_event() {
6193            self.dispatch_touch_event(touch_event, cx);
6194        }
6195        if let PlatformInput::LongPress(long_press) = &event {
6196            match long_press.phase {
6197                crate::TouchPhase::Started if !self.default_prevented => {
6198                    self.long_press_capture = None;
6199                }
6200                crate::TouchPhase::Ended | crate::TouchPhase::Cancelled => {
6201                    self.long_press_capture = None;
6202                }
6203                crate::TouchPhase::Started | crate::TouchPhase::Moved => {}
6204            }
6205        }
6206
6207        // Must run after the move is dispatched: the platform owns the gesture afterwards, so this
6208        // is the last chance for drag listeners to see the pointer leave and reset their state.
6209        self.promote_external_drag_to_platform(&event, cx);
6210
6211        let caused_invalidation = self.invalidator.update_count() > update_count_before;
6212        if caused_invalidation {
6213            self.input_rate_tracker.borrow_mut().record_input();
6214        }
6215        #[cfg(feature = "profiler")]
6216        self.window_profiler.end_input(caused_invalidation);
6217
6218        DispatchEventResult {
6219            propagate: cx.propagate_event,
6220            default_prevented: self.default_prevented,
6221        }
6222    }
6223
6224    fn promote_external_drag_to_platform(&mut self, event: &PlatformInput, cx: &mut App) {
6225        let PlatformInput::MouseMove(mouse_move) = event else {
6226            return;
6227        };
6228        if mouse_move.pressed_button != Some(MouseButton::Left) {
6229            return;
6230        }
6231        if Bounds::new(Point::default(), self.viewport_size).contains(&mouse_move.position) {
6232            return;
6233        }
6234        if !self.platform_window.can_start_external_drag() {
6235            return;
6236        }
6237        let Some(payload_source) = cx
6238            .active_drag
6239            .as_mut()
6240            .and_then(|drag| drag.external_payload_source.take())
6241        else {
6242            return;
6243        };
6244        let Some(payload) = payload_source(self, cx) else {
6245            return;
6246        };
6247        if self.platform_window.start_external_drag(&payload)
6248            && cx.hand_active_drag_to_platform(self.handle.window_id())
6249        {
6250            self.refresh();
6251        }
6252    }
6253
6254    /// Whether recognized touch pans may use the platform's predicted touch
6255    /// positions ([`TouchEvent::predicted_position`]) to compensate for input
6256    /// latency. Defaults to true.
6257    pub fn touch_prediction_enabled(&self) -> bool {
6258        self.touch_prediction_enabled
6259    }
6260
6261    /// Sets whether recognized touch pans may use the platform's predicted
6262    /// touch positions. Disabling drops [`TouchEvent::predicted_position`]
6263    /// before gesture recognition, so pans track only raw touch positions.
6264    pub fn set_touch_prediction_enabled(&mut self, enabled: bool) {
6265        self.touch_prediction_enabled = enabled;
6266    }
6267
6268    /// Runs the portable gesture recognizer over a raw touch event and
6269    /// dispatches whatever it resolves (scroll steps, synthesized taps)
6270    /// through the ordinary mouse-event path.
6271    fn dispatch_touch_event(&mut self, event: &TouchEvent, cx: &mut App) {
6272        let mut event = event.clone();
6273        if !self.touch_prediction_enabled {
6274            event.predicted_position = None;
6275        }
6276        let recognized_gestures = self.touch_gestures.handle_event(&event);
6277        if event.phase == crate::TouchPhase::Started
6278            && let Some(touch_drag) = self.touch_gestures.offer_touch_drag(event.id)
6279        {
6280            self.dispatch_recognized_touch_gesture(touch_drag, cx);
6281        }
6282        if event.phase == crate::TouchPhase::Started
6283            && self.touch_gestures.pending_long_press().is_some()
6284        {
6285            self.long_press_capture = None;
6286        }
6287        let mut tapped = false;
6288        for gesture in recognized_gestures {
6289            tapped |= matches!(gesture, RecognizedTouchGesture::Tap { .. });
6290            self.dispatch_recognized_touch_gesture(gesture, cx);
6291        }
6292        if event.phase == crate::TouchPhase::Started {
6293            self.schedule_long_press_timer(cx);
6294        } else if self.touch_gestures.pending_long_press().is_none() {
6295            self.long_press_timer.take();
6296        }
6297        // The platform's touch-release handler may inspect the input handler
6298        // as soon as this dispatch returns (the web platform decides virtual
6299        // keyboard visibility there, inside the user gesture). Input handlers
6300        // are registered during draw, so draw now to make them reflect any
6301        // focus change the tap just caused.
6302        if tapped && self.invalidator.is_dirty() {
6303            self.draw(cx).clear(cx);
6304        }
6305        if self.touch_gestures.has_momentum() {
6306            self.schedule_touch_momentum_tick();
6307        }
6308    }
6309
6310    fn dispatch_recognized_touch_gesture(&mut self, gesture: RecognizedTouchGesture, cx: &mut App) {
6311        match gesture {
6312            RecognizedTouchGesture::Scroll(scroll_wheel) => {
6313                self.mouse_position = scroll_wheel.position;
6314                cx.propagate_event = true;
6315                self.dispatch_mouse_event(&scroll_wheel, cx);
6316            }
6317            RecognizedTouchGesture::Tap { down, up } => {
6318                self.mouse_position = up.position;
6319                cx.propagate_event = true;
6320                self.dispatch_mouse_event(&down, cx);
6321                cx.propagate_event = true;
6322                self.dispatch_mouse_event(&up, cx);
6323            }
6324            RecognizedTouchGesture::TouchDrag(touch_drag) => {
6325                self.mouse_position = touch_drag.start_position;
6326                cx.propagate_event = true;
6327                self.default_prevented = false;
6328                let started = touch_drag.phase == crate::TouchPhase::Started;
6329                self.dispatch_mouse_event(&touch_drag, cx);
6330                if started {
6331                    self.touch_gestures
6332                        .resolve_touch_drag(self.default_prevented);
6333                }
6334            }
6335            RecognizedTouchGesture::LongPress(long_press) => {
6336                self.mouse_position = if long_press.phase == crate::TouchPhase::Started {
6337                    long_press.start_position
6338                } else {
6339                    long_press.position
6340                };
6341                cx.propagate_event = true;
6342                self.default_prevented = false;
6343                let started = long_press.phase == crate::TouchPhase::Started;
6344                let ended = matches!(
6345                    long_press.phase,
6346                    crate::TouchPhase::Ended | crate::TouchPhase::Cancelled
6347                );
6348                self.dispatch_mouse_event(&long_press, cx);
6349                if started {
6350                    let claimed = self.default_prevented;
6351                    self.touch_gestures.resolve_long_press(claimed);
6352                    if !claimed {
6353                        self.long_press_capture = None;
6354                    }
6355                }
6356                if ended {
6357                    self.long_press_capture = None;
6358                }
6359            }
6360        }
6361    }
6362
6363    fn schedule_long_press_timer(&mut self, cx: &mut App) {
6364        self.long_press_timer.take();
6365        let Some((touch_id, duration)) = self.touch_gestures.pending_long_press() else {
6366            return;
6367        };
6368        self.long_press_timer = Some(self.spawn(cx, async move |cx| {
6369            cx.background_executor.timer(duration).await;
6370            cx.update(move |window, cx| {
6371                window.long_press_timer.take();
6372                if let Some(gesture) = window.touch_gestures.offer_long_press(touch_id) {
6373                    window.dispatch_recognized_touch_gesture(gesture, cx);
6374                }
6375            })
6376            .log_err();
6377        }));
6378    }
6379
6380    fn schedule_touch_momentum_tick(&mut self) {
6381        self.on_next_frame(|window, cx| {
6382            if let Some(gesture) = window.touch_gestures.tick_momentum() {
6383                window.dispatch_recognized_touch_gesture(gesture, cx);
6384            }
6385            if window.touch_gestures.has_momentum() {
6386                window.schedule_touch_momentum_tick();
6387            }
6388        });
6389    }
6390
6391    fn dispatch_mouse_event(&mut self, event: &dyn Any, cx: &mut App) {
6392        let hit_test = self.rendered_frame.hit_test(self.mouse_position());
6393        if hit_test != self.mouse_hit_test {
6394            self.mouse_hit_test = hit_test;
6395            self.reset_cursor_style(cx);
6396        }
6397
6398        #[cfg(debug_assertions)]
6399        if self.is_inspector_picking(cx) {
6400            self.handle_inspector_mouse_event(event, cx);
6401            // When inspector is picking, all other mouse handling is skipped.
6402            return;
6403        }
6404
6405        let mut mouse_listeners = mem::take(&mut self.rendered_frame.mouse_listeners);
6406
6407        // Capture phase, events bubble from back to front. Handlers for this phase are used for
6408        // special purposes, such as detecting events outside of a given Bounds.
6409        for listener in &mut mouse_listeners {
6410            let listener = listener.as_mut().unwrap();
6411            listener(event, DispatchPhase::Capture, self, cx);
6412            if !cx.propagate_event {
6413                break;
6414            }
6415        }
6416
6417        // Bubble phase, where most normal handlers do their work.
6418        if cx.propagate_event {
6419            for listener in mouse_listeners.iter_mut().rev() {
6420                let listener = listener.as_mut().unwrap();
6421                listener(event, DispatchPhase::Bubble, self, cx);
6422                if !cx.propagate_event {
6423                    break;
6424                }
6425            }
6426        }
6427
6428        self.rendered_frame.mouse_listeners = mouse_listeners;
6429
6430        if cx.has_active_drag() {
6431            if event.is::<MouseMoveEvent>() {
6432                // If this was a mouse move event, redraw the window so that the
6433                // active drag can follow the mouse cursor.
6434                self.refresh();
6435            } else if event.is::<MouseUpEvent>() {
6436                // If this was a mouse up event, cancel the active drag and redraw
6437                // the window.
6438                cx.active_drag = None;
6439                self.refresh();
6440            }
6441        }
6442
6443        // Auto-release pointer capture on mouse up
6444        if event.is::<MouseUpEvent>() && self.captured_hitbox.is_some() {
6445            self.captured_hitbox = None;
6446        }
6447    }
6448
6449    // If modifiers are not excessive (e.g. AltGr), and the input handler is accepting text input,
6450    // we prefer the text input over bindings.
6451    fn input_preference(&mut self, event: &dyn Any, cx: &mut App) -> InputPreference {
6452        let prefer_character_input = event
6453            .downcast_ref::<KeyDownEvent>()
6454            .is_some_and(|key_down_event| key_down_event.prefer_character_input);
6455        if !prefer_character_input {
6456            return InputPreference::KeyBindings;
6457        }
6458        let Some(mut input_handler) = self.platform_window.take_input_handler() else {
6459            return InputPreference::KeyBindings;
6460        };
6461        let accepts_text_input = input_handler.accepts_text_input(self, cx);
6462        self.platform_window.set_input_handler(input_handler);
6463        if accepts_text_input {
6464            InputPreference::CharacterInput
6465        } else {
6466            InputPreference::KeyBindings
6467        }
6468    }
6469
6470    fn dispatch_key_event(&mut self, event: &dyn Any, cx: &mut App) {
6471        if self.invalidator.is_dirty() {
6472            self.draw(cx).clear(cx);
6473        }
6474
6475        let node_id = self.focus_node_id_in_rendered_frame(self.focus);
6476        let dispatch_path = self.rendered_frame.dispatch_tree.dispatch_path(node_id);
6477
6478        let mut keystroke: Option<Keystroke> = None;
6479
6480        if let Some(event) = event.downcast_ref::<ModifiersChangedEvent>() {
6481            if event.modifiers.number_of_modifiers() == 0
6482                && self.pending_modifier.modifiers.number_of_modifiers() == 1
6483                && !self.pending_modifier.saw_other_input
6484            {
6485                let key = match self.pending_modifier.modifiers {
6486                    modifiers if modifiers.shift => Some("shift"),
6487                    modifiers if modifiers.control => Some("control"),
6488                    modifiers if modifiers.alt => Some("alt"),
6489                    modifiers if modifiers.platform => Some("platform"),
6490                    modifiers if modifiers.function => Some("function"),
6491                    _ => None,
6492                };
6493                if let Some(key) = key {
6494                    keystroke = Some(Keystroke {
6495                        key: key.to_string(),
6496                        key_char: None,
6497                        modifiers: Modifiers::default(),
6498                    });
6499                }
6500            }
6501
6502            if self.pending_modifier.modifiers.number_of_modifiers() == 0
6503                && event.modifiers.number_of_modifiers() == 1
6504            {
6505                self.pending_modifier.saw_other_input = false
6506            } else if event.modifiers.number_of_modifiers() > 1 {
6507                self.pending_modifier.saw_other_input = true
6508            }
6509            self.pending_modifier.modifiers = event.modifiers
6510        } else if let Some(key_down_event) = event.downcast_ref::<KeyDownEvent>() {
6511            self.pending_modifier.saw_other_input = true;
6512            keystroke = Some(key_down_event.keystroke.clone());
6513            if key_down_event.keystroke.key_char.is_some()
6514                && matches!(
6515                    cx.cursor_hide_mode,
6516                    CursorHideMode::OnTyping | CursorHideMode::OnTypingAndAction
6517                )
6518            {
6519                cx.platform.hide_cursor_until_mouse_moves();
6520            }
6521        }
6522
6523        let Some(keystroke) = keystroke else {
6524            self.finish_dispatch_key_event(
6525                event,
6526                None,
6527                InputPreference::KeyBindings,
6528                dispatch_path,
6529                self.context_stack(),
6530                cx,
6531            );
6532            return;
6533        };
6534
6535        let input_preference = self.input_preference(event, cx);
6536
6537        cx.propagate_event = true;
6538        self.dispatch_keystroke_interceptors(
6539            &keystroke,
6540            input_preference,
6541            self.context_stack(),
6542            cx,
6543        );
6544        if !cx.propagate_event {
6545            self.finish_dispatch_key_event(
6546                event,
6547                Some(&keystroke),
6548                input_preference,
6549                dispatch_path,
6550                self.context_stack(),
6551                cx,
6552            );
6553            return;
6554        }
6555
6556        let mut currently_pending = self.pending_input.take().unwrap_or_default();
6557        if currently_pending.focus.is_some() && currently_pending.focus != self.focus {
6558            currently_pending = PendingInput::default();
6559        }
6560
6561        let match_result = self.rendered_frame.dispatch_tree.dispatch_key(
6562            currently_pending.keystrokes,
6563            keystroke.clone(),
6564            &dispatch_path,
6565        );
6566
6567        if !match_result.to_replay.is_empty() {
6568            self.replay_pending_input(match_result.to_replay, cx);
6569            cx.propagate_event = true;
6570        }
6571
6572        if !match_result.pending.is_empty() {
6573            let previous_timeout = currently_pending.timeout.take();
6574            currently_pending.keystrokes = match_result.pending;
6575            currently_pending.focus = self.focus;
6576
6577            let text_input_requires_timeout = event
6578                .downcast_ref::<KeyDownEvent>()
6579                .filter(|key_down| key_down.keystroke.key_char.is_some())
6580                .and_then(|_| self.platform_window.take_input_handler())
6581                .map_or(false, |mut input_handler| {
6582                    let accepts = input_handler.accepts_text_input(self, cx);
6583                    self.platform_window.set_input_handler(input_handler);
6584                    accepts
6585                });
6586
6587            let needs_timeout = previous_timeout.is_some()
6588                || match_result.pending_has_binding
6589                || text_input_requires_timeout;
6590            currently_pending.timeout = if needs_timeout {
6591                match previous_timeout {
6592                    Some(mut timeout) if timeout.is_paused() => {
6593                        timeout.reset_duration(PENDING_INPUT_TIMEOUT);
6594                        Some(timeout)
6595                    }
6596                    previous_timeout => {
6597                        drop(previous_timeout);
6598                        Some(self.new_pending_input_timeout(PENDING_INPUT_TIMEOUT, cx))
6599                    }
6600                }
6601            } else {
6602                None
6603            };
6604            self.pending_input = Some(currently_pending);
6605            self.pending_input_changed(cx);
6606            cx.propagate_event = false;
6607            return;
6608        }
6609
6610        // Interceptors or replayed actions may have changed whether the input handler accepts text.
6611        let input_preference = self.input_preference(event, cx);
6612        if input_preference == InputPreference::KeyBindings {
6613            for binding in match_result.bindings {
6614                self.dispatch_action_on_node(node_id, binding.action.as_ref(), cx);
6615                if !cx.propagate_event {
6616                    self.dispatch_keystroke_observers(
6617                        &keystroke,
6618                        input_preference,
6619                        Some(binding.action.as_ref()),
6620                        match_result.context_stack,
6621                        cx,
6622                    );
6623                    self.pending_input_changed(cx);
6624                    return;
6625                }
6626            }
6627        }
6628
6629        self.finish_dispatch_key_event(
6630            event,
6631            Some(&keystroke),
6632            input_preference,
6633            dispatch_path,
6634            match_result.context_stack,
6635            cx,
6636        );
6637        self.pending_input_changed(cx);
6638    }
6639
6640    fn new_pending_input_timeout(&self, duration: Duration, cx: &App) -> PendingInputTimeout {
6641        let (started_at, task) = self.start_pending_input_timeout(duration, cx);
6642        PendingInputTimeout {
6643            duration,
6644            remaining: duration,
6645            state: PendingInputTimeoutState::Running { started_at, task },
6646        }
6647    }
6648
6649    fn start_pending_input_timeout(&self, remaining: Duration, cx: &App) -> (Instant, Task<()>) {
6650        let started_at = cx.background_executor().now();
6651        let task = self.spawn(cx, async move |cx| {
6652            cx.background_executor.timer(remaining).await;
6653            cx.update(move |window, cx| {
6654                let Some(currently_pending) = window
6655                    .pending_input
6656                    .take()
6657                    .filter(|pending| pending.focus == window.focus)
6658                else {
6659                    return;
6660                };
6661
6662                let node_id = window.focus_node_id_in_rendered_frame(window.focus);
6663                let dispatch_path = window.rendered_frame.dispatch_tree.dispatch_path(node_id);
6664
6665                let to_replay = window
6666                    .rendered_frame
6667                    .dispatch_tree
6668                    .flush_dispatch(currently_pending.keystrokes, &dispatch_path);
6669
6670                window.pending_input_changed(cx);
6671                window.replay_pending_input(to_replay, cx)
6672            })
6673            .log_err();
6674        });
6675        (started_at, task)
6676    }
6677
6678    fn finish_dispatch_key_event(
6679        &mut self,
6680        event: &dyn Any,
6681        recognized_keystroke: Option<&Keystroke>,
6682        input_preference: InputPreference,
6683        dispatch_path: SmallVec<[DispatchNodeId; 32]>,
6684        context_stack: Vec<KeyContext>,
6685        cx: &mut App,
6686    ) {
6687        self.dispatch_key_down_up_event(event, &dispatch_path, cx);
6688        if !cx.propagate_event {
6689            return;
6690        }
6691
6692        self.dispatch_modifiers_changed_event(event, &dispatch_path, cx);
6693        if !cx.propagate_event {
6694            return;
6695        }
6696
6697        if let Some(keystroke) = recognized_keystroke {
6698            self.dispatch_keystroke_observers(keystroke, input_preference, None, context_stack, cx);
6699        }
6700    }
6701
6702    pub(crate) fn pending_input_changed(&mut self, cx: &mut App) {
6703        self.pending_input_observers
6704            .clone()
6705            .retain(&(), |callback| callback(self, cx));
6706    }
6707
6708    fn defer_pending_input_changed(&self, cx: &mut App) {
6709        // Avoid re-entrant entity updates by deferring observer notifications to the end of the
6710        // current effect cycle, and only for this window.
6711        let window_handle = self.handle;
6712        cx.defer(move |cx| {
6713            window_handle
6714                .update(cx, |_, window, cx| {
6715                    window.pending_input_changed(cx);
6716                })
6717                .ok();
6718        });
6719    }
6720
6721    fn dispatch_key_down_up_event(
6722        &mut self,
6723        event: &dyn Any,
6724        dispatch_path: &SmallVec<[DispatchNodeId; 32]>,
6725        cx: &mut App,
6726    ) {
6727        // Capture phase
6728        for node_id in dispatch_path {
6729            let node = self.rendered_frame.dispatch_tree.node(*node_id);
6730
6731            for key_listener in node.key_listeners.clone() {
6732                key_listener(event, DispatchPhase::Capture, self, cx);
6733                if !cx.propagate_event {
6734                    return;
6735                }
6736            }
6737        }
6738
6739        // Bubble phase
6740        for node_id in dispatch_path.iter().rev() {
6741            // Handle low level key events
6742            let node = self.rendered_frame.dispatch_tree.node(*node_id);
6743            for key_listener in node.key_listeners.clone() {
6744                key_listener(event, DispatchPhase::Bubble, self, cx);
6745                if !cx.propagate_event {
6746                    return;
6747                }
6748            }
6749        }
6750    }
6751
6752    fn dispatch_modifiers_changed_event(
6753        &mut self,
6754        event: &dyn Any,
6755        dispatch_path: &SmallVec<[DispatchNodeId; 32]>,
6756        cx: &mut App,
6757    ) {
6758        let Some(event) = event.downcast_ref::<ModifiersChangedEvent>() else {
6759            return;
6760        };
6761        for node_id in dispatch_path.iter().rev() {
6762            let node = self.rendered_frame.dispatch_tree.node(*node_id);
6763            for listener in node.modifiers_changed_listeners.clone() {
6764                listener(event, self, cx);
6765                if !cx.propagate_event {
6766                    return;
6767                }
6768            }
6769        }
6770    }
6771
6772    /// Determine whether a potential multi-stroke key binding is in progress on this window.
6773    pub fn has_pending_keystrokes(&self) -> bool {
6774        self.pending_input().is_some()
6775    }
6776
6777    #[cfg(test)]
6778    pub(crate) fn pending_input_is_none(&self) -> bool {
6779        self.pending_input.is_none()
6780    }
6781
6782    pub(crate) fn clear_pending_keystrokes(&mut self, cx: &mut App) {
6783        if self.pending_input.take().is_some() {
6784            self.defer_pending_input_changed(cx);
6785        }
6786    }
6787
6788    /// Returns pending input that can still complete a multi-stroke key binding. Input left over
6789    /// from a previous focus can never complete one.
6790    pub fn pending_input(&self) -> Option<PendingInputStatus<'_>> {
6791        self.pending_input
6792            .as_ref()
6793            .filter(|pending_input| pending_input.focus == self.focus)
6794            .map(|pending_input| PendingInputStatus {
6795                keystrokes: pending_input.keystrokes.as_slice(),
6796                timeout: pending_input
6797                    .timeout
6798                    .as_ref()
6799                    .map(PendingInputTimeout::status),
6800            })
6801    }
6802
6803    /// Pauses or resumes the current pending input timeout on behalf of `owner`.
6804    ///
6805    /// A paused timeout resumes automatically if `owner` is released. Returns whether the timeout
6806    /// state changed. A timeout paused by one owner cannot be resumed by another.
6807    pub fn set_pending_input_timeout_paused<T: 'static>(
6808        &mut self,
6809        owner: &Entity<T>,
6810        paused: bool,
6811        cx: &mut App,
6812    ) -> bool {
6813        let owner_id = owner.entity_id();
6814        if !paused {
6815            return self.resume_pending_input_timeout(owner_id, cx);
6816        }
6817
6818        let timeout = self
6819            .pending_input
6820            .as_ref()
6821            .filter(|pending_input| pending_input.focus == self.focus)
6822            .and_then(|pending_input| pending_input.timeout.as_ref());
6823        let Some(timeout) = timeout else {
6824            return false;
6825        };
6826        if timeout.is_paused() {
6827            return false;
6828        }
6829
6830        let release_subscription = self.observe_release(owner, cx, move |_, window, cx| {
6831            window.resume_pending_input_timeout(owner_id, cx);
6832        });
6833        let now = cx.background_executor().now();
6834        let changed = self
6835            .pending_input
6836            .as_mut()
6837            .filter(|pending_input| pending_input.focus == self.focus)
6838            .and_then(|pending_input| pending_input.timeout.as_mut())
6839            .is_some_and(|timeout| {
6840                timeout.pause(
6841                    PendingInputTimeoutPause {
6842                        owner_id,
6843                        _release_subscription: release_subscription,
6844                    },
6845                    now,
6846                )
6847            });
6848
6849        if changed {
6850            self.defer_pending_input_changed(cx);
6851        }
6852        changed
6853    }
6854
6855    fn resume_pending_input_timeout(&mut self, owner_id: EntityId, cx: &mut App) -> bool {
6856        let Some(remaining) = self
6857            .pending_input
6858            .as_ref()
6859            .and_then(|pending_input| pending_input.timeout.as_ref())
6860            .filter(|timeout| timeout.pause_owner_id() == Some(owner_id))
6861            .map(|timeout| timeout.remaining)
6862        else {
6863            return false;
6864        };
6865
6866        let (started_at, task) = self.start_pending_input_timeout(remaining, cx);
6867        let changed = self
6868            .pending_input
6869            .as_mut()
6870            .and_then(|pending_input| pending_input.timeout.as_mut())
6871            .is_some_and(|timeout| timeout.resume(owner_id, started_at, task));
6872
6873        if changed {
6874            self.defer_pending_input_changed(cx);
6875        }
6876        changed
6877    }
6878
6879    /// Returns the currently pending input keystrokes that might result in a multi-stroke key binding.
6880    pub fn pending_input_keystrokes(&self) -> Option<&[Keystroke]> {
6881        self.pending_input()
6882            .map(|pending_input| pending_input.keystrokes())
6883    }
6884
6885    fn replay_pending_input(&mut self, replays: SmallVec<[Replay; 1]>, cx: &mut App) {
6886        let node_id = self.focus_node_id_in_rendered_frame(self.focus);
6887        let dispatch_path = self.rendered_frame.dispatch_tree.dispatch_path(node_id);
6888
6889        'replay: for replay in replays {
6890            let event = KeyDownEvent {
6891                keystroke: replay.keystroke.clone(),
6892                is_held: false,
6893                prefer_character_input: true,
6894            };
6895
6896            cx.propagate_event = true;
6897            for binding in replay.bindings {
6898                self.dispatch_action_on_node(node_id, binding.action.as_ref(), cx);
6899                if !cx.propagate_event {
6900                    self.dispatch_keystroke_observers(
6901                        &replay.keystroke,
6902                        InputPreference::KeyBindings,
6903                        Some(binding.action.as_ref()),
6904                        Vec::default(),
6905                        cx,
6906                    );
6907                    continue 'replay;
6908                }
6909            }
6910
6911            self.dispatch_key_down_up_event(&event, &dispatch_path, cx);
6912            if !cx.propagate_event {
6913                continue 'replay;
6914            }
6915            if let Some(input) = replay.keystroke.key_char.as_ref().cloned()
6916                && let Some(mut input_handler) = self.platform_window.take_input_handler()
6917            {
6918                input_handler.dispatch_input(&input, self, cx);
6919                self.platform_window.set_input_handler(input_handler)
6920            }
6921        }
6922    }
6923
6924    fn focus_node_id_in_rendered_frame(&self, focus_id: Option<FocusId>) -> DispatchNodeId {
6925        focus_id
6926            .and_then(|focus_id| {
6927                self.rendered_frame
6928                    .dispatch_tree
6929                    .focusable_node_id(focus_id)
6930            })
6931            .unwrap_or_else(|| self.rendered_frame.dispatch_tree.root_node_id())
6932    }
6933
6934    fn dispatch_action_on_node(
6935        &mut self,
6936        node_id: DispatchNodeId,
6937        action: &dyn Action,
6938        cx: &mut App,
6939    ) {
6940        self.dispatch_action_on_node_inner(node_id, action, cx);
6941
6942        if !cx.propagate_event
6943            && cx.cursor_hide_mode == CursorHideMode::OnTypingAndAction
6944            && self.last_input_was_keyboard()
6945        {
6946            cx.platform.hide_cursor_until_mouse_moves();
6947        }
6948    }
6949
6950    fn dispatch_action_on_node_inner(
6951        &mut self,
6952        node_id: DispatchNodeId,
6953        action: &dyn Action,
6954        cx: &mut App,
6955    ) {
6956        let dispatch_path = self.rendered_frame.dispatch_tree.dispatch_path(node_id);
6957
6958        // Capture phase for global actions.
6959        cx.propagate_event = true;
6960        if let Some(mut global_listeners) = cx
6961            .global_action_listeners
6962            .remove(&action.as_any().type_id())
6963        {
6964            for listener in &global_listeners {
6965                #[cfg(feature = "profiler")]
6966                self.window_profiler.begin_action_handler(action, cx);
6967                listener(action.as_any(), DispatchPhase::Capture, cx);
6968                #[cfg(feature = "profiler")]
6969                self.window_profiler.end_action_handler();
6970                if !cx.propagate_event {
6971                    break;
6972                }
6973            }
6974
6975            global_listeners.extend(
6976                cx.global_action_listeners
6977                    .remove(&action.as_any().type_id())
6978                    .unwrap_or_default(),
6979            );
6980
6981            cx.global_action_listeners
6982                .insert(action.as_any().type_id(), global_listeners);
6983        }
6984
6985        if !cx.propagate_event {
6986            return;
6987        }
6988
6989        // Capture phase for window actions.
6990        for node_id in &dispatch_path {
6991            let node = self.rendered_frame.dispatch_tree.node(*node_id);
6992            for DispatchActionListener {
6993                action_type,
6994                listener,
6995            } in node.action_listeners.clone()
6996            {
6997                let any_action = action.as_any();
6998                if action_type == any_action.type_id() {
6999                    #[cfg(feature = "profiler")]
7000                    self.window_profiler.begin_action_handler(action, cx);
7001                    listener(any_action, DispatchPhase::Capture, self, cx);
7002                    #[cfg(feature = "profiler")]
7003                    self.window_profiler.end_action_handler();
7004
7005                    if !cx.propagate_event {
7006                        return;
7007                    }
7008                }
7009            }
7010        }
7011
7012        // Bubble phase for window actions.
7013        for node_id in dispatch_path.iter().rev() {
7014            let node = self.rendered_frame.dispatch_tree.node(*node_id);
7015            for DispatchActionListener {
7016                action_type,
7017                listener,
7018            } in node.action_listeners.clone()
7019            {
7020                let any_action = action.as_any();
7021                if action_type == any_action.type_id() {
7022                    cx.propagate_event = false; // Actions stop propagation by default during the bubble phase
7023                    #[cfg(feature = "profiler")]
7024                    self.window_profiler.begin_action_handler(action, cx);
7025                    listener(any_action, DispatchPhase::Bubble, self, cx);
7026                    #[cfg(feature = "profiler")]
7027                    self.window_profiler.end_action_handler();
7028
7029                    if !cx.propagate_event {
7030                        return;
7031                    }
7032                }
7033            }
7034        }
7035
7036        // Bubble phase for global actions.
7037        if let Some(mut global_listeners) = cx
7038            .global_action_listeners
7039            .remove(&action.as_any().type_id())
7040        {
7041            for listener in global_listeners.iter().rev() {
7042                cx.propagate_event = false; // Actions stop propagation by default during the bubble phase
7043
7044                #[cfg(feature = "profiler")]
7045                self.window_profiler.begin_action_handler(action, cx);
7046                listener(action.as_any(), DispatchPhase::Bubble, cx);
7047                #[cfg(feature = "profiler")]
7048                self.window_profiler.end_action_handler();
7049                if !cx.propagate_event {
7050                    break;
7051                }
7052            }
7053
7054            global_listeners.extend(
7055                cx.global_action_listeners
7056                    .remove(&action.as_any().type_id())
7057                    .unwrap_or_default(),
7058            );
7059
7060            cx.global_action_listeners
7061                .insert(action.as_any().type_id(), global_listeners);
7062        }
7063    }
7064
7065    /// Register the given handler to be invoked whenever the global of the given type
7066    /// is updated.
7067    pub fn observe_global<G: Global>(
7068        &mut self,
7069        cx: &mut App,
7070        f: impl Fn(&mut Window, &mut App) + 'static,
7071    ) -> Subscription {
7072        let window_handle = self.handle;
7073        let (subscription, activate) = cx.global_observers.insert(
7074            TypeId::of::<G>(),
7075            Box::new(move |cx| {
7076                window_handle
7077                    .update(cx, |_, window, cx| f(window, cx))
7078                    .is_ok()
7079            }),
7080        );
7081        cx.defer(move |_| activate());
7082        subscription
7083    }
7084
7085    /// Focus the current window and bring it to the foreground at the platform level.
7086    pub fn activate_window(&self) {
7087        self.platform_window.activate();
7088    }
7089
7090    /// Requests that the operating system draw attention to this window.
7091    pub fn request_attention(&self) {
7092        self.platform_window.request_attention();
7093    }
7094
7095    /// Minimize the current window at the platform level.
7096    pub fn minimize_window(&self) {
7097        self.platform_window.minimize();
7098    }
7099
7100    /// Toggle full screen status on the current window at the platform level.
7101    pub fn toggle_fullscreen(&self) {
7102        self.platform_window.toggle_fullscreen();
7103    }
7104
7105    /// Toggle simple (borderless) fullscreen, where the window covers the entire
7106    /// screen including the menu bar and, on notched displays, the area around the
7107    /// notch. Unlike [`Window::toggle_fullscreen`], this does not move the window
7108    /// into its own Mission Control space. Only has an effect on macOS.
7109    pub fn toggle_simple_fullscreen(&self) {
7110        self.platform_window.toggle_simple_fullscreen();
7111    }
7112
7113    /// Updates the IME panel position suggestions for languages like japanese, chinese.
7114    pub fn invalidate_character_coordinates(&self) {
7115        self.on_next_frame(|window, cx| {
7116            if let Some(mut input_handler) = window.platform_window.take_input_handler() {
7117                if let Some(bounds) = input_handler.selected_bounds(window, cx) {
7118                    window.platform_window.update_ime_position(bounds);
7119                }
7120                window.platform_window.set_input_handler(input_handler);
7121            }
7122        });
7123    }
7124
7125    /// Present a platform dialog.
7126    /// The provided message will be presented, along with buttons for each answer.
7127    /// When a button is clicked, the returned Receiver will receive the index of the clicked button.
7128    pub fn prompt<T>(
7129        &mut self,
7130        level: PromptLevel,
7131        message: &str,
7132        detail: Option<&str>,
7133        answers: &[T],
7134        cx: &mut App,
7135    ) -> oneshot::Receiver<usize>
7136    where
7137        T: Clone + Into<PromptButton>,
7138    {
7139        let prompt_builder = cx.prompt_builder.take();
7140        let Some(prompt_builder) = prompt_builder else {
7141            unreachable!("Re-entrant window prompting is not supported by GPUI");
7142        };
7143
7144        let answers = answers
7145            .iter()
7146            .map(|answer| answer.clone().into())
7147            .collect::<Vec<_>>();
7148
7149        let receiver = match &prompt_builder {
7150            PromptBuilder::Default => self
7151                .platform_window
7152                .prompt(level, message, detail, &answers)
7153                .unwrap_or_else(|| {
7154                    self.build_custom_prompt(&prompt_builder, level, message, detail, &answers, cx)
7155                }),
7156            PromptBuilder::Custom(_) => {
7157                self.build_custom_prompt(&prompt_builder, level, message, detail, &answers, cx)
7158            }
7159        };
7160
7161        cx.prompt_builder = Some(prompt_builder);
7162
7163        receiver
7164    }
7165
7166    fn build_custom_prompt(
7167        &mut self,
7168        prompt_builder: &PromptBuilder,
7169        level: PromptLevel,
7170        message: &str,
7171        detail: Option<&str>,
7172        answers: &[PromptButton],
7173        cx: &mut App,
7174    ) -> oneshot::Receiver<usize> {
7175        let (sender, receiver) = oneshot::channel();
7176        let handle = PromptHandle::new(sender);
7177        let handle = (prompt_builder)(level, message, detail, answers, handle, self, cx);
7178        self.prompt = Some(handle);
7179        receiver
7180    }
7181
7182    /// Returns whether a prompt rendered by GPUI is currently active in this window.
7183    ///
7184    /// This is only true for prompts rendered in the window (see
7185    /// [`App::set_prompt_builder`]), not for platform-native prompt dialogs.
7186    pub fn has_active_prompt(&self) -> bool {
7187        self.prompt.is_some()
7188    }
7189
7190    /// Returns the current context stack.
7191    pub fn context_stack(&self) -> Vec<KeyContext> {
7192        let node_id = self.focus_node_id_in_rendered_frame(self.focus);
7193        let dispatch_tree = &self.rendered_frame.dispatch_tree;
7194        dispatch_tree
7195            .dispatch_path(node_id)
7196            .iter()
7197            .filter_map(move |&node_id| dispatch_tree.node(node_id).context.clone())
7198            .collect()
7199    }
7200
7201    /// Returns all available actions for the focused element.
7202    pub fn available_actions(&self, cx: &App) -> Vec<Box<dyn Action>> {
7203        let node_id = self.focus_node_id_in_rendered_frame(self.focus);
7204        let mut actions = self.rendered_frame.dispatch_tree.available_actions(node_id);
7205        for action_type in cx.global_action_listeners.keys() {
7206            if let Err(ix) = actions.binary_search_by_key(action_type, |a| a.as_any().type_id()) {
7207                let action = cx.actions.build_action_type(action_type).ok();
7208                if let Some(action) = action {
7209                    actions.insert(ix, action);
7210                }
7211            }
7212        }
7213        actions
7214    }
7215
7216    /// Returns key bindings that invoke an action on the currently focused element. Bindings are
7217    /// returned in the order they were added. For display, the last binding should take precedence.
7218    pub fn bindings_for_action(&self, action: &dyn Action) -> Vec<KeyBinding> {
7219        self.rendered_frame
7220            .dispatch_tree
7221            .bindings_for_action(action, &self.rendered_frame.dispatch_tree.context_stack)
7222    }
7223
7224    /// Returns the highest precedence key binding that invokes an action on the currently focused
7225    /// element. This is more efficient than getting the last result of `bindings_for_action`.
7226    pub fn highest_precedence_binding_for_action(&self, action: &dyn Action) -> Option<KeyBinding> {
7227        self.rendered_frame
7228            .dispatch_tree
7229            .highest_precedence_binding_for_action(
7230                action,
7231                &self.rendered_frame.dispatch_tree.context_stack,
7232            )
7233    }
7234
7235    /// Returns the key bindings for an action in a context.
7236    pub fn bindings_for_action_in_context(
7237        &self,
7238        action: &dyn Action,
7239        context: KeyContext,
7240    ) -> Vec<KeyBinding> {
7241        let dispatch_tree = &self.rendered_frame.dispatch_tree;
7242        dispatch_tree.bindings_for_action(action, &[context])
7243    }
7244
7245    /// Returns the highest precedence key binding for an action in a context. This is more
7246    /// efficient than getting the last result of `bindings_for_action_in_context`.
7247    pub fn highest_precedence_binding_for_action_in_context(
7248        &self,
7249        action: &dyn Action,
7250        context: KeyContext,
7251    ) -> Option<KeyBinding> {
7252        let dispatch_tree = &self.rendered_frame.dispatch_tree;
7253        dispatch_tree.highest_precedence_binding_for_action(action, &[context])
7254    }
7255
7256    /// Returns any bindings that would invoke an action on the given focus handle if it were
7257    /// focused. Bindings are returned in the order they were added. For display, the last binding
7258    /// should take precedence.
7259    pub fn bindings_for_action_in(
7260        &self,
7261        action: &dyn Action,
7262        focus_handle: &FocusHandle,
7263    ) -> Vec<KeyBinding> {
7264        let dispatch_tree = &self.rendered_frame.dispatch_tree;
7265        let Some(context_stack) = self.context_stack_for_focus_handle(focus_handle) else {
7266            return vec![];
7267        };
7268        dispatch_tree.bindings_for_action(action, &context_stack)
7269    }
7270
7271    /// Returns the highest precedence key binding that would invoke an action on the given focus
7272    /// handle if it were focused. This is more efficient than getting the last result of
7273    /// `bindings_for_action_in`.
7274    pub fn highest_precedence_binding_for_action_in(
7275        &self,
7276        action: &dyn Action,
7277        focus_handle: &FocusHandle,
7278    ) -> Option<KeyBinding> {
7279        let dispatch_tree = &self.rendered_frame.dispatch_tree;
7280        let context_stack = self.context_stack_for_focus_handle(focus_handle)?;
7281        dispatch_tree.highest_precedence_binding_for_action(action, &context_stack)
7282    }
7283
7284    /// Find the bindings that can follow the current input sequence for the current context stack.
7285    pub fn possible_bindings_for_input(&self, input: &[Keystroke]) -> Vec<KeyBinding> {
7286        self.rendered_frame
7287            .dispatch_tree
7288            .possible_next_bindings_for_input(input, &self.context_stack())
7289    }
7290
7291    fn context_stack_for_focus_handle(
7292        &self,
7293        focus_handle: &FocusHandle,
7294    ) -> Option<Vec<KeyContext>> {
7295        let dispatch_tree = &self.rendered_frame.dispatch_tree;
7296        let node_id = dispatch_tree.focusable_node_id(focus_handle.id)?;
7297        let context_stack: Vec<_> = dispatch_tree
7298            .dispatch_path(node_id)
7299            .into_iter()
7300            .filter_map(|node_id| dispatch_tree.node(node_id).context.clone())
7301            .collect();
7302        Some(context_stack)
7303    }
7304
7305    /// Returns a generic event listener that invokes the given listener with the view and context associated with the given view handle.
7306    pub fn listener_for<T: 'static, E>(
7307        &self,
7308        view: &Entity<T>,
7309        f: impl Fn(&mut T, &E, &mut Window, &mut Context<T>) + 'static,
7310    ) -> impl Fn(&E, &mut Window, &mut App) + 'static {
7311        let view = view.downgrade();
7312        move |e: &E, window: &mut Window, cx: &mut App| {
7313            view.update(cx, |view, cx| f(view, e, window, cx)).ok();
7314        }
7315    }
7316
7317    /// Returns a generic handler that invokes the given handler with the view and context associated with the given view handle.
7318    pub fn handler_for<E: 'static, Callback: Fn(&mut E, &mut Window, &mut Context<E>) + 'static>(
7319        &self,
7320        entity: &Entity<E>,
7321        f: Callback,
7322    ) -> impl Fn(&mut Window, &mut App) + 'static {
7323        let entity = entity.downgrade();
7324        move |window: &mut Window, cx: &mut App| {
7325            entity.update(cx, |entity, cx| f(entity, window, cx)).ok();
7326        }
7327    }
7328
7329    /// Register a callback that can interrupt the closing of the current window based the returned boolean.
7330    /// If the callback returns false, the window won't be closed.
7331    pub fn on_window_should_close(
7332        &self,
7333        cx: &App,
7334        f: impl Fn(&mut Window, &mut App) -> bool + 'static,
7335    ) {
7336        let mut cx = self.to_async(cx);
7337        self.platform_window.on_should_close(Box::new(move || {
7338            cx.update(|window, cx| f(window, cx)).unwrap_or(true)
7339        }))
7340    }
7341
7342    /// Register an action listener on this node for the next frame. The type of action
7343    /// is determined by the first parameter of the given listener. When the next frame is rendered
7344    /// the listener will be cleared.
7345    ///
7346    /// This is a fairly low-level method, so prefer using action handlers on elements unless you have
7347    /// a specific need to register a listener yourself.
7348    ///
7349    /// This method should only be called as part of the paint phase of element drawing.
7350    pub fn on_action(
7351        &mut self,
7352        action_type: TypeId,
7353        listener: impl Fn(&dyn Any, DispatchPhase, &mut Window, &mut App) + 'static,
7354    ) {
7355        self.invalidator.debug_assert_paint();
7356
7357        self.next_frame
7358            .dispatch_tree
7359            .on_action(action_type, Rc::new(listener));
7360    }
7361
7362    /// Register a capturing action listener on this node for the next frame if the condition is true.
7363    /// The type of action is determined by the first parameter of the given listener. When the next
7364    /// frame is rendered the listener will be cleared.
7365    ///
7366    /// This is a fairly low-level method, so prefer using action handlers on elements unless you have
7367    /// a specific need to register a listener yourself.
7368    ///
7369    /// This method should only be called as part of the paint phase of element drawing.
7370    pub fn on_action_when(
7371        &mut self,
7372        condition: bool,
7373        action_type: TypeId,
7374        listener: impl Fn(&dyn Any, DispatchPhase, &mut Window, &mut App) + 'static,
7375    ) {
7376        self.invalidator.debug_assert_paint();
7377
7378        if condition {
7379            self.next_frame
7380                .dispatch_tree
7381                .on_action(action_type, Rc::new(listener));
7382        }
7383    }
7384
7385    /// Read information about the GPU backing this window.
7386    /// Currently returns None on Mac and Windows.
7387    pub fn gpu_specs(&self) -> Option<GpuSpecs> {
7388        self.platform_window.gpu_specs()
7389    }
7390
7391    /// Perform titlebar double-click action.
7392    /// This is macOS specific.
7393    pub fn titlebar_double_click(&self) {
7394        self.platform_window
7395            .titlebar_double_click(self.is_resizable, self.is_minimizable);
7396    }
7397
7398    /// Gets the window's title at the platform level.
7399    /// This is macOS specific.
7400    pub fn window_title(&self) -> String {
7401        self.platform_window.get_title()
7402    }
7403
7404    /// Returns a list of all tabbed windows and their titles.
7405    /// This is macOS specific.
7406    pub fn tabbed_windows(&self) -> Option<Vec<SystemWindowTab>> {
7407        self.platform_window.tabbed_windows()
7408    }
7409
7410    /// Returns the tab bar visibility.
7411    /// This is macOS specific.
7412    pub fn tab_bar_visible(&self) -> bool {
7413        self.platform_window.tab_bar_visible()
7414    }
7415
7416    /// Merges all open windows into a single tabbed window.
7417    /// This is macOS specific.
7418    pub fn merge_all_windows(&self) {
7419        self.platform_window.merge_all_windows()
7420    }
7421
7422    /// Moves the tab to a new containing window.
7423    /// This is macOS specific.
7424    pub fn move_tab_to_new_window(&self) {
7425        self.platform_window.move_tab_to_new_window()
7426    }
7427
7428    /// Shows or hides the window tab overview.
7429    /// This is macOS specific.
7430    pub fn toggle_window_tab_overview(&self) {
7431        self.platform_window.toggle_window_tab_overview()
7432    }
7433
7434    /// Sets the tabbing identifier for the window.
7435    /// This is macOS specific.
7436    pub fn set_tabbing_identifier(&self, tabbing_identifier: Option<String>) {
7437        self.platform_window
7438            .set_tabbing_identifier(tabbing_identifier)
7439    }
7440
7441    /// Request the OS to play an alert sound. On some platforms this is associated
7442    /// with the window, for others it's just a simple global function call.
7443    pub fn play_system_bell(&self) {
7444        self.platform_window.play_system_bell()
7445    }
7446
7447    /// Returns whether accessibility support is enabled for this window.
7448    ///
7449    /// This is false when the app was created with [`crate::Application::new_inaccessible`].
7450    /// Unlike [`Self::is_a11y_active`], this does not depend on whether assistive
7451    /// technology is currently connected, so it can be used to gate subscriptions
7452    /// that are only needed for accessibility.
7453    pub fn is_a11y_enabled(&self) -> bool {
7454        self.a11y.is_enabled()
7455    }
7456
7457    /// Returns whether accessibility features are active for this frame,
7458    /// i.e. whether assistive technology (such as a screen reader) is
7459    /// connected and an accessibility tree is being built.
7460    ///
7461    /// Use this to skip computing data during rendering that is only
7462    /// observable through the accessibility tree. When accessibility is
7463    /// activated, a redraw is forced, so gated work is recomputed before the
7464    /// next tree update is sent to the platform.
7465    ///
7466    /// See the [accessibility guide](crate::_accessibility) for an overview.
7467    pub fn is_a11y_active(&self) -> bool {
7468        self.a11y.is_active()
7469    }
7470
7471    /// Debug representation of the last frame's accessibility information.
7472    pub fn debug_a11y_tree_json(&self) -> Option<String> {
7473        self.a11y.debug_tree_json()
7474    }
7475
7476    /// Register a listener for an accessibility action on a specific node.
7477    /// The listener will be called when a screen reader requests the given
7478    /// action on the node identified by `node_id`.
7479    ///
7480    /// See the [accessibility guide](crate::_accessibility) for an overview.
7481    pub fn on_a11y_action(
7482        &mut self,
7483        node_id: accesskit::NodeId,
7484        action: accesskit::Action,
7485        listener: impl FnMut(Option<&accesskit::ActionData>, &mut Window, &mut App) + 'static,
7486    ) {
7487        self.a11y
7488            .action_listeners
7489            .entry(node_id)
7490            .or_default()
7491            .push((action, Box::new(listener)));
7492    }
7493
7494    #[cfg(not(target_family = "wasm"))]
7495    pub(crate) fn handle_a11y_action(&mut self, request: accesskit::ActionRequest, cx: &mut App) {
7496        // Take listeners out temporarily so the closures can borrow Window
7497        // mutably, then restore them afterward.
7498        if let Some(mut listeners) = self.a11y.action_listeners.remove(&request.target_node) {
7499            let extra_data = request.data.as_ref();
7500            let mut matched = false;
7501            for (action, listener) in &mut listeners {
7502                if *action == request.action {
7503                    listener(extra_data, self, cx);
7504                    matched = true;
7505                }
7506            }
7507            self.a11y
7508                .action_listeners
7509                .insert(request.target_node, listeners);
7510            if matched {
7511                return;
7512            }
7513        }
7514
7515        // Fall back to built-in action handling.
7516        match request.action {
7517            accesskit::Action::Click => {
7518                if let Some(bounds) = self.a11y.node_bounds.get(&request.target_node).copied() {
7519                    let center = bounds.center();
7520                    let mouse_down = PlatformInput::MouseDown(crate::MouseDownEvent {
7521                        button: MouseButton::Left,
7522                        position: center,
7523                        modifiers: Modifiers::default(),
7524                        click_count: 1,
7525                        first_mouse: false,
7526                    });
7527                    let mouse_up = PlatformInput::MouseUp(MouseUpEvent {
7528                        button: MouseButton::Left,
7529                        position: center,
7530                        modifiers: Modifiers::default(),
7531                        click_count: 1,
7532                    });
7533                    self.dispatch_event(mouse_down, cx);
7534                    self.dispatch_event(mouse_up, cx);
7535                }
7536            }
7537            accesskit::Action::Focus => {
7538                if let Some(focus_id) = self.a11y.focus_ids.get(&request.target_node).copied()
7539                    && let Some(handle) = FocusHandle::for_id(focus_id, &cx.focus_handles)
7540                {
7541                    self.focus(&handle, cx);
7542                }
7543            }
7544            accesskit::Action::Blur => {
7545                self.blur(cx);
7546            }
7547            _ => {
7548                log::debug!(
7549                    "Unhandled a11y action: {:?} on {:?}",
7550                    request.action,
7551                    request.target_node
7552                );
7553            }
7554        }
7555    }
7556
7557    /// Toggles the inspector mode on this window.
7558    #[cfg(debug_assertions)]
7559    pub fn toggle_inspector(&mut self, cx: &mut App) {
7560        self.inspector = match self.inspector {
7561            None => Some(cx.new(|_| Inspector::new())),
7562            Some(_) => {
7563                self.rendered_frame.next_inspector_instance_ids = FxHashMap::default();
7564                self.rendered_frame.inspector_hitboxes = FxHashMap::default();
7565                self.next_frame.next_inspector_instance_ids = FxHashMap::default();
7566                self.next_frame.inspector_hitboxes = FxHashMap::default();
7567                None
7568            }
7569        };
7570        self.refresh();
7571    }
7572
7573    /// Returns true if the window is in inspector mode.
7574    pub fn is_inspector_picking(&self, _cx: &App) -> bool {
7575        #[cfg(debug_assertions)]
7576        {
7577            if let Some(inspector) = &self.inspector {
7578                return inspector.read(_cx).is_picking();
7579            }
7580        }
7581        false
7582    }
7583
7584    /// Executes the provided function with mutable access to an inspector state.
7585    #[cfg(debug_assertions)]
7586    pub fn with_inspector_state<T: 'static, R>(
7587        &mut self,
7588        inspector_id: Option<&crate::InspectorElementId>,
7589        cx: &mut App,
7590        f: impl FnOnce(&mut Option<T>, &mut Self) -> R,
7591    ) -> Option<R> {
7592        let inspector_id = inspector_id?;
7593        let inspector = self.inspector.as_ref()?;
7594        if inspector.read(cx).active_element_id() != Some(inspector_id) {
7595            return None;
7596        }
7597        let inspector = inspector.clone();
7598        Some(inspector.update(cx, |inspector, _cx| {
7599            inspector.with_active_element_state(self, f)
7600        }))
7601    }
7602
7603    #[cfg(debug_assertions)]
7604    pub(crate) fn inspector_enabled(&self) -> bool {
7605        self.inspector.is_some()
7606    }
7607
7608    #[cfg(debug_assertions)]
7609    pub(crate) fn build_inspector_element_id(
7610        &mut self,
7611        path: crate::InspectorElementPath,
7612    ) -> crate::InspectorElementId {
7613        self.invalidator.debug_assert_paint_or_prepaint();
7614        let path = Rc::new(path);
7615        let next_instance_id = self
7616            .next_frame
7617            .next_inspector_instance_ids
7618            .entry(path.clone())
7619            .or_insert(0);
7620        let instance_id = *next_instance_id;
7621        *next_instance_id += 1;
7622        crate::InspectorElementId { path, instance_id }
7623    }
7624
7625    #[cfg(debug_assertions)]
7626    fn prepaint_inspector(&mut self, inspector_width: Pixels, cx: &mut App) -> Option<AnyElement> {
7627        if let Some(inspector) = self.inspector.take() {
7628            let mut inspector_element = AnyView::from(inspector.clone()).into_any_element();
7629            inspector_element.prepaint_as_root(
7630                point(self.viewport_size.width - inspector_width, px(0.0)),
7631                size(inspector_width, self.viewport_size.height).into(),
7632                self,
7633                cx,
7634            );
7635            self.inspector = Some(inspector);
7636            Some(inspector_element)
7637        } else {
7638            None
7639        }
7640    }
7641
7642    #[cfg(debug_assertions)]
7643    fn paint_inspector(&mut self, mut inspector_element: Option<AnyElement>, cx: &mut App) {
7644        if let Some(mut inspector_element) = inspector_element {
7645            inspector_element.paint(self, cx);
7646        };
7647    }
7648
7649    /// Registers a hitbox that can be used for inspector picking mode, allowing users to select and
7650    /// inspect UI elements by clicking on them.
7651    #[cfg(debug_assertions)]
7652    pub fn insert_inspector_hitbox(
7653        &mut self,
7654        hitbox_id: HitboxId,
7655        inspector_id: Option<&crate::InspectorElementId>,
7656        cx: &App,
7657    ) {
7658        self.invalidator.debug_assert_paint_or_prepaint();
7659        if !self.is_inspector_picking(cx) {
7660            return;
7661        }
7662        if let Some(inspector_id) = inspector_id {
7663            self.next_frame
7664                .inspector_hitboxes
7665                .insert(hitbox_id, inspector_id.clone());
7666        }
7667    }
7668
7669    #[cfg(debug_assertions)]
7670    fn paint_inspector_hitbox(&mut self, cx: &App) {
7671        if let Some(inspector) = self.inspector.as_ref() {
7672            let inspector = inspector.read(cx);
7673            if let Some((hitbox_id, _)) = self.hovered_inspector_hitbox(inspector, &self.next_frame)
7674                && let Some(hitbox) = self
7675                    .next_frame
7676                    .hitboxes
7677                    .iter()
7678                    .find(|hitbox| hitbox.id == hitbox_id)
7679            {
7680                self.paint_quad(crate::fill(hitbox.bounds, crate::rgba(0x61afef4d)));
7681            }
7682        }
7683    }
7684
7685    #[cfg(debug_assertions)]
7686    fn handle_inspector_mouse_event(&mut self, event: &dyn Any, cx: &mut App) {
7687        let Some(inspector) = self.inspector.clone() else {
7688            return;
7689        };
7690        if event.downcast_ref::<MouseMoveEvent>().is_some() {
7691            inspector.update(cx, |inspector, _cx| {
7692                if let Some((_, inspector_id)) =
7693                    self.hovered_inspector_hitbox(inspector, &self.rendered_frame)
7694                {
7695                    inspector.hover(inspector_id, self);
7696                }
7697            });
7698        } else if event.downcast_ref::<crate::MouseDownEvent>().is_some() {
7699            inspector.update(cx, |inspector, _cx| {
7700                if let Some((_, inspector_id)) =
7701                    self.hovered_inspector_hitbox(inspector, &self.rendered_frame)
7702                {
7703                    inspector.select(inspector_id, self);
7704                }
7705            });
7706        } else if let Some(event) = event.downcast_ref::<crate::ScrollWheelEvent>() {
7707            // This should be kept in sync with SCROLL_LINES in x11 platform.
7708            const SCROLL_LINES: f32 = 3.0;
7709            const SCROLL_PIXELS_PER_LAYER: f32 = 36.0;
7710            let delta_y = event
7711                .delta
7712                .pixel_delta(px(SCROLL_PIXELS_PER_LAYER / SCROLL_LINES))
7713                .y;
7714            if let Some(inspector) = self.inspector.clone() {
7715                inspector.update(cx, |inspector, _cx| {
7716                    if let Some(depth) = inspector.pick_depth.as_mut() {
7717                        *depth += f32::from(delta_y) / SCROLL_PIXELS_PER_LAYER;
7718                        let max_depth = self.mouse_hit_test.ids.len() as f32 - 0.5;
7719                        if *depth < 0.0 {
7720                            *depth = 0.0;
7721                        } else if *depth > max_depth {
7722                            *depth = max_depth;
7723                        }
7724                        if let Some((_, inspector_id)) =
7725                            self.hovered_inspector_hitbox(inspector, &self.rendered_frame)
7726                        {
7727                            inspector.set_active_element_id(inspector_id, self);
7728                        }
7729                    }
7730                });
7731            }
7732        }
7733    }
7734
7735    #[cfg(debug_assertions)]
7736    fn hovered_inspector_hitbox(
7737        &self,
7738        inspector: &Inspector,
7739        frame: &Frame,
7740    ) -> Option<(HitboxId, crate::InspectorElementId)> {
7741        if let Some(pick_depth) = inspector.pick_depth {
7742            let depth = (pick_depth as i64).try_into().unwrap_or(0);
7743            let max_skipped = self.mouse_hit_test.ids.len().saturating_sub(1);
7744            let skip_count = (depth as usize).min(max_skipped);
7745            for hitbox_id in self.mouse_hit_test.ids.iter().skip(skip_count) {
7746                if let Some(inspector_id) = frame.inspector_hitboxes.get(hitbox_id) {
7747                    return Some((*hitbox_id, inspector_id.clone()));
7748                }
7749            }
7750        }
7751        None
7752    }
7753
7754    /// For testing: set the current modifier keys state.
7755    /// This does not generate any events.
7756    #[cfg(any(test, feature = "test-support"))]
7757    pub fn set_modifiers(&mut self, modifiers: Modifiers) {
7758        self.modifiers = modifiers;
7759    }
7760
7761    /// For testing: simulate a mouse move event to the given position.
7762    /// This dispatches the event through the normal event handling path,
7763    /// which will trigger hover states and tooltips.
7764    #[cfg(any(test, feature = "test-support"))]
7765    pub fn simulate_mouse_move(&mut self, position: Point<Pixels>, cx: &mut App) {
7766        let event = PlatformInput::MouseMove(MouseMoveEvent {
7767            position,
7768            modifiers: self.modifiers,
7769            pressed_button: None,
7770        });
7771        let _ = self.dispatch_event(event, cx);
7772    }
7773
7774    #[inline(never)]
7775    fn take_element_state(
7776        &mut self,
7777        global_id: &GlobalElementId,
7778        state_type: TypeId,
7779    ) -> ((GlobalElementId, TypeId), Option<ElementStateBox>) {
7780        let key = (global_id.clone(), state_type);
7781        self.next_frame.accessed_element_states.push(key.clone());
7782        let state = self
7783            .next_frame
7784            .element_states
7785            .remove(&key)
7786            .or_else(|| self.rendered_frame.element_states.remove(&key));
7787        (key, state)
7788    }
7789
7790    #[inline(never)]
7791    fn insert_element_state(
7792        &mut self,
7793        key: (GlobalElementId, TypeId),
7794        state: ElementStateBox,
7795    ) -> Option<ElementStateBox> {
7796        self.next_frame.element_states.insert(key, state)
7797    }
7798
7799    #[inline(never)]
7800    fn observe_keyed_state<S: 'static>(state: &Entity<S>, current_view: EntityId, cx: &mut App) {
7801        cx.observe(state, move |_, cx| {
7802            cx.notify(current_view);
7803        })
7804        .detach();
7805    }
7806}
7807
7808// #[derive(Clone, Copy, Eq, PartialEq, Hash)]
7809slotmap::new_key_type! {
7810    /// A unique identifier for a window.
7811    pub struct WindowId;
7812}
7813
7814impl WindowId {
7815    /// Converts this window ID to a `u64`.
7816    pub fn as_u64(&self) -> u64 {
7817        self.0.as_ffi()
7818    }
7819}
7820
7821impl From<u64> for WindowId {
7822    fn from(value: u64) -> Self {
7823        WindowId(slotmap::KeyData::from_ffi(value))
7824    }
7825}
7826
7827/// A handle to a window with a specific root view type.
7828/// Note that this does not keep the window alive on its own.
7829#[derive(Deref, DerefMut)]
7830pub struct WindowHandle<V> {
7831    #[deref]
7832    #[deref_mut]
7833    pub(crate) any_handle: AnyWindowHandle,
7834    state_type: PhantomData<fn(V) -> V>,
7835}
7836
7837impl<V> Debug for WindowHandle<V> {
7838    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
7839        f.debug_struct("WindowHandle")
7840            .field("any_handle", &self.any_handle.id.as_u64())
7841            .finish()
7842    }
7843}
7844
7845impl<V: 'static + Render> WindowHandle<V> {
7846    /// Creates a new handle from a window ID.
7847    /// This does not check if the root type of the window is `V`.
7848    pub fn new(id: WindowId) -> Self {
7849        WindowHandle {
7850            any_handle: AnyWindowHandle {
7851                id,
7852                state_type: TypeId::of::<V>(),
7853                root_entity_type_name: std::any::type_name::<V>(),
7854            },
7855            state_type: PhantomData,
7856        }
7857    }
7858
7859    /// Get the root view out of this window.
7860    ///
7861    /// This will fail if the window is closed or if the root view's type does not match `V`.
7862    #[cfg(any(test, feature = "test-support"))]
7863    pub fn root<C>(&self, cx: &mut C) -> Result<Entity<V>>
7864    where
7865        C: AppContext,
7866    {
7867        cx.update_window(self.any_handle, |root_view, _, _| {
7868            root_view
7869                .downcast::<V>()
7870                .map_err(|_| anyhow!("the type of the window's root view has changed"))
7871        })?
7872    }
7873
7874    /// Updates the root view of this window.
7875    ///
7876    /// This will fail if the window has been closed or if the root view's type does not match
7877    pub fn update<C, R>(
7878        &self,
7879        cx: &mut C,
7880        update: impl FnOnce(&mut V, &mut Window, &mut Context<V>) -> R,
7881    ) -> Result<R>
7882    where
7883        C: AppContext,
7884    {
7885        cx.update_window(self.any_handle, |root_view, window, cx| {
7886            let view = root_view
7887                .downcast::<V>()
7888                .map_err(|_| anyhow!("the type of the window's root view has changed"))?;
7889
7890            Ok(view.update(cx, |view, cx| update(view, window, cx)))
7891        })?
7892    }
7893
7894    /// Read the root view out of this window.
7895    ///
7896    /// This will fail if the window is closed or if the root view's type does not match `V`.
7897    pub fn read<'a>(&self, cx: &'a App) -> Result<&'a V> {
7898        let x = cx
7899            .windows
7900            .get(self.id)
7901            .and_then(|window| {
7902                window
7903                    .as_deref()
7904                    .and_then(|window| window.root.clone())
7905                    .map(|root_view| root_view.downcast::<V>())
7906            })
7907            .context("window not found")?
7908            .map_err(|_| anyhow!("the type of the window's root view has changed"))?;
7909
7910        Ok(x.read(cx))
7911    }
7912
7913    /// Read the root view out of this window, with a callback
7914    ///
7915    /// This will fail if the window is closed or if the root view's type does not match `V`.
7916    pub fn read_with<C, R>(&self, cx: &C, read_with: impl FnOnce(&V, &App) -> R) -> Result<R>
7917    where
7918        C: AppContext,
7919    {
7920        cx.read_window(self, |root_view, cx| read_with(root_view.read(cx), cx))
7921    }
7922
7923    /// Read the root view pointer off of this window.
7924    ///
7925    /// This will fail if the window is closed or if the root view's type does not match `V`.
7926    pub fn entity<C>(&self, cx: &C) -> Result<Entity<V>>
7927    where
7928        C: AppContext,
7929    {
7930        cx.read_window(self, |root_view, _cx| root_view)
7931    }
7932
7933    /// Check if this window is 'active'.
7934    ///
7935    /// Will return `None` if the window is closed or currently
7936    /// borrowed.
7937    pub fn is_active(&self, cx: &mut App) -> Option<bool> {
7938        cx.update_window(self.any_handle, |_, window, _| window.is_window_active())
7939            .ok()
7940    }
7941}
7942
7943impl<V> Copy for WindowHandle<V> {}
7944
7945impl<V> Clone for WindowHandle<V> {
7946    fn clone(&self) -> Self {
7947        *self
7948    }
7949}
7950
7951impl<V> PartialEq for WindowHandle<V> {
7952    fn eq(&self, other: &Self) -> bool {
7953        self.any_handle == other.any_handle
7954    }
7955}
7956
7957impl<V> Eq for WindowHandle<V> {}
7958
7959impl<V> Hash for WindowHandle<V> {
7960    fn hash<H: Hasher>(&self, state: &mut H) {
7961        self.any_handle.hash(state);
7962    }
7963}
7964
7965impl<V: 'static> From<WindowHandle<V>> for AnyWindowHandle {
7966    fn from(val: WindowHandle<V>) -> Self {
7967        val.any_handle
7968    }
7969}
7970
7971/// A handle to a window with any root view type, which can be downcast to a window with a specific root view type.
7972#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
7973pub struct AnyWindowHandle {
7974    pub(crate) id: WindowId,
7975    state_type: TypeId,
7976    root_entity_type_name: &'static str,
7977}
7978
7979impl AnyWindowHandle {
7980    /// Get the ID of this window.
7981    pub fn window_id(&self) -> WindowId {
7982        self.id
7983    }
7984
7985    /// Returns the name of the window's declared root entity type.
7986    pub fn root_entity_type_name(&self) -> &'static str {
7987        self.root_entity_type_name
7988    }
7989
7990    /// Attempt to convert this handle to a window handle with a specific root view type.
7991    /// If the types do not match, this will return `None`.
7992    pub fn downcast<T: 'static>(&self) -> Option<WindowHandle<T>> {
7993        if TypeId::of::<T>() == self.state_type {
7994            Some(WindowHandle {
7995                any_handle: *self,
7996                state_type: PhantomData,
7997            })
7998        } else {
7999            None
8000        }
8001    }
8002
8003    /// Updates the state of the root view of this window.
8004    ///
8005    /// This will fail if the window has been closed.
8006    pub fn update<C, R>(
8007        self,
8008        cx: &mut C,
8009        update: impl FnOnce(AnyView, &mut Window, &mut App) -> R,
8010    ) -> Result<R>
8011    where
8012        C: AppContext,
8013    {
8014        cx.update_window(self, update)
8015    }
8016
8017    /// Read the state of the root view of this window.
8018    ///
8019    /// This will fail if the window has been closed.
8020    pub fn read<T, C, R>(self, cx: &C, read: impl FnOnce(Entity<T>, &App) -> R) -> Result<R>
8021    where
8022        C: AppContext,
8023        T: 'static,
8024    {
8025        let view = self
8026            .downcast::<T>()
8027            .context("the type of the window's root view has changed")?;
8028
8029        cx.read_window(&view, read)
8030    }
8031}
8032
8033impl HasWindowHandle for Window {
8034    fn window_handle(&self) -> Result<raw_window_handle::WindowHandle<'_>, HandleError> {
8035        self.platform_window.window_handle()
8036    }
8037}
8038
8039impl HasDisplayHandle for Window {
8040    fn display_handle(
8041        &self,
8042    ) -> std::result::Result<raw_window_handle::DisplayHandle<'_>, HandleError> {
8043        self.platform_window.display_handle()
8044    }
8045}
8046
8047/// An identifier for an [`Element`].
8048///
8049/// Can be constructed with a string, a number, or both, as well
8050/// as other internal representations.
8051#[derive(Clone, Debug, Eq, PartialEq, Hash)]
8052pub enum ElementId {
8053    /// The ID of a View element
8054    View(EntityId),
8055    /// An integer ID.
8056    Integer(u64),
8057    /// A string based ID.
8058    Name(SharedString),
8059    /// A UUID.
8060    Uuid(Uuid),
8061    /// An ID that's equated with a focus handle.
8062    FocusHandle(FocusId),
8063    /// A combination of a name and an integer.
8064    NamedInteger(SharedString, u64),
8065    /// A path.
8066    Path(Arc<std::path::Path>),
8067    /// A code location.
8068    CodeLocation(core::panic::Location<'static>),
8069    /// A labeled child of an element.
8070    NamedChild(Arc<ElementId>, SharedString),
8071    /// A byte array ID (used for text-anchors)
8072    OpaqueId([u8; 20]),
8073}
8074
8075impl ElementId {
8076    /// Constructs an `ElementId::NamedInteger` from a name and `usize`.
8077    pub fn named_usize(name: impl Into<SharedString>, integer: usize) -> ElementId {
8078        Self::NamedInteger(name.into(), integer as u64)
8079    }
8080}
8081
8082impl Display for ElementId {
8083    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
8084        match self {
8085            ElementId::View(entity_id) => write!(f, "view-{}", entity_id)?,
8086            ElementId::Integer(ix) => write!(f, "{}", ix)?,
8087            ElementId::Name(name) => write!(f, "{}", name)?,
8088            ElementId::FocusHandle(_) => write!(f, "FocusHandle")?,
8089            ElementId::NamedInteger(s, i) => write!(f, "{}-{}", s, i)?,
8090            ElementId::Uuid(uuid) => write!(f, "{}", uuid)?,
8091            ElementId::Path(path) => write!(f, "{}", path.display())?,
8092            ElementId::CodeLocation(location) => write!(f, "{}", location)?,
8093            ElementId::NamedChild(id, name) => write!(f, "{}-{}", id, name)?,
8094            ElementId::OpaqueId(opaque_id) => write!(f, "{:x?}", opaque_id)?,
8095        }
8096
8097        Ok(())
8098    }
8099}
8100
8101impl TryInto<SharedString> for ElementId {
8102    type Error = anyhow::Error;
8103
8104    fn try_into(self) -> anyhow::Result<SharedString> {
8105        if let ElementId::Name(name) = self {
8106            Ok(name)
8107        } else {
8108            anyhow::bail!("element id is not string")
8109        }
8110    }
8111}
8112
8113impl From<u64> for ElementId {
8114    fn from(id: u64) -> Self {
8115        ElementId::Integer(id)
8116    }
8117}
8118
8119impl From<usize> for ElementId {
8120    fn from(id: usize) -> Self {
8121        ElementId::Integer(id as u64)
8122    }
8123}
8124
8125impl From<i32> for ElementId {
8126    fn from(id: i32) -> Self {
8127        Self::Integer(id as u64)
8128    }
8129}
8130
8131impl From<SharedString> for ElementId {
8132    fn from(name: SharedString) -> Self {
8133        ElementId::Name(name)
8134    }
8135}
8136
8137impl From<String> for ElementId {
8138    fn from(name: String) -> Self {
8139        ElementId::Name(name.into())
8140    }
8141}
8142
8143impl From<Arc<str>> for ElementId {
8144    fn from(name: Arc<str>) -> Self {
8145        ElementId::Name(name.into())
8146    }
8147}
8148
8149impl From<Arc<std::path::Path>> for ElementId {
8150    fn from(path: Arc<std::path::Path>) -> Self {
8151        ElementId::Path(path)
8152    }
8153}
8154
8155impl From<&'static str> for ElementId {
8156    fn from(name: &'static str) -> Self {
8157        ElementId::Name(SharedString::new_static(name))
8158    }
8159}
8160
8161impl<'a> From<&'a FocusHandle> for ElementId {
8162    fn from(handle: &'a FocusHandle) -> Self {
8163        ElementId::FocusHandle(handle.id)
8164    }
8165}
8166
8167impl From<(&'static str, EntityId)> for ElementId {
8168    fn from((name, id): (&'static str, EntityId)) -> Self {
8169        ElementId::NamedInteger(SharedString::new_static(name), id.as_u64())
8170    }
8171}
8172
8173impl From<(&'static str, usize)> for ElementId {
8174    fn from((name, id): (&'static str, usize)) -> Self {
8175        ElementId::NamedInteger(SharedString::new_static(name), id as u64)
8176    }
8177}
8178
8179impl From<(SharedString, usize)> for ElementId {
8180    fn from((name, id): (SharedString, usize)) -> Self {
8181        ElementId::NamedInteger(name, id as u64)
8182    }
8183}
8184
8185impl From<(&'static str, u64)> for ElementId {
8186    fn from((name, id): (&'static str, u64)) -> Self {
8187        ElementId::NamedInteger(SharedString::new_static(name), id)
8188    }
8189}
8190
8191impl From<Uuid> for ElementId {
8192    fn from(value: Uuid) -> Self {
8193        Self::Uuid(value)
8194    }
8195}
8196
8197impl From<(&'static str, u32)> for ElementId {
8198    fn from((name, id): (&'static str, u32)) -> Self {
8199        ElementId::NamedInteger(SharedString::new_static(name), u64::from(id))
8200    }
8201}
8202
8203impl<T: Into<SharedString>> From<(ElementId, T)> for ElementId {
8204    fn from((id, name): (ElementId, T)) -> Self {
8205        ElementId::NamedChild(Arc::new(id), name.into())
8206    }
8207}
8208
8209impl From<&'static core::panic::Location<'static>> for ElementId {
8210    fn from(location: &'static core::panic::Location<'static>) -> Self {
8211        ElementId::CodeLocation(*location)
8212    }
8213}
8214
8215impl From<[u8; 20]> for ElementId {
8216    fn from(opaque_id: [u8; 20]) -> Self {
8217        ElementId::OpaqueId(opaque_id)
8218    }
8219}
8220
8221/// A rectangle to be rendered in the window at the given position and size.
8222/// Passed as an argument [`Window::paint_quad`].
8223#[derive(Clone)]
8224pub struct PaintQuad {
8225    /// The bounds of the quad within the window.
8226    pub bounds: Bounds<Pixels>,
8227    /// The radii of the quad's corners.
8228    pub corner_radii: Corners<Pixels>,
8229    /// The background color of the quad.
8230    pub background: Background,
8231    /// The widths of the quad's borders.
8232    pub border_widths: Edges<Pixels>,
8233    /// The color of the quad's borders.
8234    pub border_color: Hsla,
8235    /// The style of the quad's borders.
8236    pub border_style: BorderStyle,
8237}
8238
8239impl PaintQuad {
8240    /// Sets the corner radii of the quad.
8241    pub fn corner_radii(self, corner_radii: impl Into<Corners<Pixels>>) -> Self {
8242        PaintQuad {
8243            corner_radii: corner_radii.into(),
8244            ..self
8245        }
8246    }
8247
8248    /// Sets the border widths of the quad.
8249    pub fn border_widths(self, border_widths: impl Into<Edges<Pixels>>) -> Self {
8250        PaintQuad {
8251            border_widths: border_widths.into(),
8252            ..self
8253        }
8254    }
8255
8256    /// Sets the border color of the quad.
8257    pub fn border_color(self, border_color: impl Into<Hsla>) -> Self {
8258        PaintQuad {
8259            border_color: border_color.into(),
8260            ..self
8261        }
8262    }
8263
8264    /// Sets the background color of the quad.
8265    pub fn background(self, background: impl Into<Background>) -> Self {
8266        PaintQuad {
8267            background: background.into(),
8268            ..self
8269        }
8270    }
8271}
8272
8273/// Creates a quad with the given parameters.
8274pub fn quad(
8275    bounds: Bounds<Pixels>,
8276    corner_radii: impl Into<Corners<Pixels>>,
8277    background: impl Into<Background>,
8278    border_widths: impl Into<Edges<Pixels>>,
8279    border_color: impl Into<Hsla>,
8280    border_style: BorderStyle,
8281) -> PaintQuad {
8282    PaintQuad {
8283        bounds,
8284        corner_radii: corner_radii.into(),
8285        background: background.into(),
8286        border_widths: border_widths.into(),
8287        border_color: border_color.into(),
8288        border_style,
8289    }
8290}
8291
8292/// Creates a filled quad with the given bounds and background color.
8293pub fn fill(bounds: impl Into<Bounds<Pixels>>, background: impl Into<Background>) -> PaintQuad {
8294    PaintQuad {
8295        bounds: bounds.into(),
8296        corner_radii: (0.).into(),
8297        background: background.into(),
8298        border_widths: (0.).into(),
8299        border_color: transparent_black(),
8300        border_style: BorderStyle::default(),
8301    }
8302}
8303
8304/// Creates a rectangle outline with the given bounds, border color, and a 1px border width
8305pub fn outline(
8306    bounds: impl Into<Bounds<Pixels>>,
8307    border_color: impl Into<Hsla>,
8308    border_style: BorderStyle,
8309) -> PaintQuad {
8310    PaintQuad {
8311        bounds: bounds.into(),
8312        corner_radii: (0.).into(),
8313        background: transparent_black().into(),
8314        border_widths: (1.).into(),
8315        border_color: border_color.into(),
8316        border_style,
8317    }
8318}
8319
8320#[inline(never)]
8321fn with_element_arena_erased(callback: &mut dyn FnMut(&mut Arena)) -> Result<(), AccessError> {
8322    if let Some(arena_pointer) = CURRENT_ELEMENT_ARENA.try_with(Cell::get)? {
8323        // SAFETY: The pointer is valid for the duration of the draw operation
8324        // that set it, and we're being called during that same draw.
8325        let arena_cell = unsafe { &*arena_pointer };
8326        callback(&mut arena_cell.borrow_mut());
8327        Ok(())
8328    } else {
8329        ELEMENT_ARENA.try_with(|arena| callback(&mut arena.borrow_mut()))
8330    }
8331}
8332
8333#[cfg(test)]
8334mod tests {
8335    use std::{
8336        cell::{Cell, RefCell},
8337        path::PathBuf,
8338        rc::Rc,
8339        time::Duration,
8340    };
8341
8342    use crate::{
8343        AnyWindowHandle, AppContext as _, Bounds, ContentMask, Context, DispatchPhase,
8344        DragMoveEvent, Empty, ExternalDragPayload, ExternalPaths, FileDragPaths, FileDropEvent,
8345        FocusHandle, InputEvent as _, InteractiveElement as _, IntoElement, KeyDownEvent,
8346        Keystroke, LongPressEvent, MouseButton, MouseDownEvent, MouseMoveEvent, ParentElement,
8347        Pixels, PlatformInput, Point, Render, RequestFrameOptions, ScaledPixels,
8348        StatefulInteractiveElement as _, Styled, TestAppContext, TouchDragEvent, TouchEvent,
8349        TouchId, TouchPhase, Underline, UnderlineStyle, Window, WindowAppearance, WindowOptions,
8350        canvas, div, hsla, point, px, size,
8351    };
8352
8353    #[gpui::test]
8354    fn test_cover_bounds_preserves_empty_fractional_clips(cx: &mut TestAppContext) {
8355        let window = cx.add_window(|_, _| EmptyView);
8356        window
8357            .update(cx, |_, window, _| {
8358                for scale in [1., 1.25, 2.] {
8359                    window.scale_factor = scale;
8360                    let tile = Bounds::new(point(px(10.), px(10.)), size(px(20.), px(20.)));
8361                    let glyph = Bounds::new(point(px(40.25), px(15.25)), size(px(4.), px(4.)));
8362                    for clip in [
8363                        tile.intersect(&glyph),
8364                        Bounds::new(point(px(40.25), px(15.25)), size(px(0.), px(4.))),
8365                        Bounds::new(point(px(15.25), px(40.25)), size(px(4.), px(0.))),
8366                    ] {
8367                        assert!(clip.is_empty());
8368                        assert!(window.cover_bounds(clip).is_empty());
8369                    }
8370                    let visible = Bounds::new(point(px(15.25), px(15.25)), size(px(0.1), px(0.1)));
8371                    assert!(!window.cover_bounds(visible).is_empty());
8372                }
8373            })
8374            .unwrap();
8375    }
8376
8377    #[cfg(feature = "profiler")]
8378    #[gpui::test]
8379    fn test_frame_requests_and_skips_are_journaled(cx: &mut TestAppContext) {
8380        use crate::FrameRequestSource;
8381        use crate::profiler::journal::{
8382            self, ForegroundJournalEntry, FrameSkipReason, IntervalBoundary,
8383        };
8384        use scheduler::Instant;
8385
8386        cx.app.borrow_mut().mode = crate::app::GpuiMode::Production;
8387        let window = cx.add_window(|_, _| EmptyView);
8388        let platform_window = cx.test_window(window.into());
8389        platform_window.simulate_frame_request(RequestFrameOptions::default());
8390        let (journal, _guard) = journal::install_test_foreground_journal(64, 4);
8391        let mut collector = journal.collector();
8392
8393        for (signal_at, source) in [
8394            (Some(Instant::now()), FrameRequestSource::NativeCallback),
8395            (Some(Instant::now()), FrameRequestSource::LocalSchedule),
8396            (None, FrameRequestSource::NativeCallback),
8397        ] {
8398            platform_window.simulate_frame_request(RequestFrameOptions {
8399                signal_at,
8400                signal_source: source,
8401                require_presentation: true,
8402                ..Default::default()
8403            });
8404            let entries = collector.collect_unseen().entries;
8405            let signal_index = entries
8406                .iter()
8407                .position(|entry| {
8408                    matches!(
8409                        entry,
8410                        ForegroundJournalEntry::PlatformSignal(signal)
8411                            if signal.window_id == window.window_id()
8412                                && signal.signal_at == signal_at
8413                                && signal.source == source
8414                                && signal_at.is_none_or(|at| signal.handled_at >= at)
8415                    )
8416                })
8417                .expect("frame request metadata");
8418            let skip_index = entries
8419                .iter()
8420                .position(|entry| {
8421                    matches!(
8422                        entry,
8423                        ForegroundJournalEntry::Boundary(IntervalBoundary::FrameSkipped(skipped))
8424                            if skipped.window_id == window.window_id()
8425                                && skipped.reason == FrameSkipReason::NoRenderNeeded
8426                    )
8427                })
8428                .expect("completed no-render boundary");
8429            assert!(signal_index < skip_index);
8430        }
8431    }
8432
8433    #[cfg(feature = "profiler")]
8434    #[gpui::test]
8435    fn test_frame_demand_survives_throttling(cx: &mut TestAppContext) {
8436        use crate::profiler::journal::{
8437            self, ForegroundJournalEntry, FrameSkipReason, IntervalBoundary,
8438        };
8439        use scheduler::Instant;
8440
8441        // Test mode draws during effect flushing, bypassing platform frame throttling.
8442        cx.app.borrow_mut().mode = crate::app::GpuiMode::Production;
8443        let (journal, _guard) = journal::install_test_foreground_journal(256, 4);
8444        let mut collector = journal.collector();
8445        for initially_dirty in [true, false] {
8446            // Keep the throttle closed without depending on short wall-clock deadlines.
8447            let window = cx
8448                .app
8449                .borrow_mut()
8450                .open_window(
8451                    WindowOptions {
8452                        inactive_frame_interval: Some(Duration::from_secs(3600)),
8453                        ..Default::default()
8454                    },
8455                    |_, cx| cx.new(|_| EmptyView),
8456                )
8457                .expect("open inactive test window");
8458            let platform_window = cx.test_window(window.into());
8459            platform_window.simulate_active_status_change(false);
8460            platform_window.simulate_frame_request(RequestFrameOptions::default());
8461            let callback_ran = Rc::new(Cell::new(false));
8462            let draws_before = window
8463                .update(cx, |_, window, _| {
8464                    let draws_before = window
8465                        .frame_duration_snapshot()
8466                        .draw_duration_histogram
8467                        .len();
8468                    if initially_dirty {
8469                        window.refresh();
8470                    }
8471                    window.on_next_frame({
8472                        let callback_ran = callback_ran.clone();
8473                        move |window, _| {
8474                            callback_ran.set(true);
8475                            window.refresh();
8476                        }
8477                    });
8478                    draws_before
8479                })
8480                .expect("schedule throttled frame");
8481            // Skips only seal retained work, so give the throttled skip some.
8482            let input_at = Instant::now();
8483            journal::record_input(journal::InputTiming {
8484                kind: "test",
8485                start: input_at,
8486                end: input_at,
8487                caused_invalidation: false,
8488            });
8489            collector.collect_unseen();
8490            platform_window.simulate_frame_request(RequestFrameOptions {
8491                signal_at: Some(Instant::now()),
8492                ..Default::default()
8493            });
8494            window
8495                .update(cx, |_, window, _| {
8496                    assert_eq!(
8497                        window
8498                            .frame_duration_snapshot()
8499                            .draw_duration_histogram
8500                            .len(),
8501                        draws_before,
8502                    );
8503                })
8504                .expect("inspect deferred frame");
8505            assert!(!callback_ran.get());
8506            assert!(collector.collect_unseen().entries.iter().any(|entry| {
8507                matches!(
8508                    entry,
8509                    ForegroundJournalEntry::Boundary(IntervalBoundary::FrameSkipped(skipped))
8510                        if skipped.window_id == window.window_id()
8511                            && skipped.reason == FrameSkipReason::InactiveFrameRateLimit
8512                )
8513            }));
8514            platform_window.simulate_frame_request(RequestFrameOptions {
8515                signal_at: Some(Instant::now()),
8516                require_presentation: true,
8517                ..Default::default()
8518            });
8519            window
8520                .update(cx, |_, window, _| {
8521                    assert_eq!(
8522                        window
8523                            .frame_duration_snapshot()
8524                            .draw_duration_histogram
8525                            .len(),
8526                        draws_before + 1,
8527                    );
8528                })
8529                .expect("inspect presented frame");
8530            assert!(callback_ran.get());
8531        }
8532    }
8533
8534    /// Visibility transitions reach observers exactly once each, with the new
8535    /// state already stored on the window, and never wake the platform for a
8536    /// frame: the platform requests one itself when it resumes presenting.
8537    #[gpui::test]
8538    fn test_window_visibility(cx: &mut TestAppContext) {
8539        use crate::WindowVisibility;
8540
8541        let window = cx.add_window(|_, _| EmptyView);
8542        let observed = Rc::new(RefCell::new(Vec::new()));
8543        let _subscription = window
8544            .update(cx, {
8545                let observed = observed.clone();
8546                move |_, window, _| {
8547                    assert_eq!(window.visibility(), WindowVisibility::Visible);
8548                    assert!(window.is_visible());
8549                    window.observe_window_visibility(move |visibility, window, _| {
8550                        assert_eq!(window.visibility(), visibility);
8551                        observed.borrow_mut().push(visibility);
8552                    })
8553                }
8554            })
8555            .unwrap();
8556        let test_window = cx.test_window(window.into());
8557        let frame_wake_count = test_window.frame_wake_count();
8558
8559        test_window.simulate_visibility_change(WindowVisibility::Hidden);
8560        assert_eq!(*observed.borrow(), [WindowVisibility::Hidden]);
8561        window
8562            .update(cx, |_, window, _| assert!(!window.is_visible()))
8563            .unwrap();
8564
8565        // Platforms may report the same state again; observers only see changes.
8566        test_window.simulate_visibility_change(WindowVisibility::Hidden);
8567        assert_eq!(observed.borrow().len(), 1);
8568
8569        test_window.simulate_visibility_change(WindowVisibility::Visible);
8570        assert_eq!(
8571            *observed.borrow(),
8572            [WindowVisibility::Hidden, WindowVisibility::Visible]
8573        );
8574        window
8575            .update(cx, |_, window, _| assert!(window.is_visible()))
8576            .unwrap();
8577        assert_eq!(test_window.frame_wake_count(), frame_wake_count);
8578    }
8579
8580    /// App learns display state from the platform's display notifications,
8581    /// and a window from the platform's report of which display it is on.
8582    #[gpui::test]
8583    fn test_display_tracking(cx: &mut TestAppContext) {
8584        use crate::{DisplayChanges, DisplayEvent, DisplayId, Subscription};
8585
8586        let sixty_hertz = Duration::from_secs(1) / 60;
8587        let one_hundred_twenty_hertz = Duration::from_secs(1) / 120;
8588        let one_hundred_forty_four_hertz = Duration::from_secs(1) / 144;
8589
8590        let display_events = Rc::new(RefCell::new(Vec::new()));
8591        let _display_subscription = cx.update({
8592            let display_events = display_events.clone();
8593            move |cx| cx.observe_displays(move |event, _| display_events.borrow_mut().push(event))
8594        });
8595
8596        let window = cx.add_window(|window, cx| DisplayTracker {
8597            refresh_intervals: Vec::new(),
8598            _subscription: cx.observe_window_display(
8599                window,
8600                |tracker: &mut DisplayTracker, window, cx| {
8601                    tracker.refresh_intervals.push(window.refresh_interval(cx));
8602                },
8603            ),
8604        });
8605        let window_notifications = Rc::new(RefCell::new(Vec::new()));
8606        let _window_subscription = window
8607            .update(cx, {
8608                let window_notifications = window_notifications.clone();
8609                move |_, window, cx| {
8610                    assert_eq!(window.refresh_interval(cx), Some(sixty_hertz));
8611                    window.observe_window_display(move |window, cx| {
8612                        window_notifications
8613                            .borrow_mut()
8614                            .push((window.display_id, window.refresh_interval(cx)));
8615                    })
8616                }
8617            })
8618            .unwrap();
8619        let test_window = cx.test_window(window.into());
8620
8621        // The window may hear that it moved before App hears the display was
8622        // connected. App learns about the display before the window's
8623        // observers run, and the platform's later notification changes
8624        // nothing.
8625        cx.test_platform()
8626            .connect_display(DisplayId(2), Some(one_hundred_twenty_hertz));
8627        test_window.simulate_move_to_display(DisplayId(2));
8628        assert_eq!(
8629            window_notifications.take(),
8630            [(Some(DisplayId(2)), Some(one_hundred_twenty_hertz))]
8631        );
8632        assert_eq!(display_events.take(), [DisplayEvent::Added(DisplayId(2))]);
8633        cx.simulate_display_refresh_interval_change(DisplayId(2), Some(one_hundred_twenty_hertz));
8634        assert!(window_notifications.borrow().is_empty());
8635
8636        // Platforms may report a move that isn't one.
8637        test_window.simulate_move_to_display(DisplayId(2));
8638        assert!(window_notifications.borrow().is_empty());
8639
8640        cx.simulate_display_refresh_interval_change(
8641            DisplayId(2),
8642            Some(one_hundred_forty_four_hertz),
8643        );
8644        assert_eq!(
8645            window_notifications.take(),
8646            [(Some(DisplayId(2)), Some(one_hundred_forty_four_hertz))]
8647        );
8648
8649        // Changes to a display the window isn't on don't notify it.
8650        cx.simulate_display_refresh_interval_change(DisplayId(1), Some(one_hundred_twenty_hertz));
8651        cx.simulate_display_removed(DisplayId(1));
8652        assert!(window_notifications.borrow().is_empty());
8653
8654        assert_eq!(
8655            display_events.take(),
8656            [
8657                DisplayEvent::Changed {
8658                    id: DisplayId(2),
8659                    changes: DisplayChanges::REFRESH_INTERVAL,
8660                },
8661                DisplayEvent::Changed {
8662                    id: DisplayId(1),
8663                    changes: DisplayChanges::REFRESH_INTERVAL,
8664                },
8665                DisplayEvent::Removed(DisplayId(1)),
8666            ]
8667        );
8668        window
8669            .update(cx, |tracker, _, _| {
8670                assert_eq!(
8671                    tracker.refresh_intervals,
8672                    [
8673                        Some(one_hundred_twenty_hertz),
8674                        Some(one_hundred_forty_four_hertz)
8675                    ]
8676                );
8677            })
8678            .unwrap();
8679
8680        struct DisplayTracker {
8681            refresh_intervals: Vec<Option<Duration>>,
8682            _subscription: Subscription,
8683        }
8684
8685        impl Render for DisplayTracker {
8686            fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
8687                Empty
8688            }
8689        }
8690    }
8691
8692    #[gpui::test]
8693    fn test_fully_visible_bounds_preserve_layout_viewport(cx: &mut TestAppContext) {
8694        let window = cx.add_window(|_, _| EmptyView);
8695        let mut platform_window = cx.test_window(window.into());
8696        platform_window.simulate_resize(size(px(400.), px(800.)));
8697        window
8698            .update(cx, |_, window, _| {
8699                assert_eq!(
8700                    window.visual_viewport_bounds(),
8701                    Bounds::new(Point::default(), size(px(400.), px(800.)))
8702                );
8703                assert_eq!(
8704                    window.fully_visible_bounds(),
8705                    window.visual_viewport_bounds()
8706                );
8707            })
8708            .unwrap();
8709
8710        platform_window.simulate_frame_request(RequestFrameOptions::default());
8711        let wakes = platform_window.frame_wake_count();
8712        let visual_bounds = Bounds::new(point(px(10.), px(40.)), size(px(380.), px(460.)));
8713        platform_window.simulate_visual_viewport_change(visual_bounds);
8714        assert!(platform_window.frame_wake_count() > wakes);
8715        platform_window.simulate_frame_request(RequestFrameOptions::default());
8716        let wakes = platform_window.frame_wake_count();
8717        platform_window.simulate_insets_change(crate::WindowInsets {
8718            safe_area: crate::Edges {
8719                top: px(60.),
8720                right: px(20.),
8721                bottom: px(30.),
8722                left: px(-10.),
8723            },
8724            ime: crate::Edges {
8725                bottom: px(350.),
8726                ..Default::default()
8727            },
8728        });
8729        assert!(platform_window.frame_wake_count() > wakes);
8730        window
8731            .update(cx, |_, window, _| {
8732                assert_eq!(window.viewport_size(), size(px(400.), px(800.)));
8733                assert_eq!(window.visual_viewport_bounds(), visual_bounds);
8734                assert_eq!(
8735                    window.fully_visible_bounds(),
8736                    Bounds::new(point(px(10.), px(60.)), size(px(370.), px(390.)))
8737                );
8738                window.request_virtual_keyboard();
8739                window.dismiss_virtual_keyboard();
8740                assert_eq!(window.viewport_size(), size(px(400.), px(800.)));
8741            })
8742            .unwrap();
8743        assert_eq!(platform_window.virtual_keyboard_requests(), 1);
8744        assert_eq!(platform_window.virtual_keyboard_dismissals(), 1);
8745
8746        platform_window.simulate_insets_change(crate::WindowInsets {
8747            safe_area: crate::Edges {
8748                top: px(900.),
8749                left: px(500.),
8750                ..Default::default()
8751            },
8752            ..Default::default()
8753        });
8754        window
8755            .update(cx, |_, window, _| {
8756                assert_eq!(
8757                    window.fully_visible_bounds().size,
8758                    size(Pixels::ZERO, Pixels::ZERO)
8759                );
8760            })
8761            .unwrap();
8762    }
8763
8764    struct EmptyView;
8765
8766    impl Render for EmptyView {
8767        fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
8768            div()
8769        }
8770    }
8771
8772    struct OpensWindowOnPaint {
8773        opened: Rc<Cell<bool>>,
8774    }
8775
8776    impl Render for OpensWindowOnPaint {
8777        fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
8778            let opened = self.opened.clone();
8779            div()
8780                .size_full()
8781                .child(canvas(
8782                    |_, _, _| {},
8783                    move |_, _, _window, cx| {
8784                        if !opened.replace(true) {
8785                            cx.open_window(WindowOptions::default(), |_, cx| cx.new(|_| EmptyView))
8786                                .unwrap();
8787                        }
8788                    },
8789                ))
8790                // Siblings painted after the canvas: their elements were
8791                // allocated in the arena before the nested draw, so they detect
8792                // a mid-draw arena clear when painted afterwards.
8793                .child(div().child("after"))
8794        }
8795    }
8796
8797    /// Opening a window synchronously draws it and requests an element arena
8798    /// clear. When that happens from within another window's draw (here: from
8799    /// an element's paint), the clear must be deferred until the outer draw
8800    /// finishes, or the outer draw's arena-allocated elements would be freed
8801    /// out from under it.
8802    #[test]
8803    fn test_window_opened_during_draw_defers_arena_clear() {
8804        let mut cx = TestAppContext::single();
8805
8806        let opened = Rc::new(Cell::new(false));
8807        // add_window draws once, which runs the nested open_window mid-draw.
8808        let window = cx.add_window({
8809            let opened = opened.clone();
8810            move |_, _| OpensWindowOnPaint { opened }
8811        });
8812
8813        assert!(opened.get());
8814        assert_eq!(cx.windows().len(), 2);
8815
8816        // The deferred clear must actually run once the outer draw unwinds:
8817        // subsequent draws of both windows work against a fresh arena.
8818        cx.update_window(window.into(), |_, window, cx| window.draw(cx).clear(cx))
8819            .unwrap();
8820    }
8821
8822    #[test]
8823    fn test_scale_factor_change_preserves_bounds_and_survives_resize() {
8824        let mut cx = TestAppContext::single();
8825        let window = cx.add_window(|_, _| EmptyView);
8826        let handle: AnyWindowHandle = window.into();
8827        let window_state = |cx: &mut TestAppContext| {
8828            cx.update_window(handle, |_, window, _| {
8829                (
8830                    window.scale_factor(),
8831                    window.bounds(),
8832                    window.viewport_size(),
8833                )
8834            })
8835            .unwrap()
8836        };
8837
8838        let (scale_factor, mut expected_bounds, _) = window_state(&mut cx);
8839        assert_eq!(scale_factor, 2.0);
8840
8841        for (scale_factor, resized_size) in [
8842            (1.0, size(px(800.), px(600.))),
8843            (1.25, size(px(640.), px(480.))),
8844            (2.0, size(px(1024.), px(768.))),
8845        ] {
8846            cx.simulate_window_scale_factor_change(handle, scale_factor);
8847            assert_eq!(
8848                window_state(&mut cx),
8849                (scale_factor, expected_bounds, expected_bounds.size)
8850            );
8851
8852            cx.simulate_window_resize(handle, resized_size);
8853            expected_bounds.size = resized_size;
8854            assert_eq!(
8855                window_state(&mut cx),
8856                (scale_factor, expected_bounds, resized_size)
8857            );
8858        }
8859    }
8860
8861    /// Platforms that stop requesting frames for idle windows (currently web)
8862    /// rely on the frame waker firing whenever frame demand arises; a demand
8863    /// source that skips the waker shows up there as a window that silently
8864    /// stops repainting until unrelated activity wakes it.
8865    #[gpui::test]
8866    fn test_frame_waker_fires_on_frame_demand(cx: &mut TestAppContext) {
8867        let window = cx.add_window(|_, _| EmptyView);
8868        let test_window = cx.test_window(window.into());
8869
8870        // Windows start dirty, and that can predate waker installation;
8871        // installing the waker must deliver the pending wake or the first
8872        // frame would never be requested.
8873        assert!(
8874            test_window.frame_wake_count() >= 1,
8875            "opening a window must wake the frame source for the initial frame"
8876        );
8877
8878        // Serve outstanding demand (present the frame drawn by `add_window`).
8879        test_window.simulate_frame_request(RequestFrameOptions::default());
8880
8881        // An idle window must not wake on clean frames or plain updates, or
8882        // the frame source could never stop.
8883        let baseline = test_window.frame_wake_count();
8884        test_window.simulate_frame_request(RequestFrameOptions::default());
8885        window.update(cx, |_, _, _| {}).unwrap();
8886        assert_eq!(
8887            test_window.frame_wake_count(),
8888            baseline,
8889            "clean frames and non-notifying updates must not wake the frame source"
8890        );
8891
8892        // Notifying a view in an idle window is the core demand signal.
8893        window.update(cx, |_, _, cx| cx.notify()).unwrap();
8894        assert!(
8895            test_window.frame_wake_count() > baseline,
8896            "notifying a view in an idle window must wake the frame source"
8897        );
8898
8899        // Serving that demand returns to idle without further wakes.
8900        test_window.simulate_frame_request(RequestFrameOptions::default());
8901        let baseline = test_window.frame_wake_count();
8902        test_window.simulate_frame_request(RequestFrameOptions::default());
8903        assert_eq!(
8904            test_window.frame_wake_count(),
8905            baseline,
8906            "serving demand must return the window to idle"
8907        );
8908
8909        // Next-frame callbacks create demand without dirtying the window.
8910        window
8911            .update(cx, |_, window, _| window.on_next_frame(|_, _| {}))
8912            .unwrap();
8913        assert!(
8914            test_window.frame_wake_count() > baseline,
8915            "scheduling a next-frame callback in an idle window must wake the frame source"
8916        );
8917    }
8918
8919    /// A frame request that arrives while next-frame callbacks are pending
8920    /// must never strand them: either the frame runs them, or (when the
8921    /// inactive-window frame-rate throttle defers the frame) the waker fires
8922    /// so another request is delivered.
8923    #[gpui::test]
8924    fn test_pending_next_frame_callbacks_are_not_stranded(cx: &mut TestAppContext) {
8925        let window = cx.add_window(|_, _| EmptyView);
8926        let test_window = cx.test_window(window.into());
8927        // Establish a recent last-frame time so the inactive-window throttle
8928        // can engage on the next request.
8929        test_window.simulate_frame_request(RequestFrameOptions::default());
8930
8931        let callback_ran = Rc::new(Cell::new(false));
8932        window
8933            .update(cx, {
8934                let callback_ran = callback_ran.clone();
8935                move |_, window, _| {
8936                    window.on_next_frame(move |_, _| callback_ran.set(true));
8937                }
8938            })
8939            .unwrap();
8940
8941        let baseline = test_window.frame_wake_count();
8942        test_window.simulate_frame_request(RequestFrameOptions::default());
8943        // The test window is inactive, so this request throttles to ~30fps
8944        // when it lands within the throttle interval of the previous frame
8945        // (the common case here, but timing-dependent): the callback is
8946        // deferred and the waker must re-arm the frame source. On a slow run
8947        // the request instead lands outside the interval and runs the
8948        // callback directly.
8949        assert!(
8950            test_window.frame_wake_count() > baseline || callback_ran.get(),
8951            "a frame request with pending next-frame callbacks must either run them or re-arm the frame source"
8952        );
8953    }
8954
8955    #[gpui::test]
8956    fn color_mode_default_platform_is_compatible_and_rejects_drawing(cx: &mut TestAppContext) {
8957        let handle = cx.add_window(|_, _| EmptyView);
8958        handle
8959            .update(cx, |_, window, _| {
8960                let original = window.color_status();
8961                assert_eq!(original, crate::WindowColorStatus::default());
8962                assert_eq!(
8963                    window
8964                        .set_color_mode(crate::WindowColorMode::Default)
8965                        .unwrap(),
8966                    original
8967                );
8968                assert!(
8969                    window
8970                        .set_color_mode(crate::WindowColorMode::WideGamutSdr)
8971                        .is_err()
8972                );
8973                assert_eq!(window.color_status(), original);
8974                for phase in [
8975                    super::DrawPhase::Prepaint,
8976                    super::DrawPhase::Paint,
8977                    super::DrawPhase::Focus,
8978                ] {
8979                    window.invalidator.set_phase(phase);
8980                    assert!(
8981                        window
8982                            .set_color_mode(crate::WindowColorMode::Default)
8983                            .is_err()
8984                    );
8985                    assert_eq!(window.color_status(), original);
8986                }
8987                window.invalidator.set_phase(super::DrawPhase::None);
8988            })
8989            .unwrap();
8990    }
8991
8992    #[gpui::test]
8993    fn test_window_reports_no_raw_handle_instead_of_panicking(cx: &mut TestAppContext) {
8994        use raw_window_handle::{HandleError, HasDisplayHandle as _, HasWindowHandle as _};
8995
8996        let window = cx.add_window(|_, _| EmptyView);
8997        window
8998            .update(cx, |_, window, _| {
8999                assert!(matches!(
9000                    window.window_handle(),
9001                    Err(HandleError::NotSupported)
9002                ));
9003                assert!(matches!(
9004                    window.display_handle(),
9005                    Err(HandleError::NotSupported)
9006                ));
9007            })
9008            .unwrap();
9009    }
9010
9011    #[gpui::test]
9012    fn test_appearance_change_runs_after_app_update(cx: &mut TestAppContext) {
9013        let window = cx.add_window(|_, _| EmptyView);
9014        let observed_appearance = Rc::new(Cell::new(None));
9015        let _subscription = window
9016            .update(cx, {
9017                let observed_appearance = observed_appearance.clone();
9018                move |_, window, _| {
9019                    window.observe_window_appearance(move |window, _| {
9020                        observed_appearance.set(Some(window.appearance()));
9021                    })
9022                }
9023            })
9024            .unwrap();
9025        let test_window = cx.test_window(window.into());
9026
9027        cx.update(|_| {
9028            test_window.simulate_appearance_change(WindowAppearance::Dark);
9029            assert_eq!(observed_appearance.get(), None);
9030        });
9031        cx.run_until_parked();
9032
9033        assert_eq!(observed_appearance.get(), Some(WindowAppearance::Dark));
9034    }
9035
9036    #[gpui::test]
9037    fn queued_frame_callback_wakes_a_parked_render_loop(cx: &mut TestAppContext) {
9038        let window = cx.add_window(|_, _| Empty);
9039        let test_window = cx.test_window(window.into());
9040
9041        assert!(test_window.simulate_scheduled_frame());
9042        assert!(test_window.simulate_scheduled_frame());
9043        assert!(!test_window.frame_scheduled());
9044
9045        cx.update_window(window.into(), |_, window, _| {
9046            window.active.set(true);
9047            window.on_next_frame(|_, _| {});
9048        })
9049        .unwrap();
9050        assert!(
9051            test_window.frame_scheduled(),
9052            "queuing work on a parked window must wake the render loop"
9053        );
9054
9055        assert!(test_window.simulate_scheduled_frame());
9056        assert!(
9057            test_window.frame_scheduled(),
9058            "presenting the frame must await one compositor callback"
9059        );
9060        assert!(test_window.simulate_scheduled_frame());
9061        assert!(!test_window.frame_scheduled());
9062    }
9063
9064    #[gpui::test]
9065    fn pending_presentation_wakes_a_parked_render_loop(cx: &mut TestAppContext) {
9066        let window = cx.add_window(|_, _| Empty);
9067        let test_window = cx.test_window(window.into());
9068
9069        assert!(test_window.simulate_scheduled_frame());
9070        assert!(test_window.simulate_scheduled_frame());
9071        assert!(!test_window.frame_scheduled());
9072
9073        cx.update_window(window.into(), |_, window, cx| window.draw(cx).clear(cx))
9074            .unwrap();
9075
9076        assert!(
9077            test_window.frame_scheduled(),
9078            "a rendered scene awaiting presentation must wake the render loop"
9079        );
9080    }
9081
9082    #[gpui::test]
9083    fn callback_queued_during_a_frame_requests_a_follow_up(cx: &mut TestAppContext) {
9084        let window = cx.add_window(|_, _| Empty);
9085        let test_window = cx.test_window(window.into());
9086
9087        let callback_ran = Rc::new(Cell::new(false));
9088        cx.update_window(window.into(), |_, window, _| {
9089            // Inactive windows are frame-rate throttled, which would defer the
9090            // ticks this test drives manually.
9091            window.active.set(true);
9092            let callback_ran = callback_ran.clone();
9093            window.on_next_frame(move |window, _| {
9094                window.on_next_frame(move |_, _| callback_ran.set(true));
9095            });
9096        })
9097        .unwrap();
9098
9099        assert!(test_window.simulate_scheduled_frame());
9100        assert!(!callback_ran.get());
9101        assert!(
9102            test_window.frame_scheduled(),
9103            "a callback queued mid-frame must schedule a follow-up before the loop parks"
9104        );
9105
9106        assert!(test_window.simulate_scheduled_frame());
9107        assert!(callback_ran.get());
9108    }
9109
9110    struct RootView {
9111        explicit_size: bool,
9112        child_bounds: Rc<Cell<Bounds<Pixels>>>,
9113    }
9114
9115    impl Render for RootView {
9116        fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
9117            let child_bounds = self.child_bounds.clone();
9118            let root = div().flex().flex_col().child(
9119                canvas(
9120                    move |bounds, _, _| child_bounds.set(bounds),
9121                    |_, _, _, _| {},
9122                )
9123                .size_full(),
9124            );
9125            if self.explicit_size {
9126                root.w(px(300.)).h(px(200.))
9127            } else {
9128                root
9129            }
9130        }
9131    }
9132
9133    #[test]
9134    fn auto_sized_window_root_fills_the_window() {
9135        let mut cx = TestAppContext::single();
9136        let child_bounds = Rc::new(Cell::new(Bounds::default()));
9137        let window = cx.add_window({
9138            let child_bounds = child_bounds.clone();
9139            move |_, _| RootView {
9140                explicit_size: false,
9141                child_bounds,
9142            }
9143        });
9144
9145        let viewport_size = cx
9146            .update_window(window.into(), |_, window, cx| {
9147                window.draw(cx).clear(cx);
9148                window.viewport_size()
9149            })
9150            .unwrap();
9151
9152        assert_eq!(child_bounds.get().size, viewport_size);
9153    }
9154
9155    #[test]
9156    fn explicitly_sized_window_root_keeps_its_size() {
9157        let mut cx = TestAppContext::single();
9158        let child_bounds = Rc::new(Cell::new(Bounds::default()));
9159        let window = cx.add_window({
9160            let child_bounds = child_bounds.clone();
9161            move |_, _| RootView {
9162                explicit_size: true,
9163                child_bounds,
9164            }
9165        });
9166
9167        cx.update_window(window.into(), |_, window, cx| {
9168            window.draw(cx).clear(cx);
9169        })
9170        .unwrap();
9171
9172        assert_eq!(child_bounds.get().size, size(px(300.), px(200.)));
9173    }
9174
9175    struct FileDragView {
9176        path: PathBuf,
9177        observed_drag_moves: Rc<RefCell<Vec<Point<Pixels>>>>,
9178        observed_drops: Rc<RefCell<Vec<PathBuf>>>,
9179    }
9180
9181    struct FileDropExitView(Rc<Cell<usize>>);
9182
9183    impl Render for FileDropExitView {
9184        fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
9185            div().size_full().on_file_drop_exit({
9186                let observed_file_drop_exit = self.0.clone();
9187                move |_, _, _| observed_file_drop_exit.set(observed_file_drop_exit.get() + 1)
9188            })
9189        }
9190    }
9191
9192    impl Render for FileDragView {
9193        fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
9194            div()
9195                .id("file-drag")
9196                .size_full()
9197                .on_drag(self.path.clone(), |_, _, _, cx| cx.new(|_| Empty))
9198                .external_drag_payload(|path: &PathBuf, _, _| {
9199                    Some(ExternalDragPayload::Files(FileDragPaths::new([(
9200                        path.clone(),
9201                        true,
9202                    )])))
9203                })
9204                .on_drag_move({
9205                    let observed_drag_moves = self.observed_drag_moves.clone();
9206                    move |event: &DragMoveEvent<PathBuf>, _, _| {
9207                        observed_drag_moves.borrow_mut().push(event.event.position);
9208                    }
9209                })
9210                .on_drop({
9211                    let observed_drops = self.observed_drops.clone();
9212                    move |path: &PathBuf, _, _| observed_drops.borrow_mut().push(path.clone())
9213                })
9214        }
9215    }
9216
9217    #[gpui::test]
9218    fn file_drag_is_promoted_once_and_restored_in_source_window(cx: &mut TestAppContext) {
9219        struct Drag {
9220            window: AnyWindowHandle,
9221            observed_drag_moves: Rc<RefCell<Vec<Point<Pixels>>>>,
9222            observed_drops: Rc<RefCell<Vec<PathBuf>>>,
9223        }
9224
9225        fn start_drag(cx: &mut TestAppContext, path: PathBuf, platform_result: bool) -> Drag {
9226            let observed_drag_moves = Rc::new(RefCell::new(Vec::new()));
9227            let observed_drops = Rc::new(RefCell::new(Vec::new()));
9228            let window: AnyWindowHandle = cx
9229                .add_window({
9230                    let observed_drag_moves = observed_drag_moves.clone();
9231                    let observed_drops = observed_drops.clone();
9232                    move |_, _| FileDragView {
9233                        path,
9234                        observed_drag_moves,
9235                        observed_drops,
9236                    }
9237                })
9238                .into();
9239            cx.test_window(window)
9240                .set_start_external_drag_result(platform_result);
9241
9242            let update_result = cx.update_window(window, |_, window, cx| {
9243                window.draw(cx).clear(cx);
9244                window.dispatch_event(
9245                    MouseDownEvent {
9246                        position: point(px(10.), px(10.)),
9247                        button: MouseButton::Left,
9248                        modifiers: Default::default(),
9249                        click_count: 1,
9250                        first_mouse: false,
9251                    }
9252                    .to_platform_input(),
9253                    cx,
9254                );
9255                window.dispatch_event(
9256                    MouseMoveEvent {
9257                        position: point(px(20.), px(20.)),
9258                        pressed_button: Some(MouseButton::Left),
9259                        modifiers: Default::default(),
9260                    }
9261                    .to_platform_input(),
9262                    cx,
9263                );
9264                assert!(cx.active_drag.is_some());
9265            });
9266            assert!(
9267                update_result.is_ok(),
9268                "failed to start drag: {update_result:?}"
9269            );
9270
9271            assert!(cx.test_window(window).external_drag_files().is_empty());
9272            Drag {
9273                window,
9274                observed_drag_moves,
9275                observed_drops,
9276            }
9277        }
9278
9279        let successful_path = PathBuf::from("/tmp/successful-drag");
9280        let successful = start_drag(cx, successful_path.clone(), true);
9281        let outside_position = point(px(-1.), px(20.));
9282        let update_result = cx.update_window(successful.window, |_, window, cx| {
9283            window.dispatch_event(
9284                MouseMoveEvent {
9285                    position: outside_position,
9286                    pressed_button: Some(MouseButton::Left),
9287                    modifiers: Default::default(),
9288                }
9289                .to_platform_input(),
9290                cx,
9291            );
9292            assert!(cx.active_drag.is_none());
9293        });
9294        assert!(
9295            update_result.is_ok(),
9296            "failed to promote drag: {update_result:?}"
9297        );
9298        assert_eq!(
9299            cx.test_window(successful.window).external_drag_files(),
9300            [(successful_path.clone(), true)]
9301        );
9302        // Views must still see the move that leaves the window, otherwise they never learn to tear
9303        // down the drag state they built up while the pointer was inside.
9304        assert_eq!(
9305            successful.observed_drag_moves.borrow().last(),
9306            Some(&outside_position)
9307        );
9308
9309        let first_destination_exit_count = Rc::new(Cell::new(0));
9310        let first_destination: AnyWindowHandle = cx
9311            .add_window({
9312                let first_destination_exit_count = first_destination_exit_count.clone();
9313                move |_, _| FileDropExitView(first_destination_exit_count)
9314            })
9315            .into();
9316        let second_destination_exit_count = Rc::new(Cell::new(0));
9317        let second_destination: AnyWindowHandle = cx
9318            .add_window({
9319                let second_destination_exit_count = second_destination_exit_count.clone();
9320                move |_, _| FileDropExitView(second_destination_exit_count)
9321            })
9322            .into();
9323        let reentry_position = point(px(30.), px(30.));
9324        let external_paths = || ExternalPaths([successful_path.clone()].into_iter().collect());
9325        let update_result = cx.update_window(first_destination, |_, window, cx| {
9326            window.draw(cx).clear(cx);
9327            window.dispatch_event(
9328                FileDropEvent::Entered {
9329                    position: reentry_position,
9330                    paths: external_paths(),
9331                }
9332                .to_platform_input(),
9333                cx,
9334            );
9335            assert!(
9336                cx.active_drag
9337                    .as_ref()
9338                    .is_some_and(|drag| drag.value.downcast_ref::<ExternalPaths>().is_some())
9339            );
9340            window.dispatch_event(FileDropEvent::Exited.to_platform_input(), cx);
9341            assert!(cx.active_drag.is_none());
9342            assert_eq!(first_destination_exit_count.get(), 1);
9343            assert_eq!(second_destination_exit_count.get(), 0);
9344        });
9345        assert!(
9346            update_result.is_ok(),
9347            "failed to handle drag in first destination window: {update_result:?}"
9348        );
9349
9350        let update_result = cx.update_window(second_destination, |_, window, cx| {
9351            window.draw(cx).clear(cx);
9352            window.dispatch_event(
9353                PlatformInput::KeyDown(KeyDownEvent {
9354                    keystroke: Keystroke::parse("down").expect("valid keystroke"),
9355                    is_held: false,
9356                    prefer_character_input: false,
9357                }),
9358                cx,
9359            );
9360            window.dispatch_event(
9361                FileDropEvent::Entered {
9362                    position: reentry_position,
9363                    paths: external_paths(),
9364                }
9365                .to_platform_input(),
9366                cx,
9367            );
9368            assert!(
9369                cx.active_drag
9370                    .as_ref()
9371                    .is_some_and(|drag| drag.value.downcast_ref::<ExternalPaths>().is_some())
9372            );
9373            assert_eq!(first_destination_exit_count.get(), 1);
9374            assert_eq!(second_destination_exit_count.get(), 0);
9375
9376            window.dispatch_event(FileDropEvent::Exited.to_platform_input(), cx);
9377            assert!(cx.active_drag.is_none());
9378            assert_eq!(first_destination_exit_count.get(), 1);
9379            assert_eq!(second_destination_exit_count.get(), 1);
9380        });
9381        assert!(
9382            update_result.is_ok(),
9383            "failed to handle drag in second destination window: {update_result:?}"
9384        );
9385
9386        let update_result = cx.update_window(successful.window, |_, window, cx| {
9387            window.dispatch_event(
9388                FileDropEvent::Entered {
9389                    position: reentry_position,
9390                    paths: external_paths(),
9391                }
9392                .to_platform_input(),
9393                cx,
9394            );
9395            assert!(
9396                cx.active_drag
9397                    .as_ref()
9398                    .is_some_and(|drag| drag.value.downcast_ref::<PathBuf>().is_some())
9399            );
9400            assert_eq!(
9401                successful.observed_drag_moves.borrow().last(),
9402                Some(&reentry_position)
9403            );
9404
9405            window.dispatch_event(FileDropEvent::Exited.to_platform_input(), cx);
9406            assert!(cx.active_drag.is_none());
9407
9408            window.dispatch_event(
9409                FileDropEvent::Entered {
9410                    position: reentry_position,
9411                    paths: external_paths(),
9412                }
9413                .to_platform_input(),
9414                cx,
9415            );
9416            assert!(
9417                cx.active_drag
9418                    .as_ref()
9419                    .is_some_and(|drag| drag.value.downcast_ref::<PathBuf>().is_some())
9420            );
9421
9422            window.dispatch_event(
9423                FileDropEvent::Submit {
9424                    position: reentry_position,
9425                }
9426                .to_platform_input(),
9427                cx,
9428            );
9429            assert_eq!(
9430                successful.observed_drops.borrow().as_slice(),
9431                std::slice::from_ref(&successful_path)
9432            );
9433            assert!(cx.active_drag.is_none());
9434
9435            window.dispatch_event(FileDropEvent::Exited.to_platform_input(), cx);
9436            assert!(cx.active_drag.is_none());
9437            window.dispatch_event(FileDropEvent::Ended.to_platform_input(), cx);
9438            assert!(cx.active_drag.is_none());
9439
9440            window.dispatch_event(
9441                FileDropEvent::Entered {
9442                    position: reentry_position,
9443                    paths: external_paths(),
9444                }
9445                .to_platform_input(),
9446                cx,
9447            );
9448            assert!(
9449                cx.active_drag
9450                    .as_ref()
9451                    .is_some_and(|drag| drag.value.downcast_ref::<ExternalPaths>().is_some())
9452            );
9453            window.dispatch_event(FileDropEvent::Exited.to_platform_input(), cx);
9454        });
9455        assert!(
9456            update_result.is_ok(),
9457            "failed to restore drag in source window: {update_result:?}"
9458        );
9459
9460        let cancelled_path = PathBuf::from("/tmp/cancelled-drag");
9461        let cancelled = start_drag(cx, cancelled_path.clone(), true);
9462        let update_result = cx.update_window(cancelled.window, |_, window, cx| {
9463            window.dispatch_event(
9464                MouseMoveEvent {
9465                    position: outside_position,
9466                    pressed_button: Some(MouseButton::Left),
9467                    modifiers: Default::default(),
9468                }
9469                .to_platform_input(),
9470                cx,
9471            );
9472            assert!(cx.active_drag.is_none());
9473
9474            window.dispatch_event(
9475                FileDropEvent::Entered {
9476                    position: reentry_position,
9477                    paths: ExternalPaths([cancelled_path].into_iter().collect()),
9478                }
9479                .to_platform_input(),
9480                cx,
9481            );
9482            assert!(
9483                cx.active_drag
9484                    .as_ref()
9485                    .is_some_and(|drag| drag.value.downcast_ref::<PathBuf>().is_some())
9486            );
9487            assert!(cx.stop_active_drag(window));
9488            assert!(cx.active_drag.is_none());
9489        });
9490        assert!(
9491            update_result.is_ok(),
9492            "failed to cancel restored drag: {update_result:?}"
9493        );
9494        assert!(!cx.update(|cx| cx.end_platform_drag(cancelled.window.window_id())));
9495
9496        let removed_path = PathBuf::from("/tmp/removed-window-drag");
9497        let removed = start_drag(cx, removed_path, true);
9498        let removed_window_id = removed.window.window_id();
9499        let update_result = cx.update_window(removed.window, |_, window, cx| {
9500            window.dispatch_event(
9501                MouseMoveEvent {
9502                    position: outside_position,
9503                    pressed_button: Some(MouseButton::Left),
9504                    modifiers: Default::default(),
9505                }
9506                .to_platform_input(),
9507                cx,
9508            );
9509            assert!(cx.active_drag.is_none());
9510            window.remove_window();
9511        });
9512        assert!(
9513            update_result.is_ok(),
9514            "failed to remove drag source window: {update_result:?}"
9515        );
9516        assert!(!cx.update(|cx| cx.end_platform_drag(removed_window_id)));
9517
9518        let failed_path = PathBuf::from("/tmp/failed-drag");
9519        let failed = start_drag(cx, failed_path.clone(), false);
9520        let update_result = cx.update_window(failed.window, |_, window, cx| {
9521            for x_position in [-1., -2.] {
9522                window.dispatch_event(
9523                    MouseMoveEvent {
9524                        position: point(px(x_position), px(20.)),
9525                        pressed_button: Some(MouseButton::Left),
9526                        modifiers: Default::default(),
9527                    }
9528                    .to_platform_input(),
9529                    cx,
9530                );
9531            }
9532            assert!(cx.active_drag.is_some());
9533        });
9534        assert!(
9535            update_result.is_ok(),
9536            "failed to retain drag after platform failure: {update_result:?}"
9537        );
9538        assert_eq!(
9539            cx.test_window(failed.window).external_drag_files(),
9540            [(failed_path, true)]
9541        );
9542    }
9543
9544    struct FocusForwarder {
9545        a: FocusHandle,
9546        b: FocusHandle,
9547    }
9548
9549    impl Render for FocusForwarder {
9550        fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
9551            div()
9552                .size_full()
9553                .child(div().w(px(50.)).h(px(50.)).track_focus(&self.a))
9554                .child(div().w(px(50.)).h(px(50.)).track_focus(&self.b))
9555        }
9556    }
9557
9558    /// When a focus listener moves focus again (e.g. a dock forwarding focus to its
9559    /// active panel), the resulting focus events must be dispatched without waiting
9560    /// for an unrelated redraw of the window.
9561    #[gpui::test]
9562    fn test_focus_moved_by_focus_listener_is_dispatched(cx: &mut TestAppContext) {
9563        let b_focus_count = Rc::new(Cell::new(0));
9564        let window = cx.add_window({
9565            let b_focus_count = b_focus_count.clone();
9566            move |window, cx| {
9567                let a = cx.focus_handle();
9568                let b = cx.focus_handle();
9569                cx.on_focus(&a, window, |this: &mut FocusForwarder, window, cx| {
9570                    let b = this.b.clone();
9571                    window.focus(&b, cx);
9572                })
9573                .detach();
9574                cx.on_focus(&b, window, move |_, _, _| {
9575                    b_focus_count.set(b_focus_count.get() + 1);
9576                })
9577                .detach();
9578                FocusForwarder { a, b }
9579            }
9580        });
9581
9582        window
9583            .update(cx, |_, window, _| window.activate_window())
9584            .unwrap();
9585        cx.executor().run_until_parked();
9586
9587        window
9588            .update(cx, |this, window, cx| {
9589                let a = this.a.clone();
9590                window.focus(&a, cx);
9591            })
9592            .unwrap();
9593        cx.executor().run_until_parked();
9594
9595        window
9596            .update(cx, |this, window, _| {
9597                assert!(this.b.is_focused(window));
9598            })
9599            .unwrap();
9600        assert_eq!(b_focus_count.get(), 1);
9601    }
9602
9603    #[gpui::test]
9604    fn claimed_touch_drag_receives_movement_and_release(cx: &mut TestAppContext) {
9605        let events = Rc::new(RefCell::new(Vec::new()));
9606        let window = cx.add_window({
9607            let events = events.clone();
9608            move |_, _| TouchDragListener { events }
9609        });
9610        let touch = TouchId(1);
9611
9612        dispatch_touch(window, cx, touch, TouchPhase::Started, 10.);
9613        dispatch_touch(window, cx, touch, TouchPhase::Moved, 30.);
9614        dispatch_touch(window, cx, touch, TouchPhase::Ended, 40.);
9615
9616        assert_eq!(
9617            events.borrow().as_slice(),
9618            [
9619                (TouchPhase::Started, px(10.)),
9620                (TouchPhase::Moved, px(30.)),
9621                (TouchPhase::Ended, px(40.)),
9622            ]
9623        );
9624    }
9625
9626    struct TouchDragListener {
9627        events: Rc<RefCell<Vec<(TouchPhase, Pixels)>>>,
9628    }
9629
9630    impl Render for TouchDragListener {
9631        fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
9632            let events = self.events.clone();
9633            canvas(
9634                |_, _, _| {},
9635                move |_, _, window, _| {
9636                    window.on_mouse_event(move |event: &TouchDragEvent, phase, window, _cx| {
9637                        if phase != DispatchPhase::Bubble {
9638                            return;
9639                        }
9640                        events.borrow_mut().push((event.phase, event.position.x));
9641                        if event.phase == TouchPhase::Started {
9642                            window.prevent_default();
9643                        }
9644                    });
9645                },
9646            )
9647        }
9648    }
9649
9650    #[gpui::test]
9651    fn long_press_is_claimed_only_when_started_prevents_default(cx: &mut TestAppContext) {
9652        for response in [
9653            LongPressResponse::PreventDefault,
9654            LongPressResponse::StopPropagation,
9655            LongPressResponse::None,
9656        ] {
9657            let phases = Rc::new(RefCell::new(Vec::new()));
9658            let window = cx.add_window({
9659                let phases = phases.clone();
9660                move |_, _| LongPressListener { phases, response }
9661            });
9662            dispatch_touch(window, cx, TouchId(1), TouchPhase::Started, 0.);
9663            cx.executor().advance_clock(Duration::from_millis(501));
9664            cx.executor().run_until_parked();
9665            window
9666                .update(cx, |_, window, _| {
9667                    assert_eq!(
9668                        window.long_press_capture.is_some(),
9669                        response == LongPressResponse::PreventDefault
9670                    );
9671                })
9672                .unwrap();
9673            dispatch_touch(window, cx, TouchId(1), TouchPhase::Moved, 2.);
9674            dispatch_touch(window, cx, TouchId(1), TouchPhase::Ended, 2.);
9675            window
9676                .update(cx, |_, window, _| {
9677                    assert!(window.long_press_capture.is_none());
9678                })
9679                .unwrap();
9680
9681            let phases = phases.borrow();
9682            if response == LongPressResponse::PreventDefault {
9683                assert_eq!(
9684                    phases.as_slice(),
9685                    [TouchPhase::Started, TouchPhase::Moved, TouchPhase::Ended]
9686                );
9687            } else {
9688                assert_eq!(phases.as_slice(), [TouchPhase::Started]);
9689            }
9690        }
9691    }
9692
9693    #[gpui::test]
9694    fn stale_default_prevention_does_not_claim_long_press(cx: &mut TestAppContext) {
9695        let phases = Rc::new(RefCell::new(Vec::new()));
9696        let window = cx.add_window({
9697            let phases = phases.clone();
9698            move |_, _| LongPressListener {
9699                phases,
9700                response: LongPressResponse::None,
9701            }
9702        });
9703        window
9704            .update(cx, |_, window, _| {
9705                window.prevent_default();
9706            })
9707            .unwrap();
9708
9709        dispatch_touch(window, cx, TouchId(1), TouchPhase::Started, 0.);
9710        cx.executor().advance_clock(Duration::from_millis(501));
9711        cx.executor().run_until_parked();
9712        dispatch_touch(window, cx, TouchId(1), TouchPhase::Moved, 2.);
9713
9714        assert_eq!(phases.borrow().as_slice(), [TouchPhase::Started]);
9715    }
9716
9717    #[gpui::test]
9718    fn resolved_touch_cancels_scheduled_long_press(cx: &mut TestAppContext) {
9719        for (phase, position) in [
9720            (TouchPhase::Ended, 0.),
9721            (TouchPhase::Cancelled, 0.),
9722            (TouchPhase::Moved, 20.),
9723        ] {
9724            let phases = Rc::new(RefCell::new(Vec::new()));
9725            let window = cx.add_window({
9726                let phases = phases.clone();
9727                move |_, _| LongPressListener {
9728                    phases,
9729                    response: LongPressResponse::PreventDefault,
9730                }
9731            });
9732            dispatch_touch(window, cx, TouchId(1), TouchPhase::Started, 0.);
9733            dispatch_touch(window, cx, TouchId(1), phase, position);
9734            cx.executor().advance_clock(Duration::from_millis(501));
9735            cx.executor().run_until_parked();
9736
9737            assert!(phases.borrow().is_empty(), "{phase:?} allowed long press");
9738        }
9739    }
9740
9741    #[gpui::test]
9742    fn stale_long_press_timer_cannot_affect_replacement_touch(cx: &mut TestAppContext) {
9743        let phases = Rc::new(RefCell::new(Vec::new()));
9744        let window = cx.add_window({
9745            let phases = phases.clone();
9746            move |_, _| LongPressListener {
9747                phases,
9748                response: LongPressResponse::PreventDefault,
9749            }
9750        });
9751        let first_touch = TouchId(1);
9752        dispatch_touch(window, cx, first_touch, TouchPhase::Started, 0.);
9753        cx.executor().advance_clock(Duration::from_millis(250));
9754        dispatch_touch(window, cx, first_touch, TouchPhase::Cancelled, 0.);
9755        dispatch_touch(window, cx, TouchId(2), TouchPhase::Started, 10.);
9756
9757        cx.executor().advance_clock(Duration::from_millis(251));
9758        cx.executor().run_until_parked();
9759        assert!(phases.borrow().is_empty());
9760
9761        cx.executor().advance_clock(Duration::from_millis(250));
9762        cx.executor().run_until_parked();
9763        assert_eq!(phases.borrow().as_slice(), [TouchPhase::Started]);
9764    }
9765
9766    #[gpui::test]
9767    fn test_underline_exclusions_preserve_device_geometry(cx: &mut TestAppContext) {
9768        test_underline_paint_at_scales(cx, |window| {
9769            let (numerator, denominator) = match window.scale_factor() {
9770                1.0 => (1, 1),
9771                1.25 => (5, 4),
9772                1.5 => (3, 2),
9773                2.0 => (2, 1),
9774                3.0 => (3, 1),
9775                scale => panic!("unexpected scale {scale}"),
9776            };
9777            let snap = |quarters: i32| {
9778                let scaled = quarters * numerator;
9779                let divisor = 4 * denominator;
9780                let rounded =
9781                    scaled.abs() / divisor + i32::from(2 * (scaled.abs() % divisor) > divisor);
9782                ScaledPixels((scaled.signum() * rounded) as f32)
9783            };
9784            let stroke = |quarters| {
9785                if quarters == 0 {
9786                    ScaledPixels(0.)
9787                } else {
9788                    snap(quarters).max(ScaledPixels(1.))
9789                }
9790            };
9791
9792            for origin in [-101, -3, -2, -1, 0, 1, 2, 3, 101] {
9793                for width in [0, 1, 3, 84] {
9794                    for thickness in [0, 1, 4, 7] {
9795                        for wavy in [false, true] {
9796                            let style = UnderlineStyle {
9797                                thickness: px(thickness as f32 / 4.),
9798                                color: Some(hsla(0.25, 0.5, 0.75, 0.5)),
9799                                wavy,
9800                            };
9801                            let bounds = Bounds::new(
9802                                point(snap(origin), snap(-origin)),
9803                                size(
9804                                    stroke(width),
9805                                    stroke(thickness) * if wavy { 3. } else { 1. },
9806                                ),
9807                            );
9808                            let origin = point(px(origin as f32 / 4.), px(-origin as f32 / 4.));
9809                            let width = px(width as f32 / 4.);
9810                            assert_eq!(window.underline_bounds(origin, width, &style), bounds);
9811                            let original = paint_test_underlines(window, |window| {
9812                                window.paint_underline(origin, width, &style);
9813                            })
9814                            .to_vec();
9815                            assert_eq!(original.len(), usize::from(!bounds.is_empty()));
9816                            if let Some(underline) = original.first() {
9817                                assert_eq!(underline.bounds, bounds);
9818                                assert_eq!(underline.thickness, stroke(thickness));
9819                                assert_eq!(underline.wavy, wavy.into());
9820                                assert_eq!(underline.color, hsla(0.25, 0.5, 0.75, 0.5));
9821                            }
9822
9823                            let underlines = paint_test_underlines(window, |window| {
9824                                window.paint_underline_with_exclusions(origin, width, &style, &[]);
9825                            });
9826                            assert_eq!(underlines.len(), original.len());
9827                            for (actual, original) in underlines.iter().zip(&original) {
9828                                assert_same_underline_geometry(actual, original);
9829                                assert_eq!(actual.content_mask, original.content_mask);
9830                            }
9831
9832                            let left = bounds.left().0 as i32;
9833                            let right = bounds.right().0 as i32;
9834                            let exclusions = [
9835                                (15, 25),
9836                                (3, 7),
9837                                (5, 10),
9838                                (10, 12),
9839                                (0, 0),
9840                                (4, 2),
9841                                (-50, -1),
9842                                (70, 100),
9843                            ]
9844                            .map(|(start, end)| {
9845                                ScaledPixels((left + start) as f32)
9846                                    ..ScaledPixels((left + end) as f32)
9847                            });
9848                            let underlines = paint_test_underlines(window, |window| {
9849                                window.paint_underline_with_exclusions(
9850                                    origin,
9851                                    width,
9852                                    &style,
9853                                    &exclusions,
9854                                );
9855                            });
9856                            let expected = (left..right)
9857                                .filter(|column| {
9858                                    !bounds.is_empty()
9859                                        && !exclusions.iter().any(|span| {
9860                                            span.contains(&ScaledPixels(*column as f32))
9861                                        })
9862                                })
9863                                .collect::<Vec<_>>();
9864                            assert_eq!(underline_device_columns(underlines), expected);
9865                            for underline in underlines {
9866                                assert_same_underline_geometry(underline, &original[0]);
9867                            }
9868                        }
9869                    }
9870                }
9871            }
9872        });
9873    }
9874
9875    #[gpui::test]
9876    fn test_underline_exclusions_preserve_helvetica_warning_edge(cx: &mut TestAppContext) {
9877        test_underline_paint_at_scales(cx, |window| {
9878            if window.scale_factor() != 2.0 {
9879                return;
9880            }
9881            let style = UnderlineStyle {
9882                thickness: px(1.),
9883                color: None,
9884                wavy: true,
9885            };
9886            let origin = point(px(2.888_183_8), px(15.357_917));
9887            let width = px(23.848_145) - origin.x;
9888            let original = paint_test_underlines(window, |window| {
9889                window.paint_underline(origin, width, &style);
9890            })[0];
9891            assert_eq!(original.bounds.left(), ScaledPixels(6.));
9892            assert_eq!(original.bounds.right(), ScaledPixels(48.));
9893            let point_bounds = window.underline_bounds(origin, px(10.829_102), &style);
9894            assert_eq!(point_bounds.left(), ScaledPixels(6.));
9895            assert_eq!(point_bounds.right(), ScaledPixels(28.));
9896
9897            let underlines = paint_test_underlines(window, |window| {
9898                window.paint_underline_with_exclusions(
9899                    origin,
9900                    width,
9901                    &style,
9902                    &[point_bounds.left()..point_bounds.right()],
9903                );
9904            });
9905            assert_eq!(underlines.len(), 1);
9906            assert_same_underline_geometry(&underlines[0], &original);
9907            assert_eq!(
9908                underline_device_columns(underlines),
9909                (28..48).collect::<Vec<_>>()
9910            );
9911        });
9912    }
9913
9914    #[gpui::test]
9915    fn test_underline_exclusions_preserve_content_mask_and_opacity(cx: &mut TestAppContext) {
9916        test_underline_paint_at_scales(cx, |window| {
9917            let scale = window.scale_factor();
9918            let original_mask = window.content_mask();
9919            let original_opacity = window.element_opacity();
9920            let mask = ContentMask {
9921                bounds: Bounds::from_corners(point(px(4.), px(10.)), point(px(16.), px(12.))),
9922            };
9923            let style = UnderlineStyle {
9924                thickness: px(2.),
9925                color: Some(hsla(0.25, 0.5, 0.75, 0.5)),
9926                wavy: true,
9927            };
9928            let origin = point(px(-1.25), px(9.25));
9929            let width = px(24.);
9930            window.with_content_mask(Some(mask), |window| {
9931                window.with_element_opacity(Some(0.5), |window| {
9932                    window.with_element_opacity(Some(0.5), |window| {
9933                        let original = paint_test_underlines(window, |window| {
9934                            window.paint_underline(origin, width, &style);
9935                        })[0];
9936                        assert_eq!(original.color, hsla(0.25, 0.5, 0.75, 0.125));
9937                        let underlines = paint_test_underlines(window, |window| {
9938                            window.paint_underline_with_exclusions(
9939                                origin,
9940                                width,
9941                                &style,
9942                                &[ScaledPixels(6. * scale)..ScaledPixels(8. * scale)],
9943                            );
9944                        });
9945                        assert_eq!(underlines.len(), 2);
9946                        let expected = [(4. * scale, 6. * scale), (8. * scale, 16. * scale)].map(
9947                            |(left, right)| {
9948                                Bounds::from_corners(
9949                                    point(ScaledPixels(left), ScaledPixels((10. * scale).floor())),
9950                                    point(ScaledPixels(right), ScaledPixels((12. * scale).ceil())),
9951                                )
9952                            },
9953                        );
9954                        assert_eq!(
9955                            underlines
9956                                .iter()
9957                                .map(|underline| underline.content_mask.bounds)
9958                                .collect::<Vec<_>>(),
9959                            expected
9960                        );
9961                        for underline in underlines {
9962                            assert_same_underline_geometry(underline, &original);
9963                        }
9964                    });
9965                });
9966            });
9967            assert_eq!(window.content_mask(), original_mask);
9968            assert_eq!(window.element_opacity(), original_opacity);
9969        });
9970    }
9971
9972    #[gpui::test]
9973    fn test_underline_exclusions_adversarial_permutations(cx: &mut TestAppContext) {
9974        test_underline_paint_at_scales(cx, |window| {
9975            let style = UnderlineStyle {
9976                thickness: px(1.),
9977                color: None,
9978                wavy: true,
9979            };
9980            let origin = point(px(-4.), px(-1.));
9981            let width = px(8.);
9982            let left = (-4. * window.scale_factor()) as i32;
9983            let right = (4. * window.scale_factor()) as i32;
9984            let endpoints = [-16, -8, -1, 0, 1, 8, 16];
9985            for first_start in endpoints {
9986                for first_end in endpoints {
9987                    for second_start in endpoints {
9988                        for second_end in endpoints {
9989                            let exclusions = [first_start..first_end, second_start..second_end];
9990                            let expected = (left..right)
9991                                .filter(|column| {
9992                                    !exclusions.iter().any(|span| span.contains(column))
9993                                })
9994                                .collect::<Vec<_>>();
9995                            let exclusions = exclusions.map(|span| {
9996                                ScaledPixels(span.start as f32)..ScaledPixels(span.end as f32)
9997                            });
9998                            let underlines = paint_test_underlines(window, |window| {
9999                                window.paint_underline_with_exclusions(
10000                                    origin,
10001                                    width,
10002                                    &style,
10003                                    &exclusions,
10004                                );
10005                            });
10006                            assert_eq!(
10007                                underline_device_columns(underlines),
10008                                expected,
10009                                "{exclusions:?}"
10010                            );
10011                        }
10012                    }
10013                }
10014            }
10015        });
10016    }
10017
10018    #[derive(Clone, Copy, PartialEq)]
10019    enum LongPressResponse {
10020        PreventDefault,
10021        StopPropagation,
10022        None,
10023    }
10024
10025    struct LongPressListener {
10026        phases: Rc<RefCell<Vec<TouchPhase>>>,
10027        response: LongPressResponse,
10028    }
10029
10030    impl Render for LongPressListener {
10031        fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
10032            let entity = cx.entity();
10033            let phases = self.phases.clone();
10034            let response = self.response;
10035            canvas(
10036                |_, _, _| {},
10037                move |_, _, window, _| {
10038                    window.on_mouse_event(move |event: &LongPressEvent, phase, window, cx| {
10039                        if phase != DispatchPhase::Bubble {
10040                            return;
10041                        }
10042                        phases.borrow_mut().push(event.phase);
10043                        match response {
10044                            LongPressResponse::PreventDefault => {
10045                                window.capture_long_press(&entity);
10046                                window.prevent_default();
10047                            }
10048                            LongPressResponse::StopPropagation => cx.stop_propagation(),
10049                            LongPressResponse::None => {}
10050                        }
10051                    });
10052                },
10053            )
10054        }
10055    }
10056
10057    struct UnderlineTestView(Rc<dyn Fn(&mut Window)>);
10058
10059    #[gpui::test]
10060    fn preparation_window_geometry_survives_scaling_and_clipping(cx: &mut TestAppContext) {
10061        #[derive(Debug)]
10062        struct Probe;
10063        impl crate::CustomContent for Probe {
10064            fn prepare(
10065                &self,
10066                _: &dyn std::any::Any,
10067                _: crate::Size<crate::DevicePixels>,
10068            ) -> anyhow::Result<Box<dyn std::any::Any>> {
10069                panic!("request-aware preparation expected")
10070            }
10071
10072            fn prepare_with_request(
10073                &self,
10074                _: &dyn std::any::Any,
10075                request: &crate::PreparationRequest,
10076            ) -> anyhow::Result<Box<dyn std::any::Any>> {
10077                Ok(Box::new(*request))
10078            }
10079        }
10080        test_underline_paint_at_scales(cx, |window| {
10081            let bounds = Bounds::new(point(px(10.3), px(20.7)), size(px(100.3), px(50.7)));
10082            let content: std::sync::Arc<dyn crate::CustomContent> = std::sync::Arc::new(Probe);
10083            let mut path = crate::PathBuilder::fill();
10084            path.move_to(bounds.origin);
10085            path.line_to(bounds.top_right());
10086            path.line_to(bounds.bottom_right());
10087            path.line_to(bounds.bottom_left());
10088            path.close();
10089            let path = path.build().unwrap();
10090            let mut full_requests = Vec::new();
10091            for clipped in [false, true] {
10092                window.next_frame.scene.clear();
10093                if clipped {
10094                    window.content_mask_stack.push(ContentMask {
10095                        bounds: Bounds::new(point(px(30.), px(30.)), size(px(20.), px(15.))),
10096                    });
10097                }
10098                window.paint_custom(
10099                    crate::CustomGeometry::RoundedRect {
10100                        bounds,
10101                        corner_radii: crate::Corners::default(),
10102                    },
10103                    content.clone(),
10104                );
10105                window.paint_custom(
10106                    crate::CustomGeometry::Border(crate::quad(
10107                        bounds,
10108                        crate::Corners::default(),
10109                        crate::transparent_black(),
10110                        crate::Edges::all(px(2.)),
10111                        crate::transparent_black(),
10112                        crate::BorderStyle::Solid,
10113                    )),
10114                    content.clone(),
10115                );
10116                window.paint_custom(crate::CustomGeometry::Path(path.clone()), content.clone());
10117                if clipped {
10118                    window.content_mask_stack.pop();
10119                }
10120                let draws = &window.next_frame.scene.custom_draws;
10121                assert_eq!(draws.len(), 3);
10122                for (index, draw) in draws.iter().enumerate() {
10123                    let raster = draw
10124                        .bounds
10125                        .size
10126                        .map(|v| crate::DevicePixels(v.0.ceil() as i32));
10127                    let default_request = crate::PreparationRequest::new(
10128                        draw.bounds.size.map(|v| px(v.0)),
10129                        raster,
10130                        1.,
10131                    )
10132                    .unwrap();
10133                    let output = draw
10134                        .content
10135                        .prepare_with_request(&(), &default_request)
10136                        .unwrap();
10137                    let request = *output.downcast::<crate::PreparationRequest>().unwrap();
10138                    let logical = if index == 2 {
10139                        path.bounds.size
10140                    } else {
10141                        bounds.size
10142                    };
10143                    assert_eq!(request.logical_size(), logical);
10144                    assert_eq!(request.scale_factor(), window.scale_factor());
10145                    assert_eq!(request.raster_size(), raster);
10146                    if clipped {
10147                        assert_eq!(request, full_requests[index]);
10148                    } else {
10149                        full_requests.push(request);
10150                    }
10151                }
10152            }
10153        });
10154    }
10155
10156    impl Render for UnderlineTestView {
10157        fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
10158            let paint = self.0.clone();
10159            canvas(
10160                |_, _, _| {},
10161                move |_, _, window, _| {
10162                    window.content_mask_stack.push(ContentMask {
10163                        bounds: Bounds::from_corners(
10164                            point(px(-1000.), px(-1000.)),
10165                            point(px(1000.), px(1000.)),
10166                        ),
10167                    });
10168                    paint(window);
10169                    window.content_mask_stack.pop();
10170                },
10171            )
10172            .size_full()
10173        }
10174    }
10175
10176    fn test_underline_paint_at_scales(
10177        cx: &mut TestAppContext,
10178        paint: impl Fn(&mut Window) + 'static,
10179    ) {
10180        let window = cx.add_window(move |_, _| UnderlineTestView(Rc::new(paint)));
10181        for scale in [1., 1.25, 1.5, 2., 3.] {
10182            cx.simulate_window_scale_factor_change(window.into(), scale);
10183            cx.update_window(window.into(), |_, window, cx| window.draw(cx).clear(cx))
10184                .unwrap();
10185        }
10186    }
10187
10188    fn paint_test_underlines(window: &mut Window, paint: impl FnOnce(&mut Window)) -> &[Underline] {
10189        window.next_frame.scene.clear();
10190        paint(window);
10191        &window.next_frame.scene.underlines
10192    }
10193
10194    fn assert_same_underline_geometry(actual: &Underline, expected: &Underline) {
10195        assert_eq!(actual.bounds, expected.bounds);
10196        assert_eq!(actual.thickness, expected.thickness);
10197        assert_eq!(actual.wavy, expected.wavy);
10198        assert_eq!(actual.color, expected.color);
10199        assert_eq!(actual.pad, expected.pad);
10200    }
10201
10202    fn underline_device_columns(underlines: &[Underline]) -> Vec<i32> {
10203        underlines
10204            .iter()
10205            .flat_map(|underline| {
10206                let bounds = underline.bounds.intersect(&underline.content_mask.bounds);
10207                bounds.left().0 as i32..bounds.right().0 as i32
10208            })
10209            .collect()
10210    }
10211
10212    fn dispatch_touch<T: 'static>(
10213        window: crate::WindowHandle<T>,
10214        cx: &mut TestAppContext,
10215        id: TouchId,
10216        phase: TouchPhase,
10217        x: f32,
10218    ) {
10219        window
10220            .update(cx, |_, window, cx| {
10221                window.dispatch_event(
10222                    TouchEvent {
10223                        id,
10224                        phase,
10225                        position: point(px(x), px(0.)),
10226                        predicted_position: None,
10227                        force: None,
10228                    }
10229                    .to_platform_input(),
10230                    cx,
10231                );
10232            })
10233            .unwrap();
10234    }
10235}
10236
10237#[cfg(all(test, debug_assertions))]
10238mod inspector_tests {
10239    use super::*;
10240    use crate::{
10241        DivInspectorState, InspectorElementId, MouseDownEvent, StyleRefinement, TestAppContext, div,
10242    };
10243
10244    #[gpui::test]
10245    fn inspector_only_tracks_its_open_window(cx: &mut TestAppContext) {
10246        let windows = [
10247            cx.add_window(|_, cx| InspectorTestRoot {
10248                child: cx.new(|_| InspectorTestView::default()),
10249            }),
10250            cx.add_window(|_, cx| InspectorTestRoot {
10251                child: cx.new(|_| InspectorTestView::default()),
10252            }),
10253        ];
10254        for window in windows {
10255            assert_closed_inspector(window.into(), cx);
10256        }
10257        for _ in 0..2 {
10258            cx.update_window(windows[0].into(), |root, window, cx| {
10259                let root = root.downcast::<InspectorTestRoot>().expect("test root");
10260                let child_widths = root.read(cx).child.read(cx).child_widths.clone();
10261                window.toggle_inspector(cx);
10262                window.draw(cx).clear(cx);
10263                assert_eq!(child_widths.borrow().as_slice(), &[px(10.); 3]);
10264                let path = window
10265                    .rendered_frame
10266                    .next_inspector_instance_ids
10267                    .iter()
10268                    .find_map(|(path, count)| (*count == 3).then(|| path.clone()))
10269                    .expect("anonymous siblings share an inspector path");
10270                let selected_id = InspectorElementId {
10271                    path,
10272                    instance_id: 1,
10273                };
10274                let position = window
10275                    .rendered_frame
10276                    .hitboxes
10277                    .iter()
10278                    .find(|hitbox| {
10279                        window.rendered_frame.inspector_hitboxes.get(&hitbox.id)
10280                            == Some(&selected_id)
10281                    })
10282                    .expect("middle sibling is pickable")
10283                    .bounds
10284                    .center();
10285                window.simulate_mouse_move(position, cx);
10286                window.dispatch_event(
10287                    PlatformInput::MouseDown(MouseDownEvent {
10288                        position,
10289                        button: MouseButton::Left,
10290                        modifiers: Modifiers::default(),
10291                        click_count: 1,
10292                        first_mouse: false,
10293                    }),
10294                    cx,
10295                );
10296                window.dispatch_event(
10297                    PlatformInput::MouseUp(MouseUpEvent {
10298                        position,
10299                        button: MouseButton::Left,
10300                        modifiers: Modifiers::default(),
10301                        click_count: 1,
10302                    }),
10303                    cx,
10304                );
10305                assert!(!window.is_inspector_picking(cx));
10306                assert_eq!(
10307                    window
10308                        .inspector
10309                        .as_ref()
10310                        .expect("open inspector")
10311                        .read(cx)
10312                        .active_element_id(),
10313                    Some(&selected_id)
10314                );
10315                window.draw(cx).clear(cx);
10316                window.with_inspector_state::<DivInspectorState, _>(
10317                    Some(&selected_id),
10318                    cx,
10319                    |state, _| {
10320                        let state = state.as_mut().expect("selected div has style state");
10321                        assert_eq!(
10322                            state.base_style.size.width,
10323                            Some(crate::Length::from(px(10.)))
10324                        );
10325                        state.base_style.size.width = Some(crate::Length::from(px(25.)));
10326                    },
10327                );
10328                window.refresh();
10329                window.draw(cx).clear(cx);
10330                assert_eq!(
10331                    child_widths.borrow().as_slice(),
10332                    &[px(10.), px(25.), px(10.)]
10333                );
10334            })
10335            .expect("pick and edit a cached child");
10336            assert_closed_inspector(windows[1].into(), cx);
10337            windows[0]
10338                .update(cx, |_, window, cx| window.toggle_inspector(cx))
10339                .expect("close inspector");
10340            assert_closed_inspector(windows[0].into(), cx);
10341        }
10342    }
10343
10344    struct InspectorTestRoot {
10345        child: Entity<InspectorTestView>,
10346    }
10347
10348    impl Render for InspectorTestRoot {
10349        fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
10350            self.child
10351                .clone()
10352                .cached(StyleRefinement::default().size(px(100.)))
10353        }
10354    }
10355
10356    #[derive(Default)]
10357    struct InspectorTestView {
10358        child_widths: Rc<RefCell<Vec<Pixels>>>,
10359    }
10360
10361    impl Render for InspectorTestView {
10362        fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
10363            let child_widths = self.child_widths.clone();
10364            div()
10365                .on_children_prepainted(move |bounds, _, _| {
10366                    *child_widths.borrow_mut() =
10367                        bounds.iter().map(|bounds| bounds.size.width).collect();
10368                })
10369                .with_dynamic_prepaint_order(|_, _| SmallVec::from_iter([2, 0, 1]))
10370                .id("inspector-root")
10371                .flex()
10372                .children((0..3).map(|_| div().size(px(10.)).flex_shrink_0()))
10373        }
10374    }
10375
10376    fn assert_closed_inspector(window: AnyWindowHandle, cx: &mut TestAppContext) {
10377        cx.update_window(window, |root, window, cx| {
10378            window.draw(cx).clear(cx);
10379            window.draw(cx).clear(cx);
10380            let root = root.downcast::<InspectorTestRoot>().expect("test root");
10381            assert_eq!(
10382                root.read(cx)
10383                    .child
10384                    .read(cx)
10385                    .child_widths
10386                    .borrow()
10387                    .as_slice(),
10388                &[px(10.); 3]
10389            );
10390            for frame in [&window.rendered_frame, &window.next_frame] {
10391                assert_eq!(frame.next_inspector_instance_ids.capacity(), 0);
10392                assert_eq!(frame.inspector_hitboxes.capacity(), 0);
10393            }
10394        })
10395        .expect("closed inspector has no bookkeeping and no style overrides");
10396    }
10397}