Skip to main content

gpui/
window.rs

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