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