Skip to main content

gpui/
window.rs

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