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::{
8 Action, AnyDrag, AnyElement, AnyImageCache, AnyTooltip, AnyView, App, AppContext, Arena, Asset,
9 AsyncWindowContext, AtlasTile, AvailableSpace, Background, BorderStyle, Bounds, BoxShadow,
10 Capslock, ContentMask, Context, Corners, CursorHideMode, CursorStyle, CustomRenderPrimitive,
11 DEFAULT_WINDOW_SIZE, Decorations, DevicePixels, DispatchActionListener, DispatchEventResult,
12 DispatchNodeId, DispatchTree, DisplayId, Edges, Effect, Entity, EntityId, EventEmitter,
13 FileDropEvent, FontId, Global, GlobalElementId, GlyphId, GpuSpecs, Hsla, ImportedTextureHandle,
14 InputHandler, InputPreference, IsZero, KeyBinding, KeyContext, KeyDownEvent, KeyEvent,
15 Keystroke, KeystrokeEvent, LayoutId, LineLayoutIndex, MeasureContext, MeasureHandles,
16 Modifiers, ModifiersChangedEvent, MonochromeSprite, MouseButton, MouseEvent, MouseMoveEvent,
17 MouseUpEvent, Path, Pixels, PlatformAtlas, PlatformDisplay, PlatformInput,
18 PlatformInputHandler, PlatformWindow, Point, PolychromeSprite, Priority, PromptButton,
19 PromptLevel, Quad, Render, RenderGlyphParams, RenderImage, RenderImageParams, RenderSvgParams,
20 Replay, ResizeEdge, SMOOTH_SVG_SCALE_FACTOR, SUBPIXEL_VARIANTS_X, SUBPIXEL_VARIANTS_Y,
21 ScaledPixels, Scene, Shadow, SharedString, Size, StrikethroughStyle, Style, SubpixelSprite,
22 SubscriberSet, Subscription, SystemWindowTab, SystemWindowTabController, TabStopMap, Task,
23 TextInputConfiguration, TextInputStateChange, TextRenderingMode, TextStyle,
24 TextStyleRefinement, ThermalState, TransformationMatrix, Underline, UnderlineStyle,
25 WindowAppearance, WindowBackgroundAppearance, WindowBounds, WindowControlArea, WindowControls,
26 WindowDecorations, WindowId, WindowMetrics, WindowOptions, WindowParams, WindowTextSystem,
27 WindowVisibility, new_platform_input_handler, point, prelude::*, px, rems, size,
28 transparent_black,
29};
30
31use crate::TouchEvent;
32
33#[cfg(any(test, feature = "test-support"))]
35use crate::PaintSurface;
36use crate::gestures::{GestureTuning, RecognizedTouchGesture, TouchGestureRecognizer};
37use anyhow::{Context as _, Result, anyhow};
38use arc_swap::ArcSwap;
39use collections::{FxHashMap, FxHashSet};
40use derive_more::{Deref, DerefMut};
41use futures::channel::oneshot;
42use gpui_engine::FrameSession;
43use gpui_util::post_inc;
44use gpui_util::{ResultExt, measure};
45use itertools::FoldWhile::{Continue, Done};
46use itertools::Itertools;
47use parking_lot::RwLock;
48use raw_window_handle::{HandleError, HasDisplayHandle, HasWindowHandle};
49use refineable::Refineable;
50use scheduler::Instant;
51use slotmap::SlotMap;
52use smallvec::SmallVec;
53use std::{
54 any::{Any, TypeId},
55 borrow::Cow,
56 cell::{Cell, RefCell},
57 cmp,
58 fmt::{Debug, Display},
59 hash::{Hash, Hasher},
60 marker::PhantomData,
61 mem,
62 ops::{DerefMut, Range},
63 rc::Rc,
64 sync::{
65 Arc, Weak,
66 atomic::{AtomicBool, AtomicUsize, Ordering::SeqCst},
67 },
68 thread::AccessError,
69 time::Duration,
70};
71use uuid::Uuid;
72
73pub(crate) mod a11y;
74mod frame_pipeline;
75mod prompts;
76
77pub use a11y::A11ySubtreeBuilder;
78pub use frame_pipeline::{FramePipeline, StandardImmediatePipeline};
79
80use self::a11y::A11y;
81#[cfg(not(target_family = "wasm"))]
82use self::a11y::ROOT_NODE_ID;
83use crate::engine_layout::to_engine_layout_style;
84use crate::util::{
85 atomic_incr_if_not_zero, ceil_to_device_pixel, floor_to_device_pixel, round_half_toward_zero,
86 round_half_toward_zero_f64, round_stroke_to_device_pixel, round_to_device_pixel,
87};
88pub use prompts::*;
89
90pub const DEFAULT_ADDITIONAL_WINDOW_SIZE: Size<Pixels> = Size {
93 width: Pixels(900.),
94 height: Pixels(750.),
95};
96
97struct WindowMeasureContext<'a> {
104 core: &'a mut WindowHostCore,
105 frame_state: &'a mut WindowFrameState,
106 cx: &'a mut App,
107}
108
109impl MeasureContext for WindowMeasureContext<'_> {
110 fn handles(&mut self) -> MeasureHandles<'_> {
111 MeasureHandles {
112 window: (self.core, self.frame_state),
113 app: self.cx,
114 }
115 }
116}
117
118#[derive(Default, Copy, Clone, Debug, Eq, PartialEq)]
120pub enum DispatchPhase {
121 #[default]
126 Bubble,
127 Capture,
133}
134
135impl DispatchPhase {
136 #[inline]
138 pub fn bubble(self) -> bool {
139 self == DispatchPhase::Bubble
140 }
141
142 #[inline]
144 pub fn capture(self) -> bool {
145 self == DispatchPhase::Capture
146 }
147}
148
149struct WindowInvalidatorInner {
150 #[cfg(feature = "profiler")]
151 pub window_id: WindowId,
152 pub dirty: bool,
153 pub draw_phase: DrawPhase,
154 pub dirty_views: FxHashSet<EntityId>,
155 pub update_count: usize,
156 #[cfg(feature = "profiler")]
157 pub frame_dirty: FrameDirtyAccumulator,
158 pub platform_waker: Option<Rc<dyn Fn()>>,
159}
160
161#[cfg(feature = "profiler")]
167#[derive(Default)]
168struct FrameDirtyAccumulator {
169 dirty_at: Option<Instant>,
170 invalidations: u64,
171}
172
173#[derive(Clone, Copy)]
175enum FrameRateLimit {
176 Inactive,
178 Thermal,
180}
181
182#[derive(Clone)]
183pub(crate) struct WindowInvalidator {
184 inner: Rc<RefCell<WindowInvalidatorInner>>,
185}
186
187impl WindowInvalidator {
188 pub fn new(#[allow(unused_variables)] window_id: WindowId) -> Self {
189 WindowInvalidator {
190 inner: Rc::new(RefCell::new(WindowInvalidatorInner {
191 #[cfg(feature = "profiler")]
192 window_id,
193 dirty: true,
194 draw_phase: DrawPhase::None,
195 dirty_views: FxHashSet::default(),
196 update_count: 0,
197 #[cfg(feature = "profiler")]
198 frame_dirty: FrameDirtyAccumulator::default(),
199 platform_waker: None,
200 })),
201 }
202 }
203
204 pub fn invalidate_view(&self, entity: EntityId, cx: &mut App) -> bool {
205 let mut inner = self.inner.borrow_mut();
206 inner.update_count += 1;
207 inner.dirty_views.insert(entity);
208 if inner.draw_phase == DrawPhase::None {
209 #[cfg(feature = "profiler")]
210 let dirty_at = Self::record_frame_dirty(&mut inner);
211 let became_dirty = !inner.dirty;
212 inner.dirty = true;
213 let waker = became_dirty.then(|| inner.platform_waker.clone()).flatten();
214 #[cfg(feature = "profiler")]
215 let window_id = inner.window_id;
216 drop(inner);
217 #[cfg(feature = "profiler")]
218 if became_dirty {
219 profiler::journal::record_frame_pending(window_id, dirty_at);
220 }
221 cx.push_effect(Effect::Notify { emitter: entity });
222 if let Some(waker) = waker {
223 waker();
224 }
225 true
226 } else {
227 false
228 }
229 }
230
231 pub fn is_dirty(&self) -> bool {
232 self.inner.borrow().dirty
233 }
234
235 pub fn set_dirty(&self, dirty: bool) {
236 let mut inner = self.inner.borrow_mut();
237 let became_dirty = dirty && !inner.dirty;
238 inner.dirty = dirty;
239 if dirty {
240 inner.update_count += 1;
241 }
242 #[cfg(feature = "profiler")]
243 let dirty_at = dirty.then(|| Self::record_frame_dirty(&mut inner));
244 let waker = became_dirty.then(|| inner.platform_waker.clone()).flatten();
245 #[cfg(feature = "profiler")]
246 let window_id = inner.window_id;
247 drop(inner);
248 #[cfg(feature = "profiler")]
249 if became_dirty && let Some(dirty_at) = dirty_at {
250 profiler::journal::record_frame_pending(window_id, dirty_at);
251 }
252 if let Some(waker) = waker {
253 waker();
254 }
255 }
256
257 pub fn set_platform_waker(&self, waker: Option<Rc<dyn Fn()>>) {
258 let mut inner = self.inner.borrow_mut();
259 inner.platform_waker = waker;
260 let waker = inner.dirty.then(|| inner.platform_waker.clone()).flatten();
261 drop(inner);
262 if let Some(waker) = waker {
263 waker();
264 }
265 }
266
267 pub fn wake_platform(&self) {
271 let waker = self.inner.borrow().platform_waker.clone();
272 if let Some(waker) = waker {
273 waker();
274 }
275 }
276
277 pub fn set_phase(&self, phase: DrawPhase) {
278 self.inner.borrow_mut().draw_phase = phase
279 }
280
281 pub fn update_count(&self) -> usize {
282 self.inner.borrow().update_count
283 }
284
285 #[cfg(feature = "profiler")]
286 fn record_frame_dirty(inner: &mut WindowInvalidatorInner) -> Instant {
287 let dirty_at = *inner.frame_dirty.dirty_at.get_or_insert_with(Instant::now);
288 inner.frame_dirty.invalidations += 1;
289 dirty_at
290 }
291
292 #[cfg(feature = "profiler")]
293 fn take_frame_dirty(&self) -> FrameDirtyAccumulator {
294 mem::take(&mut self.inner.borrow_mut().frame_dirty)
295 }
296
297 pub fn take_views(&self) -> FxHashSet<EntityId> {
298 mem::take(&mut self.inner.borrow_mut().dirty_views)
299 }
300
301 pub fn replace_views(&self, views: FxHashSet<EntityId>) {
302 self.inner.borrow_mut().dirty_views = views;
303 }
304
305 pub fn not_drawing(&self) -> bool {
306 self.inner.borrow().draw_phase == DrawPhase::None
307 }
308
309 #[track_caller]
310 pub fn debug_assert_paint(&self) {
311 debug_assert!(
312 matches!(self.inner.borrow().draw_phase, DrawPhase::Paint),
313 "this method can only be called during paint"
314 );
315 }
316
317 #[track_caller]
318 pub fn debug_assert_prepaint(&self) {
319 debug_assert!(
320 matches!(self.inner.borrow().draw_phase, DrawPhase::Prepaint),
321 "this method can only be called during request_layout, or prepaint"
322 );
323 }
324
325 #[track_caller]
326 pub fn debug_assert_paint_or_prepaint(&self) {
327 debug_assert!(
328 matches!(
329 self.inner.borrow().draw_phase,
330 DrawPhase::Paint | DrawPhase::Prepaint
331 ),
332 "this method can only be called during request_layout, prepaint, or paint"
333 );
334 }
335}
336
337type AnyObserver = Box<dyn FnMut(&mut Window, &mut App) -> bool + 'static>;
338
339pub(crate) type AnyWindowFocusListener =
340 Box<dyn FnMut(&WindowFocusEvent, &mut Window, &mut App) -> bool + 'static>;
341
342pub(crate) struct WindowFocusEvent {
343 pub(crate) previous_focus_path: SmallVec<[FocusId; 8]>,
344 pub(crate) current_focus_path: SmallVec<[FocusId; 8]>,
345}
346
347impl WindowFocusEvent {
348 pub fn is_focus_in(&self, focus_id: FocusId) -> bool {
349 !self.previous_focus_path.contains(&focus_id) && self.current_focus_path.contains(&focus_id)
350 }
351
352 pub fn is_focus_out(&self, focus_id: FocusId) -> bool {
353 self.previous_focus_path.contains(&focus_id) && !self.current_focus_path.contains(&focus_id)
354 }
355}
356
357pub struct FocusOutEvent {
359 pub blurred: WeakFocusHandle,
361}
362
363slotmap::new_key_type! {
364 pub struct FocusId;
366}
367
368thread_local! {
369 pub(crate) static ELEMENT_ARENA: RefCell<Arena> = RefCell::new(Arena::new(1024 * 1024));
372
373 static CURRENT_ELEMENT_ARENA: Cell<Option<*const RefCell<Arena>>> = const { Cell::new(None) };
377}
378
379fn draw_in_progress() -> bool {
390 CURRENT_ELEMENT_ARENA.with(|current| current.get().is_some())
391}
392
393#[inline(always)]
396pub(crate) fn with_element_arena<R>(callback: impl FnOnce(&mut Arena) -> R) -> R {
397 let mut callback = Some(callback);
398 let mut result = None;
399 let access = with_element_arena_erased(&mut |arena| {
400 result = Some(callback.take().expect("arena callback runs once")(arena));
401 });
402 drop(callback);
403 access.expect("cannot access a Thread Local Storage value during or after destruction");
404 result.expect("arena callback produces a result")
405}
406
407pub(crate) struct ElementArenaScope {
422 entered: *const RefCell<Arena>,
425 previous: Option<*const RefCell<Arena>>,
426 exited: bool,
427}
428
429impl ElementArenaScope {
430 pub(crate) fn enter(arena: &RefCell<Arena>) -> Self {
432 arena.borrow_mut().begin_scope();
433 let previous = CURRENT_ELEMENT_ARENA.with(|current| {
434 let prev = current.get();
435 current.set(Some(arena as *const RefCell<Arena>));
436 prev
437 });
438 Self {
439 entered: arena as *const RefCell<Arena>,
440 previous,
441 exited: false,
442 }
443 }
444
445 pub(crate) fn exit(mut self, arena: &RefCell<Arena>) -> ArenaClearNeeded {
454 assert!(
455 std::ptr::eq(self.entered, arena),
456 "ElementArenaScope::exit called with a different arena than was entered"
457 );
458 self.exited = true;
459 ArenaClearNeeded::new(arena)
464 }
465}
466
467impl Drop for ElementArenaScope {
468 fn drop(&mut self) {
469 CURRENT_ELEMENT_ARENA.with(|current| {
476 current.set(self.previous);
477 });
478 unsafe { &*self.entered }.borrow_mut().end_scope();
482 if !self.exited && !std::thread::panicking() {
483 debug_assert!(false, "ElementArenaScope dropped without calling exit()");
484 log::error!(
485 "ElementArenaScope dropped without calling exit(); \
486 the arena clear for this draw was never requested"
487 );
488 }
489 }
490}
491
492#[must_use]
494pub struct ArenaClearNeeded {
495 arena: *const RefCell<Arena>,
498}
499
500impl ArenaClearNeeded {
501 fn new(arena: &RefCell<Arena>) -> Self {
504 Self {
505 arena: arena as *const RefCell<Arena>,
506 }
507 }
508
509 pub fn clear(self, cx: &mut App) {
518 assert!(
519 std::ptr::eq(self.arena, &cx.element_arena),
520 "ArenaClearNeeded::clear called with a different App than the draw ran against"
521 );
522 cx.element_arena.borrow_mut().clear();
523 }
524}
525
526pub(crate) type FocusMap = RwLock<SlotMap<FocusId, FocusRef>>;
527pub(crate) struct FocusRef {
528 pub(crate) ref_count: AtomicUsize,
529 pub(crate) tab_index: isize,
530 pub(crate) tab_stop: bool,
531}
532
533impl FocusId {
534 pub fn is_focused(&self, window: &Window) -> bool {
536 window.core.focus == Some(*self)
537 }
538
539 pub fn contains_focused(&self, window: &Window, cx: &App) -> bool {
542 window
543 .focused(cx)
544 .is_some_and(|focused| self.contains(focused.id, window))
545 }
546
547 pub fn within_focused(&self, window: &Window, cx: &App) -> bool {
550 let focused = window.focused(cx);
551 focused.is_some_and(|focused| focused.id.contains(*self, window))
552 }
553
554 pub(crate) fn contains(&self, other: Self, window: &Window) -> bool {
556 window
557 .frame_state
558 .rendered_frame
559 .dispatch_tree
560 .focus_contains(*self, other)
561 }
562}
563
564pub struct FocusHandle {
566 pub(crate) id: FocusId,
567 handles: Arc<FocusMap>,
568 pub tab_index: isize,
570 pub tab_stop: bool,
572}
573
574impl std::fmt::Debug for FocusHandle {
575 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
576 f.write_fmt(format_args!("FocusHandle({:?})", self.id))
577 }
578}
579
580impl FocusHandle {
581 pub(crate) fn new(handles: &Arc<FocusMap>) -> Self {
582 let id = handles.write().insert(FocusRef {
583 ref_count: AtomicUsize::new(1),
584 tab_index: 0,
585 tab_stop: false,
586 });
587
588 Self {
589 id,
590 tab_index: 0,
591 tab_stop: false,
592 handles: handles.clone(),
593 }
594 }
595
596 pub(crate) fn for_id(id: FocusId, handles: &Arc<FocusMap>) -> Option<Self> {
597 let lock = handles.read();
598 let focus = lock.get(id)?;
599 if atomic_incr_if_not_zero(&focus.ref_count) == 0 {
600 return None;
601 }
602 Some(Self {
603 id,
604 tab_index: focus.tab_index,
605 tab_stop: focus.tab_stop,
606 handles: handles.clone(),
607 })
608 }
609
610 pub fn tab_index(mut self, index: isize) -> Self {
612 self.tab_index = index;
613 if let Some(focus) = self.handles.write().get_mut(self.id) {
614 focus.tab_index = index;
615 }
616 self
617 }
618
619 pub fn tab_stop(mut self, tab_stop: bool) -> Self {
623 self.tab_stop = tab_stop;
624 if let Some(focus) = self.handles.write().get_mut(self.id) {
625 focus.tab_stop = tab_stop;
626 }
627 self
628 }
629
630 pub fn downgrade(&self) -> WeakFocusHandle {
632 WeakFocusHandle {
633 id: self.id,
634 handles: Arc::downgrade(&self.handles),
635 }
636 }
637
638 pub fn focus(&self, window: &mut Window, cx: &mut App) {
640 window.focus(self, cx)
641 }
642
643 pub fn is_focused(&self, window: &Window) -> bool {
645 self.id.is_focused(window)
646 }
647
648 pub fn contains_focused(&self, window: &Window, cx: &App) -> bool {
651 self.id.contains_focused(window, cx)
652 }
653
654 pub fn within_focused(&self, window: &Window, cx: &mut App) -> bool {
657 self.id.within_focused(window, cx)
658 }
659
660 pub fn contains(&self, other: &Self, window: &Window) -> bool {
662 self.id.contains(other.id, window)
663 }
664
665 pub fn dispatch_action(&self, action: &dyn Action, window: &mut Window, cx: &mut App) {
667 if let Some(node_id) = window
668 .frame_state
669 .rendered_frame
670 .dispatch_tree
671 .focusable_node_id(self.id)
672 {
673 window.dispatch_action_on_node(node_id, action, cx)
674 }
675 }
676}
677
678impl Clone for FocusHandle {
679 fn clone(&self) -> Self {
680 Self::for_id(self.id, &self.handles).unwrap()
681 }
682}
683
684impl PartialEq for FocusHandle {
685 fn eq(&self, other: &Self) -> bool {
686 self.id == other.id
687 }
688}
689
690impl Eq for FocusHandle {}
691
692impl Drop for FocusHandle {
693 fn drop(&mut self) {
694 self.handles
695 .read()
696 .get(self.id)
697 .unwrap()
698 .ref_count
699 .fetch_sub(1, SeqCst);
700 }
701}
702
703#[derive(Clone, Debug)]
705pub struct WeakFocusHandle {
706 pub(crate) id: FocusId,
707 pub(crate) handles: Weak<FocusMap>,
708}
709
710impl WeakFocusHandle {
711 pub fn upgrade(&self) -> Option<FocusHandle> {
713 let handles = self.handles.upgrade()?;
714 FocusHandle::for_id(self.id, &handles)
715 }
716}
717
718impl PartialEq for WeakFocusHandle {
719 fn eq(&self, other: &WeakFocusHandle) -> bool {
720 self.id == other.id
721 }
722}
723
724impl Eq for WeakFocusHandle {}
725
726impl PartialEq<FocusHandle> for WeakFocusHandle {
727 fn eq(&self, other: &FocusHandle) -> bool {
728 self.id == other.id
729 }
730}
731
732impl PartialEq<WeakFocusHandle> for FocusHandle {
733 fn eq(&self, other: &WeakFocusHandle) -> bool {
734 self.id == other.id
735 }
736}
737
738pub trait Focusable: 'static {
741 fn focus_handle(&self, cx: &App) -> FocusHandle;
743}
744
745impl<V: Focusable> Focusable for Entity<V> {
746 fn focus_handle(&self, cx: &App) -> FocusHandle {
747 self.read(cx).focus_handle(cx)
748 }
749}
750
751pub trait ManagedView: Focusable + EventEmitter<DismissEvent> + Render {}
754
755impl<M: Focusable + EventEmitter<DismissEvent> + Render> ManagedView for M {}
756
757pub struct DismissEvent;
759
760type FrameCallback = Box<dyn FnOnce(&mut Window, &mut App)>;
761
762pub(crate) type AnyMouseListener =
763 Box<dyn FnMut(&dyn Any, DispatchPhase, &mut Window, &mut App) + 'static>;
764
765#[derive(Clone)]
766pub(crate) struct CursorStyleRequest {
767 pub(crate) hitbox_id: Option<HitboxId>,
768 pub(crate) style: CursorStyle,
769}
770
771#[derive(Default, Eq, PartialEq)]
772pub(crate) struct HitTest {
773 pub(crate) ids: SmallVec<[HitboxId; 8]>,
774 pub(crate) hover_hitbox_count: usize,
775}
776
777#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
779pub struct HitboxId(u64);
780
781#[cfg(feature = "test-support")]
782impl HitboxId {
783 pub const fn placeholder() -> Self {
788 Self(0)
789 }
790}
791
792impl HitboxId {
793 pub fn is_hovered(self, window: &Window) -> bool {
800 if window.core.captured_hitbox == Some(self) {
802 return true;
803 }
804 if window.last_input_was_keyboard() {
805 return false;
806 }
807 self.hit_test(window)
808 }
809
810 pub(crate) fn is_hovered_ignoring_last_input(self, window: &Window) -> bool {
815 if window.core.captured_hitbox == Some(self) {
817 return true;
818 }
819 self.hit_test(window)
820 }
821
822 fn hit_test(self, window: &Window) -> bool {
823 let hit_test = &window.core.mouse_hit_test;
824 for id in hit_test.ids.iter().take(hit_test.hover_hitbox_count) {
825 if self == *id {
826 return true;
827 }
828 }
829 false
830 }
831
832 pub fn should_handle_scroll(self, window: &Window) -> bool {
837 window.core.mouse_hit_test.ids.contains(&self)
838 }
839
840 fn next(mut self) -> HitboxId {
841 HitboxId(self.0.wrapping_add(1))
842 }
843}
844
845#[derive(Clone)]
854pub struct HitboxFilter(Rc<dyn Fn(Point<Pixels>) -> bool>);
855
856impl HitboxFilter {
857 pub fn new(allows: impl Fn(Point<Pixels>) -> bool + 'static) -> Self {
860 Self(Rc::new(allows))
861 }
862
863 fn allows(&self, position: Point<Pixels>) -> bool {
864 (self.0)(position)
865 }
866}
867
868impl Debug for HitboxFilter {
869 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
870 f.write_str("HitboxFilter(..)")
871 }
872}
873
874#[derive(Clone, Debug, Deref)]
877pub struct Hitbox {
878 pub id: HitboxId,
880 #[deref]
882 pub bounds: Bounds<Pixels>,
883 pub content_mask: ContentMask<Pixels>,
885 pub behavior: HitboxBehavior,
887}
888
889const _: fn() = || {
893 fn assert_send_sync<T: Send + Sync>() {}
894 assert_send_sync::<Hitbox>();
895};
896
897impl Hitbox {
898 pub fn is_hovered(&self, window: &Window) -> bool {
915 self.id.is_hovered(window)
916 }
917
918 pub fn is_hovered_at(&self, position: Point<Pixels>, window: &Window) -> bool {
921 let hit_test = window.frame_state.rendered_frame.hit_test(position);
922 hit_test
923 .ids
924 .iter()
925 .take(hit_test.hover_hitbox_count)
926 .any(|id| self.id == *id)
927 }
928
929 pub fn should_handle_scroll(&self, window: &Window) -> bool {
936 self.id.should_handle_scroll(window)
937 }
938}
939
940#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
942pub enum HitboxBehavior {
943 #[default]
945 Normal,
946
947 BlockMouse,
969
970 BlockMouseExceptScroll,
997}
998
999#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
1001pub struct TooltipId(usize);
1002
1003impl TooltipId {
1004 pub fn is_hovered(&self, window: &Window) -> bool {
1006 window
1007 .frame_state
1008 .tooltip_bounds
1009 .as_ref()
1010 .is_some_and(|tooltip_bounds| {
1011 tooltip_bounds.id == *self
1012 && tooltip_bounds.bounds.contains(&window.mouse_position())
1013 })
1014 }
1015}
1016
1017pub(crate) struct TooltipBounds {
1018 id: TooltipId,
1019 bounds: Bounds<Pixels>,
1020}
1021
1022#[derive(Clone)]
1023pub(crate) struct TooltipRequest {
1024 id: TooltipId,
1025 tooltip: AnyTooltip,
1026}
1027
1028#[derive(Clone, Default)]
1029pub(crate) struct ElementIdStack {
1030 ids: SmallVec<[ElementId; 32]>,
1031 hashes: SmallVec<[u64; 32]>,
1032}
1033
1034impl ElementIdStack {
1035 pub(crate) fn push(&mut self, id: ElementId) {
1036 self.hashes.push(crate::extend_path_hash(self.hash(), &id));
1037 self.ids.push(id);
1038 }
1039
1040 pub(crate) fn pop(&mut self) -> Option<ElementId> {
1041 self.hashes.pop();
1042 self.ids.pop()
1043 }
1044
1045 pub(crate) fn clear(&mut self) {
1046 self.ids.clear();
1047 self.hashes.clear();
1048 }
1049
1050 fn hash(&self) -> u64 {
1052 self.hashes
1053 .last()
1054 .copied()
1055 .unwrap_or(crate::EMPTY_PATH_HASH)
1056 }
1057
1058 pub(crate) fn global_id(&self) -> GlobalElementId {
1059 GlobalElementId::with_hash(&self.ids, self.hash())
1060 }
1061}
1062
1063impl std::ops::Deref for ElementIdStack {
1064 type Target = [ElementId];
1065
1066 fn deref(&self) -> &Self::Target {
1067 &self.ids
1068 }
1069}
1070
1071pub(crate) struct DeferredDraw {
1072 current_view: EntityId,
1073 priority: usize,
1074 parent_node: DispatchNodeId,
1075 element_id_stack: ElementIdStack,
1076 text_style_stack: Vec<TextStyleRefinement>,
1077 content_mask: Option<ContentMask<Pixels>>,
1078 rem_size: Pixels,
1079 element: Option<AnyElement>,
1080 absolute_offset: Point<Pixels>,
1081 prepaint_range: Range<PrepaintStateIndex>,
1082 paint_range: Range<PaintIndex>,
1083}
1084
1085pub(crate) struct Frame {
1086 pub(crate) focus: Option<FocusId>,
1087 pub(crate) window_active: bool,
1088 pub(crate) element_states: FxHashMap<(GlobalElementId, TypeId), ElementStateBox>,
1089 accessed_element_states: Vec<(GlobalElementId, TypeId)>,
1090 pub(crate) mouse_listeners: Vec<Option<AnyMouseListener>>,
1091 pub(crate) dispatch_tree: DispatchTree,
1092 pub(crate) scene: Scene,
1093 pub(crate) hitboxes: Vec<Hitbox>,
1094 pub(crate) hitbox_filters: Vec<Option<HitboxFilter>>,
1099 pub(crate) window_control_hitboxes: Vec<(WindowControlArea, Hitbox)>,
1100 pub(crate) deferred_draws: Vec<DeferredDraw>,
1101 pub(crate) input_handlers: Vec<Option<PlatformInputHandler>>,
1102 pub(crate) tooltip_requests: Vec<Option<TooltipRequest>>,
1103 pub(crate) cursor_styles: Vec<CursorStyleRequest>,
1104 #[cfg(any(test, feature = "test-support"))]
1105 pub(crate) debug_bounds: FxHashMap<String, Bounds<Pixels>>,
1106 #[cfg(any(test, feature = "test-support"))]
1107 debug_bounds_records: Vec<(String, Bounds<Pixels>)>,
1108 #[cfg(any(feature = "inspector", debug_assertions))]
1109 pub(crate) next_inspector_instance_ids: FxHashMap<Rc<crate::InspectorElementPath>, usize>,
1110 #[cfg(any(feature = "inspector", debug_assertions))]
1111 pub(crate) inspector_hitboxes: FxHashMap<HitboxId, crate::InspectorElementId>,
1112 pub(crate) tab_stops: TabStopMap,
1113}
1114
1115#[derive(Clone, Default)]
1116pub(crate) struct PrepaintStateIndex {
1117 hitboxes_index: usize,
1118 tooltips_index: usize,
1119 deferred_draws_index: usize,
1120 dispatch_tree_index: usize,
1121 accessed_element_states_index: usize,
1122 line_layout_index: LineLayoutIndex,
1123}
1124
1125#[derive(Clone, Default)]
1126pub(crate) struct PaintIndex {
1127 scene_index: usize,
1128 #[cfg(any(test, feature = "test-support"))]
1129 debug_bounds_index: usize,
1130 mouse_listeners_index: usize,
1131 input_handlers_index: usize,
1132 cursor_styles_index: usize,
1133 accessed_element_states_index: usize,
1134 tab_handle_index: usize,
1135 line_layout_index: LineLayoutIndex,
1136}
1137
1138impl Frame {
1139 #[cfg(any(test, feature = "test-support"))]
1140 pub(crate) fn record_debug_bounds(&mut self, selector: String, bounds: Bounds<Pixels>) {
1141 self.debug_bounds.insert(selector.clone(), bounds);
1142 self.debug_bounds_records.push((selector, bounds));
1143 }
1144
1145 pub(crate) fn new(dispatch_tree: DispatchTree) -> Self {
1146 Frame {
1147 focus: None,
1148 window_active: false,
1149 element_states: FxHashMap::default(),
1150 accessed_element_states: Vec::new(),
1151 mouse_listeners: Vec::new(),
1152 dispatch_tree,
1153 scene: Scene::default(),
1154 hitboxes: Vec::new(),
1155 hitbox_filters: Vec::new(),
1156 window_control_hitboxes: Vec::new(),
1157 deferred_draws: Vec::new(),
1158 input_handlers: Vec::new(),
1159 tooltip_requests: Vec::new(),
1160 cursor_styles: Vec::new(),
1161
1162 #[cfg(any(test, feature = "test-support"))]
1163 debug_bounds: FxHashMap::default(),
1164 #[cfg(any(test, feature = "test-support"))]
1165 debug_bounds_records: Vec::new(),
1166
1167 #[cfg(any(feature = "inspector", debug_assertions))]
1168 next_inspector_instance_ids: FxHashMap::default(),
1169
1170 #[cfg(any(feature = "inspector", debug_assertions))]
1171 inspector_hitboxes: FxHashMap::default(),
1172 tab_stops: TabStopMap::default(),
1173 }
1174 }
1175
1176 pub(crate) fn clear(&mut self) {
1177 self.element_states.clear();
1178 self.accessed_element_states.clear();
1179 self.mouse_listeners.clear();
1180 self.dispatch_tree.clear();
1181 self.scene.clear();
1182 self.input_handlers.clear();
1183 self.tooltip_requests.clear();
1184 self.cursor_styles.clear();
1185 self.hitboxes.clear();
1186 self.hitbox_filters.clear();
1187 self.window_control_hitboxes.clear();
1188 self.deferred_draws.clear();
1189 self.tab_stops.clear();
1190 self.focus = None;
1191
1192 #[cfg(any(test, feature = "test-support"))]
1193 {
1194 self.debug_bounds.clear();
1195 self.debug_bounds_records.clear();
1196 }
1197
1198 #[cfg(any(feature = "inspector", debug_assertions))]
1199 {
1200 self.next_inspector_instance_ids.clear();
1201 self.inspector_hitboxes.clear();
1202 }
1203 }
1204
1205 pub(crate) fn cursor_style(&self, window: &Window) -> Option<CursorStyle> {
1206 self.cursor_styles
1207 .iter()
1208 .rev()
1209 .fold_while(None, |style, request| match request.hitbox_id {
1210 None => Done(Some(request.style)),
1211 Some(hitbox_id) => Continue(style.or_else(|| {
1212 hitbox_id
1213 .is_hovered_ignoring_last_input(window)
1214 .then_some(request.style)
1215 })),
1216 })
1217 .into_inner()
1218 }
1219
1220 pub(crate) fn hit_test(&self, position: Point<Pixels>) -> HitTest {
1221 let mut set_hover_hitbox_count = false;
1222 let mut hit_test = HitTest::default();
1223 for (index, hitbox) in self.hitboxes.iter().enumerate().rev() {
1224 let bounds = hitbox.bounds.intersect(&hitbox.content_mask.bounds);
1225 if bounds.contains(&position) {
1226 if let Some(filter) = self.hitbox_filters.get(index).and_then(Option::as_ref)
1227 && !filter.allows(position)
1228 {
1229 continue;
1232 }
1233 hit_test.ids.push(hitbox.id);
1234 if !set_hover_hitbox_count
1235 && hitbox.behavior == HitboxBehavior::BlockMouseExceptScroll
1236 {
1237 hit_test.hover_hitbox_count = hit_test.ids.len();
1238 set_hover_hitbox_count = true;
1239 }
1240 if hitbox.behavior == HitboxBehavior::BlockMouse {
1241 break;
1242 }
1243 }
1244 }
1245 if !set_hover_hitbox_count {
1246 hit_test.hover_hitbox_count = hit_test.ids.len();
1247 }
1248 hit_test
1249 }
1250
1251 pub(crate) fn focus_path(&self) -> SmallVec<[FocusId; 8]> {
1252 self.focus
1253 .map(|focus_id| self.dispatch_tree.focus_path(focus_id))
1254 .unwrap_or_default()
1255 }
1256
1257 pub(crate) fn finish(&mut self, prev_frame: &mut Self) {
1258 for element_state_key in &self.accessed_element_states {
1259 if let Some((element_state_key, element_state)) =
1260 prev_frame.element_states.remove_entry(element_state_key)
1261 {
1262 self.element_states.insert(element_state_key, element_state);
1263 }
1264 }
1265
1266 self.scene.finish();
1267 }
1268}
1269
1270#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
1271enum InputModality {
1272 Mouse,
1273 Keyboard,
1274 Touch,
1275}
1276
1277#[cfg(debug_assertions)]
1287#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1288pub(crate) enum FramePhase {
1289 Idle,
1291 Begun,
1293 Evaluated,
1295 LaidOut,
1297 Painted,
1299 Finished,
1301 Completed,
1303}
1304
1305#[cfg(debug_assertions)]
1306impl FramePhase {
1307 #[track_caller]
1309 fn enter(&mut self, from: &[FramePhase], next: FramePhase, method: &'static str) {
1310 debug_assert!(
1311 from.contains(self),
1312 "{method} ran while the frame was {self:?}, but it must follow one of {from:?}"
1313 );
1314 *self = next;
1315 }
1316}
1317
1318pub(crate) struct WindowFrameState {
1319 rem_size_override_stack: SmallVec<[Pixels; 8]>,
1324 layout_session: Rc<FrameSession>,
1325 pub(crate) inspector_element_id: Option<crate::InspectorElementId>,
1330 pub(crate) dirty_views: FxHashSet<EntityId>,
1332 focus_lost_path: SmallVec<[FocusId; 8]>,
1335 pub(crate) element_id_stack: ElementIdStack,
1336 pub(crate) text_style_stack: Vec<TextStyleRefinement>,
1337 pub(crate) rendered_entity_stack: Vec<EntityId>,
1338 pub(crate) element_offset_stack: Vec<Point<Pixels>>,
1339 pub(crate) element_opacity: f32,
1340 pub(crate) content_mask_stack: Vec<ContentMask<Pixels>>,
1341 pub(crate) requested_autoscroll: Option<Bounds<Pixels>>,
1342 pub(crate) image_cache_stack: Vec<AnyImageCache>,
1343 pub(crate) rendered_frame: Frame,
1344 pub(crate) next_frame: Frame,
1345 next_hitbox_id: HitboxId,
1346 pub(crate) next_tooltip_id: TooltipId,
1347 pub(crate) tooltip_bounds: Option<TooltipBounds>,
1348 #[cfg(debug_assertions)]
1350 frame_phase: FramePhase,
1351}
1352
1353pub(crate) struct WindowHostCore {
1359 pub(crate) handle: AnyWindowHandle,
1360 pub(crate) invalidator: WindowInvalidator,
1361 frame_pipeline: Rc<RefCell<Box<dyn FramePipeline>>>,
1366 pub(crate) removed: bool,
1367 metrics: Arc<ArcSwap<WindowMetrics>>,
1369 pub(crate) platform_window: Box<dyn PlatformWindow>,
1370 display_id: Option<DisplayId>,
1371 is_resizable: bool,
1372 is_minimizable: bool,
1373 sprite_atlas: Arc<dyn PlatformAtlas>,
1374 text_system: Arc<WindowTextSystem>,
1375 text_rendering_mode: Rc<Cell<TextRenderingMode>>,
1376 rem_size: Pixels,
1377 pub(crate) viewport_size: Size<Pixels>,
1378 pub(crate) root: Option<AnyView>,
1379 last_text_input_configuration: Option<TextInputConfiguration>,
1383 focused_text_input_active: bool,
1384 pub(crate) next_frame_callbacks: Rc<RefCell<Vec<FrameCallback>>>,
1385 focus_listeners: SubscriberSet<(), AnyWindowFocusListener>,
1386 pub(crate) focus_lost_listeners: SubscriberSet<(), AnyObserver>,
1387 default_prevented: bool,
1388 mouse_position: Point<Pixels>,
1389 mouse_hit_test: HitTest,
1390 modifiers: Modifiers,
1391 capslock: Capslock,
1392 scale_factor: f32,
1393 pub(crate) bounds_observers: SubscriberSet<(), AnyObserver>,
1394 appearance: WindowAppearance,
1395 pub(crate) appearance_observers: SubscriberSet<(), AnyObserver>,
1396 pub(crate) button_layout_observers: SubscriberSet<(), AnyObserver>,
1397 active: Rc<Cell<bool>>,
1398 visibility: WindowVisibility,
1399 pub(crate) visibility_observers:
1400 SubscriberSet<(), Box<dyn FnMut(WindowVisibility, &mut Window, &mut App) -> bool>>,
1401 hovered: Rc<Cell<bool>>,
1402 pub(crate) needs_present: Rc<Cell<bool>>,
1403 pub(crate) input_rate_tracker: Rc<RefCell<InputRateTracker>>,
1406 #[cfg(feature = "profiler")]
1407 window_profiler: profiler::WindowProfiler,
1408 last_input_modality: InputModality,
1409 touch_gestures: TouchGestureRecognizer,
1410 touch_prediction_enabled: bool,
1411 long_press_timer: Option<Task<()>>,
1412 long_press_capture: Option<EntityId>,
1413 pub(crate) refreshing: bool,
1414 pub(crate) activation_observers: SubscriberSet<(), AnyObserver>,
1415 pub(crate) focus: Option<FocusId>,
1416 focus_enabled: bool,
1417 pub(crate) focus_generation: u64,
1420 pending_input: Option<PendingInput>,
1421 pending_modifier: ModifierState,
1422 pub(crate) pending_input_observers: SubscriberSet<(), AnyObserver>,
1423 prompt: Option<RenderablePromptHandle>,
1424 pub(crate) client_inset: Option<Pixels>,
1425 captured_hitbox: Option<HitboxId>,
1428 #[cfg(any(feature = "inspector", debug_assertions))]
1429 inspector: Option<Entity<Inspector>>,
1430 #[cfg(feature = "profiler")]
1431 debug_frame_overlay: crate::debug_overlay::DebugFrameOverlay,
1432 pub(crate) a11y: A11y,
1433}
1434
1435impl WindowHostCore {
1436 fn metrics_handle(&self) -> WindowMetricsHandle {
1437 WindowMetricsHandle {
1438 id: self.handle.window_id(),
1439 metrics: self.metrics.clone(),
1440 }
1441 }
1442
1443 pub(crate) fn should_render_frame(&self) -> bool {
1446 let is_dirty = self.invalidator.is_dirty();
1447 let metrics = self.metrics.load();
1448 self.frame_pipeline
1449 .borrow_mut()
1450 .should_render(is_dirty, &metrics)
1451 }
1452}
1453
1454pub struct WindowMetricsHandle {
1460 id: WindowId,
1461 metrics: Arc<ArcSwap<WindowMetrics>>,
1462}
1463
1464impl WindowMetricsHandle {
1465 pub fn id(&self) -> WindowId {
1467 self.id
1468 }
1469
1470 pub fn snapshot(&self) -> Arc<WindowMetrics> {
1475 self.metrics.load_full()
1476 }
1477
1478 pub fn bounds(&self) -> Bounds<Pixels> {
1480 self.metrics.load().bounds
1481 }
1482
1483 pub fn viewport(&self) -> Bounds<Pixels> {
1488 self.metrics.load().viewport
1489 }
1490
1491 pub fn content_size(&self) -> Size<Pixels> {
1493 self.metrics.load().content_size
1494 }
1495
1496 pub fn scale_factor(&self) -> f32 {
1498 self.metrics.load().scale_factor
1499 }
1500
1501 pub fn display_id(&self) -> Option<DisplayId> {
1503 self.metrics.load().display_id
1504 }
1505
1506 pub fn is_active(&self) -> bool {
1508 self.metrics.load().is_active
1509 }
1510
1511 pub fn is_fullscreen(&self) -> bool {
1513 self.metrics.load().is_fullscreen
1514 }
1515}
1516
1517pub struct Window<'frame> {
1533 pub(crate) core: &'frame mut WindowHostCore,
1536 pub(crate) frame_state: &'frame mut WindowFrameState,
1538}
1539
1540pub(crate) struct WindowHost {
1546 pub(crate) core: WindowHostCore,
1547 pub(crate) frame_state: WindowFrameState,
1548}
1549
1550impl WindowHost {
1551 pub(crate) fn with_window<R>(&mut self, f: impl FnOnce(&mut Window<'_>) -> R) -> R {
1553 let core = &mut self.core;
1554 let frame_state = &mut self.frame_state;
1555 f(&mut Window { core, frame_state })
1556 }
1557}
1558
1559#[derive(Clone, Debug, Default)]
1560struct ModifierState {
1561 modifiers: Modifiers,
1562 saw_other_input: bool,
1563}
1564
1565#[derive(Clone, Debug)]
1568pub(crate) struct InputRateTracker {
1569 timestamps: Vec<Instant>,
1570 window: Duration,
1571 inputs_per_second: u32,
1572 sustain_until: Instant,
1573 sustain_duration: Duration,
1574}
1575
1576impl Default for InputRateTracker {
1577 fn default() -> Self {
1578 Self {
1579 timestamps: Vec::new(),
1580 window: Duration::from_millis(100),
1581 inputs_per_second: 60,
1582 sustain_until: Instant::now(),
1583 sustain_duration: Duration::from_secs(1),
1584 }
1585 }
1586}
1587
1588impl InputRateTracker {
1589 pub fn record_input(&mut self) {
1590 let now = Instant::now();
1591 self.timestamps.push(now);
1592 self.prune_old_timestamps(now);
1593
1594 let min_events = self.inputs_per_second as u128 * self.window.as_millis() / 1000;
1595 if self.timestamps.len() as u128 >= min_events {
1596 self.sustain_until = now + self.sustain_duration;
1597 }
1598 }
1599
1600 pub fn is_high_rate(&self) -> bool {
1601 Instant::now() < self.sustain_until
1602 }
1603
1604 fn prune_old_timestamps(&mut self, now: Instant) {
1605 self.timestamps
1606 .retain(|&t| now.duration_since(t) <= self.window);
1607 }
1608}
1609
1610#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1611pub(crate) enum DrawPhase {
1612 None,
1613 Prepaint,
1614 Paint,
1615 Focus,
1616}
1617
1618pub(crate) const PENDING_INPUT_TIMEOUT: Duration = Duration::from_secs(1);
1619
1620pub struct PendingInputStatus<'a> {
1622 keystrokes: &'a [Keystroke],
1623 timeout: Option<PendingInputTimeoutStatus>,
1624}
1625
1626impl<'a> PendingInputStatus<'a> {
1627 pub fn keystrokes(&self) -> &'a [Keystroke] {
1629 self.keystrokes
1630 }
1631
1632 pub fn timeout(&self) -> Option<PendingInputTimeoutStatus> {
1634 self.timeout
1635 }
1636}
1637
1638#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1640pub struct PendingInputTimeoutStatus {
1641 duration: Duration,
1642 remaining: Duration,
1643 started_at: Option<Instant>,
1644 paused: bool,
1645}
1646
1647impl PendingInputTimeoutStatus {
1648 pub fn duration(&self) -> Duration {
1650 self.duration
1651 }
1652
1653 pub fn remaining(&self, cx: &App) -> Duration {
1655 self.started_at
1656 .map(|started_at| {
1657 self.remaining
1658 .saturating_sub(cx.background_executor().now() - started_at)
1659 })
1660 .unwrap_or(self.remaining)
1661 }
1662
1663 pub fn is_paused(&self) -> bool {
1665 self.paused
1666 }
1667}
1668
1669#[derive(Debug)]
1670struct PendingInputTimeout {
1671 duration: Duration,
1672 remaining: Duration,
1673 state: PendingInputTimeoutState,
1674}
1675
1676#[derive(Debug)]
1677enum PendingInputTimeoutState {
1678 Running { started_at: Instant, task: Task<()> },
1679 Paused { pause: PendingInputTimeoutPause },
1680}
1681
1682#[derive(Debug)]
1683struct PendingInputTimeoutPause {
1684 owner_id: EntityId,
1685 _release_subscription: Subscription,
1686}
1687
1688impl PendingInputTimeout {
1689 fn is_paused(&self) -> bool {
1690 matches!(&self.state, PendingInputTimeoutState::Paused { .. })
1691 }
1692
1693 fn pause(&mut self, pause: PendingInputTimeoutPause, now: Instant) -> bool {
1694 match std::mem::replace(&mut self.state, PendingInputTimeoutState::Paused { pause }) {
1695 PendingInputTimeoutState::Running { started_at, task } => {
1696 self.remaining = self.remaining.saturating_sub(now - started_at);
1697 drop(task);
1698 true
1699 }
1700 previous_state @ PendingInputTimeoutState::Paused { .. } => {
1701 self.state = previous_state;
1702 false
1703 }
1704 }
1705 }
1706
1707 fn pause_owner_id(&self) -> Option<EntityId> {
1708 match &self.state {
1709 PendingInputTimeoutState::Running { .. } => None,
1710 PendingInputTimeoutState::Paused { pause } => Some(pause.owner_id),
1711 }
1712 }
1713
1714 fn resume(&mut self, owner_id: EntityId, started_at: Instant, task: Task<()>) -> bool {
1715 match std::mem::replace(
1716 &mut self.state,
1717 PendingInputTimeoutState::Running { started_at, task },
1718 ) {
1719 PendingInputTimeoutState::Paused { pause } if pause.owner_id == owner_id => true,
1720 previous_state => {
1721 self.state = previous_state;
1722 false
1723 }
1724 }
1725 }
1726
1727 fn reset_duration(&mut self, duration: Duration) {
1728 self.duration = duration;
1729 self.remaining = duration;
1730 }
1731
1732 fn status(&self) -> PendingInputTimeoutStatus {
1733 let (started_at, paused) = match &self.state {
1734 PendingInputTimeoutState::Running { started_at, .. } => (Some(*started_at), false),
1735 PendingInputTimeoutState::Paused { .. } => (None, true),
1736 };
1737 PendingInputTimeoutStatus {
1738 duration: self.duration,
1739 remaining: self.remaining,
1740 started_at,
1741 paused,
1742 }
1743 }
1744}
1745
1746#[derive(Default, Debug)]
1747struct PendingInput {
1748 keystrokes: SmallVec<[Keystroke; 1]>,
1749 focus: Option<FocusId>,
1750 timeout: Option<PendingInputTimeout>,
1751}
1752
1753pub(crate) struct ElementStateBox {
1754 pub(crate) inner: Box<dyn Any>,
1755 #[cfg(debug_assertions)]
1756 pub(crate) type_name: &'static str,
1757}
1758
1759fn default_bounds(display_id: Option<DisplayId>, cx: &mut App) -> WindowBounds {
1760 let active_window_bounds = cx
1765 .active_window()
1766 .and_then(|w| w.update(cx, |_, window, _| window.window_bounds()).ok());
1767
1768 const CASCADE_OFFSET: f32 = 25.0;
1769
1770 let display = display_id
1771 .map(|id| cx.find_display(id))
1772 .unwrap_or_else(|| cx.primary_display());
1773
1774 let default_placement = || Bounds::new(point(px(0.), px(0.)), DEFAULT_WINDOW_SIZE);
1775
1776 let display_bounds = display
1778 .as_ref()
1779 .map(|d| d.visible_bounds())
1780 .unwrap_or_else(default_placement);
1781
1782 let (
1783 Bounds {
1784 origin: base_origin,
1785 size: base_size,
1786 },
1787 window_bounds_ctor,
1788 ): (_, fn(Bounds<Pixels>) -> WindowBounds) = match active_window_bounds {
1789 Some(bounds) => match bounds {
1790 WindowBounds::Windowed(bounds) => (bounds, WindowBounds::Windowed),
1791 WindowBounds::Maximized(bounds) => (bounds, WindowBounds::Maximized),
1792 WindowBounds::Fullscreen(bounds) => (bounds, WindowBounds::Fullscreen),
1793 },
1794 None => (
1795 display
1796 .as_ref()
1797 .map(|d| d.default_bounds())
1798 .unwrap_or_else(default_placement),
1799 WindowBounds::Windowed,
1800 ),
1801 };
1802
1803 let cascade_offset = point(px(CASCADE_OFFSET), px(CASCADE_OFFSET));
1804 let proposed_origin = base_origin + cascade_offset;
1805 let proposed_bounds = Bounds::new(proposed_origin, base_size);
1806
1807 let display_right = display_bounds.origin.x + display_bounds.size.width;
1808 let display_bottom = display_bounds.origin.y + display_bounds.size.height;
1809 let window_right = proposed_bounds.origin.x + proposed_bounds.size.width;
1810 let window_bottom = proposed_bounds.origin.y + proposed_bounds.size.height;
1811
1812 let fits_horizontally = window_right <= display_right;
1813 let fits_vertically = window_bottom <= display_bottom;
1814
1815 let final_origin = match (fits_horizontally, fits_vertically) {
1816 (true, true) => proposed_origin,
1817 (false, true) => point(display_bounds.origin.x, base_origin.y),
1818 (true, false) => point(base_origin.x, display_bounds.origin.y),
1819 (false, false) => display_bounds.origin,
1820 };
1821 window_bounds_ctor(Bounds::new(final_origin, base_size))
1822}
1823
1824impl WindowHost {
1825 pub(crate) fn new(
1826 handle: AnyWindowHandle,
1827 options: WindowOptions,
1828 cx: &mut App,
1829 ) -> Result<Self> {
1830 let WindowOptions {
1831 window_bounds,
1832 titlebar,
1833 focus,
1834 show,
1835 kind,
1836 is_movable,
1837 app_owns_titlebar_drag,
1838 inactive_frame_interval,
1839 is_resizable,
1840 is_minimizable,
1841 display_id,
1842 window_background,
1843 app_id,
1844 window_min_size,
1845 window_decorations,
1846 #[cfg_attr(
1847 not(any(target_os = "linux", target_os = "freebsd")),
1848 allow(unused_variables)
1849 )]
1850 icon,
1851 #[cfg_attr(not(target_os = "macos"), allow(unused_variables))]
1852 tabbing_identifier,
1853 renderer_factory,
1854 } = options;
1855
1856 let initial_window_title = titlebar
1857 .as_ref()
1858 .and_then(|titlebar| titlebar.title.clone());
1859
1860 let window_bounds = window_bounds.unwrap_or_else(|| default_bounds(display_id, cx));
1861 let mut platform_window = cx.platform.open_window(
1862 handle.window_id(),
1863 WindowParams {
1864 bounds: window_bounds.get_bounds(),
1865 titlebar,
1866 kind,
1867 is_movable,
1868 app_owns_titlebar_drag,
1869 is_resizable,
1870 is_minimizable,
1871 focus,
1872 show,
1873 display_id,
1874 window_min_size,
1875 app_id: app_id.clone(),
1876 icon,
1877 #[cfg(target_os = "macos")]
1878 tabbing_identifier,
1879 renderer_factory,
1880 },
1881 )?;
1882
1883 let tab_bar_visible = platform_window.tab_bar_visible();
1884 SystemWindowTabController::init_visible(cx, tab_bar_visible);
1885 if let Some(tabs) = platform_window.tabbed_windows() {
1886 SystemWindowTabController::add_tab(cx, handle.window_id(), tabs);
1887 }
1888
1889 let display_id = platform_window.display().map(|display| display.id());
1890 let mut sprite_atlas = None;
1891 platform_window.with_renderer(&mut |renderer| {
1892 sprite_atlas = Some(renderer.sprite_atlas());
1893 });
1894 let sprite_atlas = sprite_atlas
1895 .ok_or_else(|| anyhow!("platform window did not provide a scene renderer"))?;
1896 let mouse_position = platform_window.mouse_position();
1897 let modifiers = platform_window.modifiers();
1898 let capslock = platform_window.capslock();
1899 let content_size = platform_window.content_size();
1900 let scale_factor = platform_window.scale_factor();
1901 let appearance = platform_window.appearance();
1902 let text_system = Arc::new(WindowTextSystem::new(cx.text_system().clone()));
1903 let invalidator = WindowInvalidator::new(handle.window_id());
1904 let active = Rc::new(Cell::new(platform_window.is_active()));
1905 let visibility = platform_window.visibility();
1906 #[cfg(feature = "profiler")]
1907 profiler::journal::record_window_visibility(handle.window_id(), visibility);
1908 let metrics = Arc::new(ArcSwap::from_pointee(WindowMetrics {
1909 bounds: platform_window.bounds(),
1910 viewport: platform_window.visual_viewport_bounds(),
1911 content_size,
1912 scale_factor,
1913 display_id,
1914 is_active: active.get(),
1915 is_fullscreen: platform_window.is_fullscreen(),
1916 }));
1917 let hovered = Rc::new(Cell::new(platform_window.is_hovered()));
1918 let needs_present = Rc::new(Cell::new(false));
1919 let next_frame_callbacks: Rc<RefCell<Vec<FrameCallback>>> = Default::default();
1920 let input_rate_tracker = Rc::new(RefCell::new(InputRateTracker::default()));
1921 let last_frame_time = Rc::new(Cell::new(None));
1922
1923 platform_window
1924 .request_decorations(window_decorations.unwrap_or(WindowDecorations::Server));
1925 platform_window.set_background_appearance(window_background);
1926
1927 match window_bounds {
1928 WindowBounds::Fullscreen(_) => platform_window.toggle_fullscreen(),
1929 WindowBounds::Maximized(_) => platform_window.zoom(),
1930 WindowBounds::Windowed(_) => {}
1931 }
1932
1933 let accessibility_force_disabled = cx.accessibility_force_disabled;
1934 let a11y_active_flag = Arc::new(AtomicBool::new(false));
1935
1936 #[cfg(not(target_family = "wasm"))]
1937 if !accessibility_force_disabled {
1938 let mut initial_root_node = accesskit::Node::new(accesskit::Role::Window);
1939 if let Some(title) = &initial_window_title {
1940 initial_root_node.set_label(title.to_string());
1941 }
1942 let initial_tree = accesskit::TreeUpdate {
1943 nodes: vec![(ROOT_NODE_ID, initial_root_node)],
1944 tree: Some(accesskit::Tree::new(ROOT_NODE_ID)),
1945 tree_id: accesskit::TreeId::ROOT,
1946 focus: ROOT_NODE_ID,
1947 };
1948 let (activation_sender, activation_receiver) = async_channel::unbounded::<()>();
1949 let (deactivation_sender, deactivation_receiver) = async_channel::unbounded::<()>();
1950 let (action_sender, action_receiver) =
1951 async_channel::unbounded::<accesskit::ActionRequest>();
1952
1953 platform_window.a11y_init(crate::A11yCallbacks {
1954 activation: {
1955 let active_flag = a11y_active_flag.clone();
1956 Box::new(move || {
1957 log::info!("Accessibility activated");
1958 active_flag.store(true, SeqCst);
1959 activation_sender.send_blocking(()).log_err();
1960 Some(initial_tree.clone())
1961 })
1962 },
1963 action: Box::new(move |request| {
1964 action_sender.send_blocking(request).log_err();
1965 }),
1966 deactivation: {
1967 let active_flag = a11y_active_flag.clone();
1968 Box::new(move || {
1969 log::info!("Accessibility deactivated");
1970 active_flag.store(false, SeqCst);
1971 deactivation_sender.send_blocking(()).log_err();
1972 })
1973 },
1974 });
1975
1976 let mut async_cx = cx.to_async();
1982 cx.foreground_executor()
1983 .spawn(async move {
1984 while activation_receiver.recv().await.is_ok() {
1985 handle
1986 .update(&mut async_cx, |_, window, _| window.refresh())
1987 .log_err();
1988 }
1989 })
1990 .detach();
1991
1992 let mut async_cx = cx.to_async();
1993 cx.foreground_executor()
1994 .spawn(async move {
1995 while deactivation_receiver.recv().await.is_ok() {
1996 handle
1997 .update(&mut async_cx, |_, window, _| window.refresh())
1998 .log_err();
1999 }
2000 })
2001 .detach();
2002
2003 let mut async_cx = cx.to_async();
2004 cx.foreground_executor()
2005 .spawn(async move {
2006 while let Ok(request) = action_receiver.recv().await {
2007 handle
2008 .update(&mut async_cx, |_, window, cx| {
2009 window.handle_a11y_action(request, cx);
2010 })
2011 .log_err();
2012 }
2013 })
2014 .detach();
2015 }
2016
2017 platform_window.on_close(Box::new({
2018 let window_id = handle.window_id();
2019 let mut cx = cx.to_async();
2020 move || {
2021 let _ = handle.update(&mut cx, |_, window, _| window.remove_window());
2022 let _ = cx.update(|cx| {
2023 SystemWindowTabController::remove_tab(cx, window_id);
2024 });
2025 }
2026 }));
2027 platform_window.on_request_frame(Box::new({
2028 let mut cx = cx.to_async();
2029 let invalidator = invalidator.clone();
2030 let active = active.clone();
2031 let needs_present = needs_present.clone();
2032 let next_frame_callbacks = next_frame_callbacks.clone();
2033 let input_rate_tracker = input_rate_tracker.clone();
2034 let mut deferred_force_render = false;
2035 move |request_frame_options| {
2036 #[cfg(feature = "profiler")]
2037 let (_foreground_turn, window_id) = {
2038 let foreground_turn = profiler::journal::foreground_turn();
2039 let window_id = handle.window_id();
2040 profiler::journal::record_platform_signal(profiler::journal::PlatformSignal {
2041 window_id,
2042 signal_at: request_frame_options.signal_at,
2043 handled_at: Instant::now(),
2044 source: request_frame_options.signal_source,
2045 });
2046 (foreground_turn, window_id)
2047 };
2048 if draw_in_progress() {
2064 log::debug!("deferring re-entrant window draw request");
2065 deferred_force_render |= request_frame_options.force_render;
2066 #[cfg(feature = "profiler")]
2067 profiler::journal::record_reentrant_frame_skipped(window_id, Instant::now());
2068 return;
2069 }
2070 let force_render =
2074 mem::take(&mut deferred_force_render) || request_frame_options.force_render;
2075
2076 let thermal_state = handle
2077 .update(&mut cx, |_, _, cx| cx.thermal_state())
2078 .log_err();
2079
2080 let min_frame_interval = if request_frame_options.require_presentation
2084 || (!request_frame_options.force_render
2085 && next_frame_callbacks.borrow().is_empty())
2086 {
2087 None
2088 } else if !active.get() && !input_rate_tracker.borrow_mut().is_high_rate() {
2089 inactive_frame_interval.map(|interval| (interval, FrameRateLimit::Inactive))
2090 } else if let Some(ThermalState::Critical | ThermalState::Serious) = thermal_state {
2091 Some((Duration::from_micros(16667), FrameRateLimit::Thermal))
2092 } else {
2093 None
2094 };
2095
2096 let now = Instant::now();
2097 #[cfg_attr(not(feature = "profiler"), expect(unused_variables))]
2098 if let Some((min_interval, limit)) = min_frame_interval {
2099 if let Some(last_frame) = last_frame_time.get()
2100 && now.duration_since(last_frame) < min_interval
2101 {
2102 deferred_force_render |= force_render;
2104 handle
2106 .update(&mut cx, |_, window, _| {
2107 window.core.platform_window.schedule_frame();
2108 })
2109 .log_err();
2110 invalidator.wake_platform();
2115 #[cfg(feature = "profiler")]
2116 profiler::journal::record_frame_skipped(
2117 window_id,
2118 Instant::now(),
2119 match limit {
2120 FrameRateLimit::Inactive => {
2121 profiler::journal::FrameSkipReason::InactiveFrameRateLimit
2122 }
2123 FrameRateLimit::Thermal => {
2124 profiler::journal::FrameSkipReason::ThermalFrameRateLimit
2125 }
2126 },
2127 );
2128 return;
2129 }
2130 }
2131 last_frame_time.set(Some(now));
2132
2133 let pending_next_frame_callbacks = next_frame_callbacks.take();
2134 if !pending_next_frame_callbacks.is_empty() {
2135 handle
2136 .update(&mut cx, |_, window, cx| {
2137 for callback in pending_next_frame_callbacks {
2138 callback(window, cx);
2139 }
2140 })
2141 .log_err();
2142 }
2143
2144 let needs_present = request_frame_options.require_presentation
2148 || needs_present.get()
2149 || input_rate_tracker.borrow_mut().is_high_rate();
2150
2151 let should_draw = invalidator.is_dirty() || force_render;
2152 if should_draw {
2153 measure("frame duration", || {
2154 handle
2155 .update(&mut cx, |_, window, cx| {
2156 if force_render {
2157 window.refresh();
2160 }
2161 if force_render || window.core.should_render_frame() {
2164 let arena_clear_needed = window.draw(cx);
2165 window.present();
2166 arena_clear_needed.clear(cx);
2167 }
2168 })
2169 .log_err();
2170 })
2171 } else if needs_present {
2172 handle
2173 .update(&mut cx, |_, window, _| window.present())
2174 .log_err();
2175 }
2176
2177 handle
2178 .update(&mut cx, |_, window, _| {
2179 if window.core.invalidator.is_dirty()
2180 || !window.core.next_frame_callbacks.borrow().is_empty()
2181 {
2182 window.core.platform_window.schedule_frame();
2183 }
2184 })
2185 .log_err();
2186
2187 if invalidator.is_dirty() || !next_frame_callbacks.borrow().is_empty() {
2193 invalidator.wake_platform();
2194 }
2195 #[cfg(feature = "profiler")]
2196 if !should_draw {
2197 profiler::journal::record_frame_skipped(
2198 window_id,
2199 Instant::now(),
2200 profiler::journal::FrameSkipReason::NoRenderNeeded,
2201 );
2202 }
2203 }
2204 }));
2205 invalidator.set_platform_waker(platform_window.frame_waker());
2206 platform_window.on_visual_viewport_changed(Box::new({
2207 let mut cx = cx.to_async();
2208 move || {
2209 handle
2210 .update(&mut cx, |_, window, _| window.refresh())
2211 .log_err();
2212 }
2213 }));
2214 platform_window.on_insets_changed(Box::new({
2215 let mut cx = cx.to_async();
2216 move |_| {
2217 handle
2218 .update(&mut cx, |_, window, _| window.refresh())
2219 .log_err();
2220 }
2221 }));
2222 platform_window.on_resize(Box::new({
2223 let mut cx = cx.to_async();
2224 move |_, _| {
2225 handle
2226 .update(&mut cx, |_, window, cx| window.bounds_changed(cx))
2227 .log_err();
2228 }
2229 }));
2230 platform_window.on_moved(Box::new({
2231 let mut cx = cx.to_async();
2232 move || {
2233 handle
2234 .update(&mut cx, |_, window, cx| window.bounds_changed(cx))
2235 .log_err();
2236 }
2237 }));
2238 platform_window.on_appearance_changed(Box::new({
2239 let cx = cx.to_async();
2240 let foreground_executor = cx.foreground_executor().clone();
2241 move || {
2242 let mut cx = cx.clone();
2243 foreground_executor
2246 .spawn(async move {
2247 handle
2248 .update(&mut cx, |_, window, cx| window.appearance_changed(cx))
2249 .log_err();
2250 })
2251 .detach();
2252 }
2253 }));
2254 platform_window.on_button_layout_changed(Box::new({
2255 let mut cx = cx.to_async();
2256 move || {
2257 handle
2258 .update(&mut cx, |_, window, cx| window.button_layout_changed(cx))
2259 .log_err();
2260 }
2261 }));
2262 platform_window.on_active_status_change(Box::new({
2263 let mut cx = cx.to_async();
2264 move |active| {
2265 handle
2266 .update(&mut cx, |_, window, cx| {
2267 window.core.active.set(active);
2268 window.core.modifiers = window.core.platform_window.modifiers();
2269 window.core.capslock = window.core.platform_window.capslock();
2270 window
2271 .core
2272 .activation_observers
2273 .clone()
2274 .retain(&(), |callback| callback(window, cx));
2275
2276 window.bounds_changed(cx);
2277 window.refresh();
2278
2279 SystemWindowTabController::update_last_active(cx, window.core.handle.id);
2280 })
2281 .log_err();
2282 }
2283 }));
2284 platform_window.on_visibility_change(Box::new({
2285 let mut cx = cx.to_async();
2286 move |_| {
2287 handle
2288 .update(&mut cx, |_, window, cx| {
2289 window.refresh_visibility(cx);
2290 })
2291 .log_err();
2292 }
2293 }));
2294 platform_window.on_hover_status_change(Box::new({
2295 let mut cx = cx.to_async();
2296 move |active| {
2297 handle
2298 .update(&mut cx, |_, window, _| {
2299 window.core.hovered.set(active);
2300 window.refresh();
2301 })
2302 .log_err();
2303 }
2304 }));
2305 platform_window.on_input({
2306 let mut cx = cx.to_async();
2307 Box::new(move |event| {
2308 handle
2309 .update(&mut cx, |_, window, cx| window.dispatch_event(event, cx))
2310 .log_err()
2311 .unwrap_or(DispatchEventResult::default())
2312 })
2313 });
2314 platform_window.on_hit_test_window_control({
2315 let mut cx = cx.to_async();
2316 Box::new(move || {
2317 handle
2318 .update(&mut cx, |_, window, _cx| {
2319 for (area, hitbox) in
2320 &window.frame_state.rendered_frame.window_control_hitboxes
2321 {
2322 if window.core.mouse_hit_test.ids.contains(&hitbox.id) {
2323 return Some(*area);
2324 }
2325 }
2326 None
2327 })
2328 .log_err()
2329 .unwrap_or(None)
2330 })
2331 });
2332 platform_window.on_move_tab_to_new_window({
2333 let mut cx = cx.to_async();
2334 Box::new(move || {
2335 handle
2336 .update(&mut cx, |_, _window, cx| {
2337 SystemWindowTabController::move_tab_to_new_window(cx, handle.window_id());
2338 })
2339 .log_err();
2340 })
2341 });
2342 platform_window.on_merge_all_windows({
2343 let mut cx = cx.to_async();
2344 Box::new(move || {
2345 handle
2346 .update(&mut cx, |_, _window, cx| {
2347 SystemWindowTabController::merge_all_windows(cx, handle.window_id());
2348 })
2349 .log_err();
2350 })
2351 });
2352 platform_window.on_select_next_tab({
2353 let mut cx = cx.to_async();
2354 Box::new(move || {
2355 handle
2356 .update(&mut cx, |_, _window, cx| {
2357 SystemWindowTabController::select_next_tab(cx, handle.window_id());
2358 })
2359 .log_err();
2360 })
2361 });
2362 platform_window.on_select_previous_tab({
2363 let mut cx = cx.to_async();
2364 Box::new(move || {
2365 handle
2366 .update(&mut cx, |_, _window, cx| {
2367 SystemWindowTabController::select_previous_tab(cx, handle.window_id())
2368 })
2369 .log_err();
2370 })
2371 });
2372 platform_window.on_toggle_tab_bar({
2373 let mut cx = cx.to_async();
2374 Box::new(move || {
2375 handle
2376 .update(&mut cx, |_, window, cx| {
2377 let tab_bar_visible = window.core.platform_window.tab_bar_visible();
2378 SystemWindowTabController::set_visible(cx, tab_bar_visible);
2379 })
2380 .log_err();
2381 })
2382 });
2383
2384 if let Some(app_id) = app_id {
2385 platform_window.set_app_id(&app_id);
2386 }
2387
2388 platform_window.map_window().unwrap();
2389
2390 Ok(WindowHost {
2391 core: WindowHostCore {
2392 handle,
2393 invalidator,
2394 frame_pipeline: Rc::new(RefCell::new(cx.new_frame_pipeline(handle.window_id()))),
2395 removed: false,
2396 metrics,
2397 platform_window,
2398 display_id,
2399 is_resizable,
2400 is_minimizable,
2401 sprite_atlas,
2402 text_system,
2403 text_rendering_mode: cx.text_rendering_mode.clone(),
2404 rem_size: px(16.),
2405 viewport_size: content_size,
2406 root: None,
2407 last_text_input_configuration: None,
2408 focused_text_input_active: false,
2409 next_frame_callbacks,
2410 focus_listeners: SubscriberSet::new(),
2411 focus_lost_listeners: SubscriberSet::new(),
2412 default_prevented: true,
2413 mouse_position,
2414 mouse_hit_test: HitTest::default(),
2415 modifiers,
2416 capslock,
2417 scale_factor,
2418 bounds_observers: SubscriberSet::new(),
2419 appearance,
2420 appearance_observers: SubscriberSet::new(),
2421 button_layout_observers: SubscriberSet::new(),
2422 active,
2423 visibility,
2424 visibility_observers: SubscriberSet::new(),
2425 hovered,
2426 needs_present,
2427 input_rate_tracker,
2428 #[cfg(feature = "profiler")]
2429 window_profiler: profiler::WindowProfiler::new(handle.window_id())?,
2430 last_input_modality: InputModality::Mouse,
2431 touch_gestures: TouchGestureRecognizer::new(
2432 cx.platform
2433 .gestures()
2434 .map_or_else(GestureTuning::default, |gestures| gestures.tuning()),
2435 ),
2436 touch_prediction_enabled: true,
2437 long_press_timer: None,
2438 long_press_capture: None,
2439 refreshing: false,
2440 activation_observers: SubscriberSet::new(),
2441 focus: None,
2442 focus_enabled: true,
2443 focus_generation: 0,
2444 pending_input: None,
2445 pending_modifier: ModifierState::default(),
2446 pending_input_observers: SubscriberSet::new(),
2447 prompt: None,
2448 client_inset: None,
2449 captured_hitbox: None,
2450 #[cfg(any(feature = "inspector", debug_assertions))]
2451 inspector: None,
2452 #[cfg(feature = "profiler")]
2453 debug_frame_overlay: crate::debug_overlay::DebugFrameOverlay::new(),
2454 a11y: A11y::new(
2455 a11y_active_flag,
2456 accessibility_force_disabled,
2457 initial_window_title,
2458 ),
2459 },
2460 frame_state: WindowFrameState {
2461 rem_size_override_stack: SmallVec::new(),
2462 layout_session: Rc::new(FrameSession::new(cx.new_layout_engine())),
2463 inspector_element_id: None,
2464 dirty_views: FxHashSet::default(),
2465 focus_lost_path: SmallVec::new(),
2466 element_id_stack: ElementIdStack::default(),
2467 text_style_stack: Vec::new(),
2468 rendered_entity_stack: Vec::new(),
2469 element_offset_stack: Vec::new(),
2470 element_opacity: 1.0,
2471 content_mask_stack: Vec::new(),
2472 requested_autoscroll: None,
2473 image_cache_stack: Vec::new(),
2474 rendered_frame: Frame::new(DispatchTree::new(
2475 cx.keymap.clone(),
2476 cx.actions.clone(),
2477 )),
2478 next_frame: Frame::new(DispatchTree::new(cx.keymap.clone(), cx.actions.clone())),
2479 next_hitbox_id: HitboxId(0),
2480 next_tooltip_id: TooltipId::default(),
2481 tooltip_bounds: None,
2482 #[cfg(debug_assertions)]
2483 frame_phase: FramePhase::Idle,
2484 },
2485 })
2486 }
2487}
2488
2489pub struct PreparedRoots {
2501 pub root: AnyElement,
2503 pub prompt: Option<AnyElement>,
2505 pub tooltip: Option<AnyElement>,
2507 pub drag: Option<(AnyElement, Point<Pixels>)>,
2510 pub inspector: Option<AnyElement>,
2512}
2513
2514impl Window<'_> {
2515 pub(crate) fn new_focus_listener(
2516 &self,
2517 value: AnyWindowFocusListener,
2518 ) -> (Subscription, impl FnOnce() + use<>) {
2519 self.core.focus_listeners.insert((), value)
2520 }
2521
2522 fn mark_view_dirty(&mut self, view_id: EntityId) {
2523 for view_id in self
2526 .frame_state
2527 .rendered_frame
2528 .dispatch_tree
2529 .view_path_reversed(view_id)
2530 {
2531 if !self.frame_state.dirty_views.insert(view_id) {
2532 break;
2533 }
2534 }
2535 }
2536
2537 pub(crate) fn refresh_visibility(&mut self, cx: &mut App) {
2538 let visibility = self.core.platform_window.visibility();
2539 if self.core.visibility != visibility {
2540 self.core.visibility = visibility;
2541 #[cfg(feature = "profiler")]
2542 profiler::journal::record_window_visibility(self.core.handle.window_id(), visibility);
2543 self.core
2544 .visibility_observers
2545 .clone()
2546 .retain(&(), |callback| callback(visibility, self, cx));
2547 }
2548 #[cfg(feature = "profiler")]
2549 if self.core.invalidator.is_dirty() || self.core.needs_present.get() {
2550 profiler::journal::record_frame_pending(self.core.handle.window_id(), Instant::now());
2551 }
2552 }
2553
2554 pub fn visibility(&self) -> WindowVisibility {
2557 self.core.visibility
2558 }
2559
2560 pub fn is_visible(&self) -> bool {
2566 self.core.visibility.is_visible()
2567 }
2568
2569 pub fn observe_window_visibility(
2571 &self,
2572 mut callback: impl FnMut(WindowVisibility, &mut Window, &mut App) + 'static,
2573 ) -> Subscription {
2574 let (subscription, activate) = self.core.visibility_observers.insert(
2575 (),
2576 Box::new(move |visibility, window, cx| {
2577 callback(visibility, window, cx);
2578 true
2579 }),
2580 );
2581 activate();
2582 subscription
2583 }
2584
2585 pub fn observe_window_appearance(
2587 &self,
2588 mut callback: impl FnMut(&mut Window, &mut App) + 'static,
2589 ) -> Subscription {
2590 let (subscription, activate) = self.core.appearance_observers.insert(
2591 (),
2592 Box::new(move |window, cx| {
2593 callback(window, cx);
2594 true
2595 }),
2596 );
2597 activate();
2598 subscription
2599 }
2600
2601 pub fn observe_button_layout_changed(
2603 &self,
2604 mut callback: impl FnMut(&mut Window, &mut App) + 'static,
2605 ) -> Subscription {
2606 let (subscription, activate) = self.core.button_layout_observers.insert(
2607 (),
2608 Box::new(move |window, cx| {
2609 callback(window, cx);
2610 true
2611 }),
2612 );
2613 activate();
2614 subscription
2615 }
2616
2617 pub fn replace_root<E>(
2619 &mut self,
2620 cx: &mut App,
2621 build_view: impl FnOnce(&mut Window, &mut Context<E>) -> E,
2622 ) -> Entity<E>
2623 where
2624 E: 'static + Render,
2625 {
2626 let view = cx.new(|cx| build_view(self, cx));
2627 self.core.root = Some(view.clone().into());
2628 self.refresh();
2629 view
2630 }
2631
2632 pub fn root<E>(&self) -> Option<Option<Entity<E>>>
2634 where
2635 E: 'static + Render,
2636 {
2637 self.core
2638 .root
2639 .as_ref()
2640 .map(|view| view.clone().downcast::<E>().ok())
2641 }
2642
2643 pub fn window_handle(&self) -> AnyWindowHandle {
2645 self.core.handle
2646 }
2647
2648 pub fn metrics_handle(&self) -> WindowMetricsHandle {
2654 self.core.metrics_handle()
2655 }
2656
2657 pub fn refresh(&mut self) {
2659 if self.core.invalidator.not_drawing() {
2660 self.core.refreshing = true;
2661 self.core.invalidator.set_dirty(true);
2662 }
2663 }
2664
2665 pub fn remove_window(&mut self) {
2667 self.core.removed = true;
2668 }
2669
2670 pub fn focused(&self, cx: &App) -> Option<FocusHandle> {
2672 self.core
2673 .focus
2674 .and_then(|id| FocusHandle::for_id(id, &cx.focus_handles))
2675 }
2676
2677 pub fn focus_lost_restore_target(&self, cx: &App) -> Option<FocusHandle> {
2681 let (_leaf, ancestors) = self.frame_state.focus_lost_path.split_last()?;
2682 ancestors.iter().rev().find_map(|id| {
2683 self.frame_state
2684 .rendered_frame
2685 .dispatch_tree
2686 .focusable_node_id(*id)?;
2687 FocusHandle::for_id(*id, &cx.focus_handles)
2688 })
2689 }
2690
2691 pub fn focus(&mut self, handle: &FocusHandle, cx: &mut App) {
2693 if !self.core.focus_enabled || self.core.focus == Some(handle.id) {
2694 return;
2695 }
2696
2697 self.core.focus = Some(handle.id);
2698 self.core.focus_generation = self.core.focus_generation.wrapping_add(1);
2699 self.clear_pending_keystrokes(cx);
2700
2701 self.refresh();
2702 }
2703
2704 pub fn blur(&mut self, cx: &mut App) {
2706 self.clear_pending_keystrokes(cx);
2707
2708 if !self.core.focus_enabled {
2709 return;
2710 }
2711
2712 if self.core.focus.is_some() {
2713 self.core.focus_generation = self.core.focus_generation.wrapping_add(1);
2714 }
2715 self.core.focus = None;
2716 self.refresh();
2717 }
2718
2719 pub fn disable_focus(&mut self, cx: &mut App) {
2721 self.blur(cx);
2722 self.core.focus_enabled = false;
2723 }
2724
2725 pub fn focus_next(&mut self, cx: &mut App) {
2727 if !self.core.focus_enabled {
2728 return;
2729 }
2730
2731 if let Some(handle) = self
2732 .frame_state
2733 .rendered_frame
2734 .tab_stops
2735 .next(self.core.focus.as_ref())
2736 {
2737 self.focus(&handle, cx)
2738 }
2739 }
2740
2741 pub fn focus_prev(&mut self, cx: &mut App) {
2743 if !self.core.focus_enabled {
2744 return;
2745 }
2746
2747 if let Some(handle) = self
2748 .frame_state
2749 .rendered_frame
2750 .tab_stops
2751 .prev(self.core.focus.as_ref())
2752 {
2753 self.focus(&handle, cx)
2754 }
2755 }
2756
2757 pub fn text_system(&self) -> &Arc<WindowTextSystem> {
2759 &self.core.text_system
2760 }
2761
2762 pub fn text_style(&self) -> TextStyle {
2764 let mut style = TextStyle::default();
2765 for refinement in &self.frame_state.text_style_stack {
2766 style.refine(refinement);
2767 }
2768 style
2769 }
2770
2771 pub fn is_maximized(&self) -> bool {
2775 self.core.platform_window.is_maximized()
2776 }
2777
2778 pub fn request_decorations(&self, decorations: WindowDecorations) {
2780 self.core.platform_window.request_decorations(decorations);
2781 }
2782
2783 pub fn set_exclusive_zone(&self, zone: Pixels) {
2789 self.core.platform_window.set_exclusive_zone(zone);
2790 }
2791
2792 #[cfg(all(target_os = "linux", feature = "wayland"))]
2797 pub fn set_exclusive_edge(&self, edge: crate::layer_shell::Anchor) {
2798 self.core.platform_window.set_exclusive_edge(edge);
2799 }
2800
2801 pub fn start_window_resize(&self, edge: ResizeEdge) {
2803 if self.core.is_resizable {
2804 self.core.platform_window.start_window_resize(edge);
2805 }
2806 }
2807
2808 pub fn set_input_region(&self, region: Option<&[Bounds<Pixels>]>) {
2815 self.core.platform_window.set_input_region(region);
2816 }
2817
2818 pub fn window_bounds(&self) -> WindowBounds {
2821 self.core.platform_window.window_bounds()
2822 }
2823
2824 pub fn inner_window_bounds(&self) -> WindowBounds {
2826 self.core.platform_window.inner_window_bounds()
2827 }
2828
2829 pub fn native_window_state(&self) -> Option<Vec<u8>> {
2832 self.core.platform_window.native_window_state()
2833 }
2834
2835 pub fn restore_native_window_state(&self, state: &[u8]) {
2838 self.core.platform_window.restore_native_window_state(state);
2839 }
2840
2841 pub fn dispatch_action(&mut self, action: Box<dyn Action>, cx: &mut App) {
2843 let focus_id = self.focused(cx).map(|handle| handle.id);
2844
2845 let window = self.core.handle;
2846 cx.defer(move |cx| {
2847 window
2848 .update(cx, |_, window, cx| {
2849 let node_id = window.focus_node_id_in_rendered_frame(focus_id);
2850 window.dispatch_action_on_node(node_id, action.as_ref(), cx);
2851 })
2852 .log_err();
2853 })
2854 }
2855
2856 pub(crate) fn dispatch_keystroke_observers(
2857 &mut self,
2858 keystroke: &Keystroke,
2859 input_preference: InputPreference,
2860 action: Option<&dyn Action>,
2861 context_stack: Vec<KeyContext>,
2862 cx: &mut App,
2863 ) {
2864 cx.keystroke_observers.clone().retain(&(), move |callback| {
2865 (callback)(
2866 &KeystrokeEvent {
2867 keystroke: keystroke.clone(),
2868 input_preference,
2869 action: action.map(|action| action.boxed_clone()),
2870 context_stack: context_stack.clone(),
2871 },
2872 self,
2873 cx,
2874 )
2875 });
2876 }
2877
2878 pub(crate) fn dispatch_keystroke_interceptors(
2879 &mut self,
2880 keystroke: &Keystroke,
2881 input_preference: InputPreference,
2882 context_stack: Vec<KeyContext>,
2883 cx: &mut App,
2884 ) {
2885 cx.keystroke_interceptors
2886 .clone()
2887 .retain(&(), move |callback| {
2888 (callback)(
2889 &KeystrokeEvent {
2890 keystroke: keystroke.clone(),
2891 input_preference,
2892 action: None,
2893 context_stack: context_stack.clone(),
2894 },
2895 self,
2896 cx,
2897 )
2898 });
2899 }
2900
2901 pub fn defer(&self, cx: &mut App, f: impl FnOnce(&mut Window, &mut App) + 'static) {
2904 let handle = self.core.handle;
2905 cx.defer(move |cx| {
2906 handle.update(cx, |_, window, cx| f(window, cx)).ok();
2907 });
2908 }
2909
2910 pub fn observe<T: 'static>(
2914 &mut self,
2915 observed: &Entity<T>,
2916 cx: &mut App,
2917 mut on_notify: impl FnMut(Entity<T>, &mut Window, &mut App) + 'static,
2918 ) -> Subscription {
2919 let entity_id = observed.entity_id();
2920 let observed = observed.downgrade();
2921 let window_handle = self.core.handle;
2922 cx.new_observer(
2923 entity_id,
2924 Box::new(move |cx| {
2925 window_handle
2926 .update(cx, |_, window, cx| {
2927 if let Some(handle) = observed.upgrade() {
2928 on_notify(handle, window, cx);
2929 true
2930 } else {
2931 false
2932 }
2933 })
2934 .unwrap_or(false)
2935 }),
2936 )
2937 }
2938
2939 pub fn subscribe<Emitter, Evt>(
2943 &mut self,
2944 entity: &Entity<Emitter>,
2945 cx: &mut App,
2946 mut on_event: impl FnMut(Entity<Emitter>, &Evt, &mut Window, &mut App) + 'static,
2947 ) -> Subscription
2948 where
2949 Emitter: EventEmitter<Evt>,
2950 Evt: 'static,
2951 {
2952 let entity_id = entity.entity_id();
2953 let handle = entity.downgrade();
2954 let window_handle = self.core.handle;
2955 cx.new_subscription(
2956 entity_id,
2957 (
2958 TypeId::of::<Evt>(),
2959 Box::new(move |event, cx| {
2960 window_handle
2961 .update(cx, |_, window, cx| {
2962 if let Some(entity) = handle.upgrade() {
2963 let event = event.downcast_ref().expect("invalid event type");
2964 on_event(entity, event, window, cx);
2965 true
2966 } else {
2967 false
2968 }
2969 })
2970 .unwrap_or(false)
2971 }),
2972 ),
2973 )
2974 }
2975
2976 pub fn observe_release<T>(
2978 &self,
2979 entity: &Entity<T>,
2980 cx: &mut App,
2981 mut on_release: impl FnOnce(&mut T, &mut Window, &mut App) + 'static,
2982 ) -> Subscription
2983 where
2984 T: 'static,
2985 {
2986 let entity_id = entity.entity_id();
2987 let window_handle = self.core.handle;
2988 let (subscription, activate) = cx.release_listeners.insert(
2989 entity_id,
2990 Box::new(move |entity, cx| {
2991 let entity = entity.downcast_mut().expect("invalid entity type");
2992 let _ = window_handle.update(cx, |_, window, cx| on_release(entity, window, cx));
2993 }),
2994 );
2995 activate();
2996 subscription
2997 }
2998
2999 pub fn to_async(&self, cx: &App) -> AsyncWindowContext {
3002 AsyncWindowContext::new_context(cx.to_async(), self.core.handle)
3003 }
3004
3005 pub fn on_next_frame(&self, callback: impl FnOnce(&mut Window, &mut App) + 'static) {
3007 RefCell::borrow_mut(&self.core.next_frame_callbacks).push(Box::new(callback));
3008 self.core.platform_window.schedule_frame();
3009 self.core.invalidator.wake_platform();
3012 }
3013
3014 pub fn request_animation_frame(&self) {
3027 let entity = self.current_view();
3028 self.on_next_frame(move |_, cx| cx.notify(entity));
3029 }
3030
3031 #[cfg(any(test, feature = "test-support"))]
3036 pub fn simulate_next_frame(&mut self, cx: &mut App) -> usize {
3037 let callbacks = self.core.next_frame_callbacks.take();
3038 let count = callbacks.len();
3039 for callback in callbacks {
3040 callback(self, cx);
3041 }
3042 count
3043 }
3044
3045 #[track_caller]
3049 pub fn spawn<AsyncFn, R>(&self, cx: &App, f: AsyncFn) -> Task<R>
3050 where
3051 R: 'static,
3052 AsyncFn: AsyncFnOnce(&mut AsyncWindowContext) -> R + 'static,
3053 {
3054 let handle = self.core.handle;
3055 cx.spawn(async move |app| {
3056 let mut async_window_cx = AsyncWindowContext::new_context(app.clone(), handle);
3057 f(&mut async_window_cx).await
3058 })
3059 }
3060
3061 #[track_caller]
3065 pub fn spawn_with_priority<AsyncFn, R>(
3066 &self,
3067 priority: Priority,
3068 cx: &App,
3069 f: AsyncFn,
3070 ) -> Task<R>
3071 where
3072 R: 'static,
3073 AsyncFn: AsyncFnOnce(&mut AsyncWindowContext) -> R + 'static,
3074 {
3075 let handle = self.core.handle;
3076 cx.spawn_with_priority(priority, async move |app| {
3077 let mut async_window_cx = AsyncWindowContext::new_context(app.clone(), handle);
3078 f(&mut async_window_cx).await
3079 })
3080 }
3081
3082 fn sync_metrics(&self) {
3088 self.core.metrics.store(Arc::new(WindowMetrics {
3089 bounds: self.core.platform_window.bounds(),
3090 viewport: self.core.platform_window.visual_viewport_bounds(),
3091 content_size: self.core.viewport_size,
3092 scale_factor: self.core.scale_factor,
3093 display_id: self.core.display_id,
3094 is_active: self.core.active.get(),
3095 is_fullscreen: self.core.platform_window.is_fullscreen(),
3096 }));
3097 }
3098
3099 pub fn bounds_changed(&mut self, cx: &mut App) {
3105 self.core.scale_factor = self.core.platform_window.scale_factor();
3106 self.core.viewport_size = self.core.platform_window.content_size();
3107 self.core.display_id = self
3108 .core
3109 .platform_window
3110 .display()
3111 .map(|display| display.id());
3112 self.core.mouse_position = self.core.platform_window.mouse_position();
3113
3114 self.sync_metrics();
3115 self.refresh();
3116
3117 self.core
3118 .bounds_observers
3119 .clone()
3120 .retain(&(), |callback| callback(self, cx));
3121 }
3122
3123 pub fn bounds(&self) -> Bounds<Pixels> {
3125 self.core.platform_window.bounds()
3126 }
3127
3128 #[cfg(any(test, feature = "test-support"))]
3132 pub fn render_to_image(&mut self) -> anyhow::Result<image::RgbaImage> {
3133 let size = self.bounds().size.to_device_pixels(self.scale_factor());
3134 let scene = &self.frame_state.rendered_frame.scene;
3135 let mut result = None;
3136 self.core.platform_window.with_renderer(&mut |renderer| {
3137 result = Some(renderer.render_scene_to_image(scene, size));
3138 });
3139 let pixels = result
3140 .unwrap_or_else(|| anyhow::bail!("platform window does not support image capture"))?;
3141 let (width, height) = (pixels.width(), pixels.height());
3142 image::RgbaImage::from_raw(width, height, pixels.into_data()).ok_or_else(|| {
3143 anyhow::anyhow!(
3144 "the renderer returned a {width}x{height} pixel buffer of the wrong length"
3145 )
3146 })
3147 }
3148
3149 #[cfg(any(test, feature = "test-support"))]
3154 pub fn painted_quads(&self) -> Vec<Quad> {
3155 self.frame_state.rendered_frame.scene.quads.clone()
3156 }
3157
3158 #[cfg(any(test, feature = "test-support"))]
3160 pub fn painted_underlines(&self) -> Vec<Underline> {
3161 self.frame_state.rendered_frame.scene.underlines.clone()
3162 }
3163
3164 #[cfg(any(test, feature = "test-support"))]
3168 pub fn painted_surfaces(&self) -> Vec<PaintSurface> {
3169 self.frame_state.rendered_frame.scene.surfaces.clone()
3170 }
3171
3172 #[cfg(any(test, feature = "test-support"))]
3177 pub fn painted_imported_textures(&self) -> Vec<CustomRenderPrimitive> {
3178 self.frame_state.rendered_frame.scene.custom.clone()
3179 }
3180
3181 pub fn resize(&mut self, size: Size<Pixels>) {
3183 self.core.platform_window.resize(size);
3184 }
3185
3186 pub fn is_fullscreen(&self) -> bool {
3188 self.core.platform_window.is_fullscreen()
3189 }
3190
3191 pub fn is_simple_fullscreen(&self) -> bool {
3195 self.core.platform_window.is_simple_fullscreen()
3196 }
3197
3198 pub(crate) fn appearance_changed(&mut self, cx: &mut App) {
3199 self.core.appearance = self.core.platform_window.appearance();
3200
3201 self.core
3202 .appearance_observers
3203 .clone()
3204 .retain(&(), |callback| callback(self, cx));
3205 }
3206
3207 pub(crate) fn button_layout_changed(&mut self, cx: &mut App) {
3208 self.core
3209 .button_layout_observers
3210 .clone()
3211 .retain(&(), |callback| callback(self, cx));
3212 }
3213
3214 pub fn appearance(&self) -> WindowAppearance {
3216 self.core.appearance
3217 }
3218
3219 pub fn viewport_size(&self) -> Size<Pixels> {
3221 self.core.viewport_size
3222 }
3223
3224 pub fn visual_viewport_bounds(&self) -> Bounds<Pixels> {
3230 self.core.platform_window.visual_viewport_bounds()
3231 }
3232
3233 pub fn fully_visible_bounds(&self) -> Bounds<Pixels> {
3238 let insets = self.core.platform_window.insets().effective();
3239 let viewport = self.viewport_size();
3240 let left = insets.left.max(Pixels::ZERO).min(viewport.width);
3241 let top = insets.top.max(Pixels::ZERO).min(viewport.height);
3242 let right = (viewport.width - insets.right.max(Pixels::ZERO)).max(left);
3243 let bottom = (viewport.height - insets.bottom.max(Pixels::ZERO)).max(top);
3244 let safe_bounds = Bounds::from_corners(point(left, top), point(right, bottom));
3245 let mut visible = safe_bounds.intersect(&self.visual_viewport_bounds());
3246 visible.size.width = visible.size.width.max(Pixels::ZERO);
3247 visible.size.height = visible.size.height.max(Pixels::ZERO);
3248 visible
3249 }
3250
3251 pub fn request_virtual_keyboard(&self) {
3256 self.core.platform_window.show_soft_keyboard();
3257 }
3258
3259 pub fn dismiss_virtual_keyboard(&self) {
3261 self.core.platform_window.hide_soft_keyboard();
3262 }
3263
3264 pub fn is_window_active(&self) -> bool {
3266 self.core.active.get()
3267 }
3268
3269 pub fn is_window_hovered(&self) -> bool {
3273 if cfg!(any(
3274 target_os = "windows",
3275 target_os = "linux",
3276 target_os = "freebsd"
3277 )) {
3278 self.core.hovered.get()
3279 } else {
3280 self.is_window_active()
3281 }
3282 }
3283
3284 pub fn zoom_window(&self) {
3286 self.core.platform_window.zoom();
3287 }
3288
3289 pub fn show_window_menu(&self, position: Point<Pixels>) {
3291 self.core.platform_window.show_window_menu(position)
3292 }
3293
3294 pub fn start_window_move(&self) {
3299 self.core.platform_window.start_window_move()
3300 }
3301
3302 pub fn set_client_inset(&mut self, inset: Pixels) {
3304 self.core.client_inset = Some(inset);
3305 self.core.platform_window.set_client_inset(inset);
3306 }
3307
3308 pub fn client_inset(&self) -> Option<Pixels> {
3310 self.core.client_inset
3311 }
3312
3313 pub fn window_decorations(&self) -> Decorations {
3315 self.core.platform_window.window_decorations()
3316 }
3317
3318 pub fn is_resizable(&self) -> bool {
3320 self.core.is_resizable
3321 }
3322
3323 pub fn is_minimizable(&self) -> bool {
3325 self.core.is_minimizable
3326 }
3327
3328 pub fn window_controls(&self) -> WindowControls {
3330 self.core.platform_window.window_controls()
3331 }
3332
3333 pub fn set_window_title(&mut self, title: &str) {
3335 self.core.platform_window.set_title(title);
3336 self.core.a11y.set_window_title(title.to_string());
3337 }
3338
3339 #[cfg(target_os = "macos")]
3341 pub fn set_traffic_light_position(&self, position: Point<Pixels>) {
3342 self.core
3343 .platform_window
3344 .set_traffic_light_position(position);
3345 }
3346
3347 pub fn set_app_id(&mut self, app_id: &str) {
3349 self.core.platform_window.set_app_id(app_id);
3350 }
3351
3352 pub fn set_background_appearance(&self, background_appearance: WindowBackgroundAppearance) {
3354 self.core
3355 .platform_window
3356 .set_background_appearance(background_appearance);
3357 }
3358
3359 pub fn set_window_edited(&mut self, edited: bool) {
3361 self.core.platform_window.set_edited(edited);
3362 }
3363
3364 pub fn set_document_path(&self, path: Option<&std::path::Path>) {
3367 self.core.platform_window.set_document_path(path);
3368 }
3369
3370 pub fn display(&self, cx: &App) -> Option<Rc<dyn PlatformDisplay>> {
3372 cx.platform
3373 .displays()
3374 .into_iter()
3375 .find(|display| Some(display.id()) == self.core.display_id)
3376 }
3377
3378 pub fn show_character_palette(&self) {
3380 self.core.platform_window.show_character_palette();
3381 }
3382
3383 pub fn scale_factor(&self) -> f32 {
3387 self.core.scale_factor
3388 }
3389
3390 #[cfg(any(test, feature = "test-support"))]
3392 pub fn set_scale_factor(&mut self, scale_factor: f32) {
3393 self.core.scale_factor = scale_factor;
3394 self.sync_metrics();
3395 self.refresh();
3396 }
3397
3398 pub fn rem_size(&self) -> Pixels {
3401 self.frame_state
3402 .rem_size_override_stack
3403 .last()
3404 .copied()
3405 .unwrap_or(self.core.rem_size)
3406 }
3407
3408 pub fn set_rem_size(&mut self, rem_size: impl Into<Pixels>) {
3411 self.core.rem_size = rem_size.into();
3412 }
3413
3414 pub fn with_global_id<R>(
3417 &mut self,
3418 element_id: ElementId,
3419 f: impl FnOnce(&GlobalElementId, &mut Self) -> R,
3420 ) -> R {
3421 self.with_id(element_id, |this| {
3422 let global_id = this.frame_state.element_id_stack.global_id();
3423
3424 f(&global_id, this)
3425 })
3426 }
3427
3428 #[inline]
3430 pub fn with_id<R>(
3431 &mut self,
3432 element_id: impl Into<ElementId>,
3433 f: impl FnOnce(&mut Self) -> R,
3434 ) -> R {
3435 self.frame_state.element_id_stack.push(element_id.into());
3436 let result = f(self);
3437 self.frame_state.element_id_stack.pop();
3438 result
3439 }
3440
3441 #[inline]
3447 pub fn with_rem_size<F, R>(&mut self, rem_size: Option<impl Into<Pixels>>, f: F) -> R
3448 where
3449 F: FnOnce(&mut Self) -> R,
3450 {
3451 self.core.invalidator.debug_assert_paint_or_prepaint();
3452
3453 if let Some(rem_size) = rem_size {
3454 self.frame_state
3455 .rem_size_override_stack
3456 .push(rem_size.into());
3457 let result = f(self);
3458 self.frame_state.rem_size_override_stack.pop();
3459 result
3460 } else {
3461 f(self)
3462 }
3463 }
3464
3465 pub fn line_height(&self) -> Pixels {
3467 self.text_style().line_height_in_pixels(self.rem_size())
3468 }
3469
3470 #[inline]
3472 pub fn pixel_snap(&self, value: Pixels) -> Pixels {
3473 px(round_to_device_pixel(value.0, self.scale_factor()) / self.scale_factor())
3474 }
3475
3476 #[inline]
3478 pub fn pixel_snap_f64(&self, value: f64) -> f64 {
3479 let scale_factor = f64::from(self.scale_factor());
3480 round_half_toward_zero_f64(value * scale_factor) / scale_factor
3481 }
3482
3483 #[inline]
3485 pub fn pixel_snap_bounds(&self, bounds: Bounds<Pixels>) -> Bounds<Pixels> {
3486 bounds.map(|c| self.pixel_snap(c))
3487 }
3488
3489 #[inline]
3491 pub fn pixel_snap_point(&self, position: Point<Pixels>) -> Point<Pixels> {
3492 position.map(|c| self.pixel_snap(c))
3493 }
3494
3495 pub fn underline_bounds(
3497 &self,
3498 origin: Point<Pixels>,
3499 width: Pixels,
3500 style: &UnderlineStyle,
3501 ) -> Bounds<ScaledPixels> {
3502 let scale_factor = self.scale_factor();
3503 let thickness = self.snap_stroke(style.thickness);
3504 let height = if style.wavy {
3505 ScaledPixels(thickness.0 * 3.)
3506 } else {
3507 thickness
3508 };
3509 Bounds {
3510 origin: origin.map(|c| ScaledPixels(round_to_device_pixel(c.0, scale_factor))),
3511 size: size(self.snap_stroke(width), height),
3512 }
3513 }
3514
3515 pub fn paint_underline_with_exclusions(
3517 &mut self,
3518 origin: Point<Pixels>,
3519 width: Pixels,
3520 style: &UnderlineStyle,
3521 exclusions: &[Range<ScaledPixels>],
3522 ) {
3523 self.core.invalidator.debug_assert_paint();
3524 let underline = self.underline(origin, width, style);
3525 if exclusions.is_empty() {
3526 self.frame_state
3527 .next_frame
3528 .scene
3529 .insert_primitive(underline);
3530 return;
3531 }
3532
3533 let bounds = underline.bounds.intersect(&underline.content_mask.bounds);
3534 if bounds.is_empty() {
3535 return;
3536 }
3537
3538 let mut exclusions = exclusions
3539 .iter()
3540 .filter_map(|span| {
3541 let start = span.start.max(bounds.left());
3542 let end = span.end.min(bounds.right());
3543 (start < end).then_some(start..end)
3544 })
3545 .collect::<SmallVec<[_; 4]>>();
3546 if exclusions.is_empty() {
3547 self.frame_state
3548 .next_frame
3549 .scene
3550 .insert_primitive(underline);
3551 return;
3552 }
3553 exclusions.sort_unstable_by_key(|span| span.start);
3554
3555 let mut paint_span = |start, end| {
3556 self.frame_state
3557 .next_frame
3558 .scene
3559 .insert_primitive(Underline {
3560 content_mask: ContentMask {
3561 bounds: Bounds::from_corners(
3562 point(start, bounds.top()),
3563 point(end, bounds.bottom()),
3564 ),
3565 },
3566 ..underline
3567 });
3568 };
3569 let mut start = bounds.left();
3570 for exclusion in exclusions {
3571 if start < exclusion.start {
3572 paint_span(start, exclusion.start);
3573 }
3574 start = start.max(exclusion.end);
3575 }
3576 if start < bounds.right() {
3577 paint_span(start, bounds.right());
3578 }
3579 }
3580
3581 fn underline(&self, origin: Point<Pixels>, width: Pixels, style: &UnderlineStyle) -> Underline {
3582 Underline {
3583 order: 0,
3584 pad: 0,
3585 bounds: self.underline_bounds(origin, width, style),
3586 content_mask: self.snapped_content_mask(),
3587 color: style
3588 .color
3589 .unwrap_or_default()
3590 .opacity(self.element_opacity()),
3591 thickness: self.snap_stroke(style.thickness),
3592 wavy: style.wavy.into(),
3593 }
3594 }
3595
3596 #[inline]
3597 pub(crate) fn snap_bounds(&self, bounds: Bounds<Pixels>) -> Bounds<ScaledPixels> {
3598 let scale_factor = self.scale_factor();
3599 let left = round_to_device_pixel(bounds.left().0, scale_factor);
3600 let top = round_to_device_pixel(bounds.top().0, scale_factor);
3601 let right = round_to_device_pixel(bounds.right().0, scale_factor).max(left);
3602 let bottom = round_to_device_pixel(bounds.bottom().0, scale_factor).max(top);
3603 Bounds::from_corners(
3604 point(ScaledPixels(left), ScaledPixels(top)),
3605 point(ScaledPixels(right), ScaledPixels(bottom)),
3606 )
3607 }
3608
3609 #[inline]
3611 fn snap_stroke(&self, value: Pixels) -> ScaledPixels {
3612 ScaledPixels(round_stroke_to_device_pixel(value.0, self.scale_factor()))
3613 }
3614
3615 #[inline]
3616 fn snap_border_widths(&self, edges: Edges<Pixels>) -> Edges<ScaledPixels> {
3617 edges.map(|e| self.snap_stroke(*e))
3618 }
3619
3620 #[inline]
3622 fn cover_bounds(&self, bounds: Bounds<Pixels>) -> Bounds<ScaledPixels> {
3623 let scale_factor = self.scale_factor();
3624 let left = floor_to_device_pixel(bounds.left().0, scale_factor);
3625 let top = floor_to_device_pixel(bounds.top().0, scale_factor);
3626 let right = ceil_to_device_pixel(bounds.right().0, scale_factor).max(left);
3627 let bottom = ceil_to_device_pixel(bounds.bottom().0, scale_factor).max(top);
3628 Bounds::from_corners(
3629 point(ScaledPixels(left), ScaledPixels(top)),
3630 point(ScaledPixels(right), ScaledPixels(bottom)),
3631 )
3632 }
3633
3634 #[inline]
3635 pub(crate) fn snapped_content_mask(&self) -> ContentMask<ScaledPixels> {
3636 ContentMask {
3637 bounds: self.cover_bounds(self.content_mask().bounds),
3638 }
3639 }
3640
3641 pub fn prevent_default(&mut self) {
3644 self.core.default_prevented = true;
3645 }
3646
3647 pub fn default_prevented(&self) -> bool {
3649 self.core.default_prevented
3650 }
3651
3652 pub fn is_action_available(&self, action: &dyn Action, cx: &App) -> bool {
3654 let node_id =
3655 self.focus_node_id_in_rendered_frame(self.focused(cx).map(|handle| handle.id));
3656 self.frame_state
3657 .rendered_frame
3658 .dispatch_tree
3659 .is_action_available(action, node_id)
3660 }
3661
3662 pub fn is_action_available_in(&self, action: &dyn Action, focus_handle: &FocusHandle) -> bool {
3664 let node_id = self.focus_node_id_in_rendered_frame(Some(focus_handle.id));
3665 self.frame_state
3666 .rendered_frame
3667 .dispatch_tree
3668 .is_action_available(action, node_id)
3669 }
3670
3671 pub fn mouse_position(&self) -> Point<Pixels> {
3673 self.core.mouse_position
3674 }
3675
3676 pub fn capture_pointer(&mut self, hitbox_id: HitboxId) {
3683 self.core.captured_hitbox = Some(hitbox_id);
3684 }
3685
3686 pub fn release_pointer(&mut self) {
3688 self.core.captured_hitbox = None;
3689 }
3690
3691 pub fn captured_hitbox(&self) -> Option<HitboxId> {
3693 self.core.captured_hitbox
3694 }
3695
3696 pub fn capture_long_press<T: 'static>(&mut self, entity: &Entity<T>) {
3702 self.core.long_press_capture = Some(entity.entity_id());
3703 }
3704
3705 pub fn has_long_press_capture<T: 'static>(&self, entity: &Entity<T>) -> bool {
3707 self.core.long_press_capture == Some(entity.entity_id())
3708 }
3709
3710 pub fn modifiers(&self) -> Modifiers {
3712 self.core.modifiers
3713 }
3714
3715 pub fn last_input_was_keyboard(&self) -> bool {
3718 self.core.last_input_modality == InputModality::Keyboard
3719 }
3720
3721 pub(crate) fn last_input_was_touch(&self) -> bool {
3722 self.core.last_input_modality == InputModality::Touch
3723 }
3724
3725 pub fn capslock(&self) -> Capslock {
3727 self.core.capslock
3728 }
3729
3730 #[doc(hidden)]
3737 #[profiling::function]
3738 pub fn draw(&mut self, cx: &mut App) -> ArenaClearNeeded {
3739 let pipeline = self.core.frame_pipeline.clone();
3740 pipeline.borrow_mut().draw(self, cx)
3741 }
3742
3743 pub fn begin_frame(&mut self, cx: &mut App) {
3748 #[cfg(debug_assertions)]
3749 self.frame_state.frame_phase.enter(
3750 &[FramePhase::Idle, FramePhase::Completed],
3751 FramePhase::Begun,
3752 "begin_frame",
3753 );
3754 if self.core.platform_window.prepare_frame() {
3755 self.refresh();
3756 }
3757 self.sync_metrics();
3758 self.invalidate_entities();
3759 cx.entities.clear_accessed();
3760 debug_assert!(self.frame_state.rendered_entity_stack.is_empty());
3761 self.core.invalidator.set_dirty(false);
3762 self.frame_state.requested_autoscroll = None;
3763 }
3764
3765 fn restore_input_handler(&mut self) {
3770 if let Some(input_handler) = self.core.platform_window.take_input_handler() {
3771 if let Some(slot) = self
3772 .frame_state
3773 .rendered_frame
3774 .input_handlers
3775 .iter_mut()
3776 .rev()
3777 .find(|h| h.is_none())
3778 {
3779 *slot = Some(input_handler);
3780 } else {
3781 self.frame_state
3782 .rendered_frame
3783 .input_handlers
3784 .push(Some(input_handler));
3785 }
3786 }
3787 }
3788
3789 pub fn finish_frame(&mut self, cx: &mut App) {
3799 #[cfg(debug_assertions)]
3800 self.frame_state.frame_phase.enter(
3801 &[FramePhase::Begun, FramePhase::Painted],
3802 FramePhase::Finished,
3803 "finish_frame",
3804 );
3805 self.frame_state.dirty_views.clear();
3806 self.frame_state.next_frame.window_active = self.core.active.get();
3807
3808 let focused_text_input_active = if let Some(mut input_handler) = self
3813 .frame_state
3814 .next_frame
3815 .input_handlers
3816 .iter_mut()
3817 .rev()
3818 .find_map(|h| h.take())
3819 {
3820 let accepts_text_input = input_handler.accepts_text_input(self, cx);
3821 self.core.platform_window.set_input_handler(input_handler);
3822 accepts_text_input
3823 } else {
3824 false
3825 };
3826 self.apply_text_input_configuration(cx);
3827 if focused_text_input_active != self.core.focused_text_input_active {
3828 self.core.focused_text_input_active = focused_text_input_active;
3829 self.core
3830 .platform_window
3831 .text_input_state_changed(if focused_text_input_active {
3832 TextInputStateChange::FocusGained
3833 } else {
3834 TextInputStateChange::FocusLost
3835 });
3836 }
3837
3838 self.frame_state.layout_session.clear();
3839 self.text_system().finish_frame();
3840 self.frame_state
3841 .next_frame
3842 .finish(&mut self.frame_state.rendered_frame);
3843 }
3844
3845 pub fn complete_frame(&mut self, cx: &mut App) -> Option<FocusId> {
3853 #[cfg(debug_assertions)]
3854 self.frame_state.frame_phase.enter(
3855 &[FramePhase::Finished],
3856 FramePhase::Completed,
3857 "complete_frame",
3858 );
3859 self.core.invalidator.set_phase(DrawPhase::Focus);
3860 let previous_focus_path = self.frame_state.rendered_frame.focus_path();
3861 let previous_window_active = self.frame_state.rendered_frame.window_active;
3862 mem::swap(
3863 &mut self.frame_state.rendered_frame,
3864 &mut self.frame_state.next_frame,
3865 );
3866 self.frame_state.next_frame.clear();
3867 let current_focus_path = self.frame_state.rendered_frame.focus_path();
3868 let current_window_active = self.frame_state.rendered_frame.window_active;
3869 let mut focus_before_listeners = self.core.focus;
3870
3871 if previous_focus_path != current_focus_path
3872 || previous_window_active != current_window_active
3873 {
3874 if !previous_focus_path.is_empty() && current_focus_path.is_empty() {
3875 self.frame_state.focus_lost_path = previous_focus_path.clone();
3876 self.core
3877 .focus_lost_listeners
3878 .clone()
3879 .retain(&(), |listener| listener(self, cx));
3880 self.frame_state.focus_lost_path = SmallVec::new();
3881 focus_before_listeners = self.core.focus;
3886 }
3887
3888 let event = WindowFocusEvent {
3889 previous_focus_path: if previous_window_active {
3890 previous_focus_path
3891 } else {
3892 Default::default()
3893 },
3894 current_focus_path: if current_window_active {
3895 current_focus_path
3896 } else {
3897 Default::default()
3898 },
3899 };
3900 self.core
3901 .focus_listeners
3902 .clone()
3903 .retain(&(), |listener| listener(&event, self, cx));
3904 }
3905
3906 focus_before_listeners
3907 }
3908
3909 pub fn end_frame(&mut self, cx: &mut App, focus_before_listeners: Option<FocusId>) {
3913 #[cfg(debug_assertions)]
3914 self.frame_state
3915 .frame_phase
3916 .enter(&[FramePhase::Completed], FramePhase::Idle, "end_frame");
3917 debug_assert!(self.frame_state.rendered_entity_stack.is_empty());
3918 self.record_entities_accessed(cx);
3919 self.reset_cursor_style(cx);
3920 self.core.refreshing = false;
3921 self.core.invalidator.set_phase(DrawPhase::None);
3922 if self.core.focus != focus_before_listeners {
3927 self.refresh();
3928 }
3929 self.core.needs_present.set(true);
3930 }
3931 fn record_entities_accessed(&mut self, cx: &mut App) {
3932 let mut entities_ref = cx.entities.accessed_entities.get_mut();
3933 let mut entities = mem::take(entities_ref.deref_mut());
3934 let handle = self.core.handle;
3935 cx.record_entities_accessed(
3936 handle,
3937 self.core.invalidator.clone(),
3939 &entities,
3940 );
3941 let mut entities_ref = cx.entities.accessed_entities.get_mut();
3942 mem::swap(&mut entities, entities_ref.deref_mut());
3943 }
3944
3945 fn invalidate_entities(&mut self) {
3946 let mut views = self.core.invalidator.take_views();
3947 for entity in views.drain() {
3948 self.mark_view_dirty(entity);
3949 }
3950 self.core.invalidator.replace_views(views);
3951 }
3952
3953 #[doc(hidden)]
3961 #[profiling::function]
3962 pub fn present(&mut self) {
3963 #[cfg(feature = "profiler")]
3964 let _foreground_turn = profiler::journal::foreground_turn();
3965 #[cfg(feature = "profiler")]
3966 let present_start = Instant::now();
3967 self.core
3968 .platform_window
3969 .present(&mut |renderer| renderer.draw(&self.frame_state.rendered_frame.scene));
3970 #[cfg(feature = "profiler")]
3971 self.core.window_profiler.record_present(
3972 present_start,
3973 Instant::now(),
3974 self.core.active.get(),
3975 !self.core.next_frame_callbacks.borrow().is_empty(),
3976 );
3977 self.core.needs_present.set(false);
3978 profiling::finish_frame!();
3979 }
3980
3981 #[cfg(all(test, feature = "profiler"))]
3983 pub(crate) fn present_if_needed(&mut self) {
3984 if self.core.needs_present.get() {
3985 self.present();
3986 }
3987 }
3988
3989 #[cfg(feature = "profiler")]
3991 pub fn input_latency_snapshot(&self) -> profiler::InputLatencySnapshot {
3992 self.core.window_profiler.input_latency_snapshot()
3993 }
3994
3995 #[cfg(feature = "profiler")]
3997 pub fn frame_duration_snapshot(&self) -> profiler::FrameDurationSnapshot {
3998 self.core.window_profiler.frame_duration_snapshot()
3999 }
4000
4001 #[cfg(feature = "profiler")]
4003 pub fn debug_frame_overlay_mode(&self) -> DebugFrameOverlayMode {
4004 self.core.debug_frame_overlay.mode()
4005 }
4006
4007 #[cfg(feature = "profiler")]
4009 pub fn set_debug_frame_overlay_mode(&mut self, mode: DebugFrameOverlayMode) {
4010 self.core.debug_frame_overlay.set_mode(mode);
4011 self.refresh();
4012 }
4013
4014 #[cfg(feature = "profiler")]
4017 pub fn cycle_debug_frame_overlay_mode(&mut self) {
4018 self.set_debug_frame_overlay_mode(self.core.debug_frame_overlay.mode().next());
4019 }
4020
4021 #[cfg(feature = "profiler")]
4024 pub fn reset_debug_frame_overlay_stats(&mut self) {
4025 self.core.debug_frame_overlay.reset_stats();
4026 self.refresh();
4027 }
4028
4029 pub fn evaluate_roots(&mut self, cx: &mut App) -> PreparedRoots {
4035 #[cfg(debug_assertions)]
4036 self.frame_state.frame_phase.enter(
4037 &[FramePhase::Begun],
4038 FramePhase::Evaluated,
4039 "evaluate_roots",
4040 );
4041 let root = self.core.root.as_ref().unwrap().clone().into_any_element();
4042
4043 let mut prompt = None;
4046 let mut drag = None;
4047 if let Some(handle) = self.core.prompt.take() {
4048 prompt = Some(handle.view.any_view().into_any_element());
4049 self.core.prompt = Some(handle);
4050 } else if let Some(active_drag) = cx.active_drag.take() {
4051 let origin = self.mouse_position() - active_drag.cursor_offset;
4052 drag = Some((active_drag.view.clone().into_any_element(), origin));
4053 cx.active_drag = Some(active_drag);
4054 }
4055
4056 PreparedRoots {
4057 root,
4058 prompt,
4059 tooltip: None,
4060 drag,
4061 inspector: None,
4062 }
4063 }
4064
4065 pub fn layout_roots(&mut self, roots: &mut PreparedRoots, cx: &mut App) {
4068 #[cfg(debug_assertions)]
4069 self.frame_state.frame_phase.enter(
4070 &[FramePhase::Evaluated],
4071 FramePhase::LaidOut,
4072 "layout_roots",
4073 );
4074 self.core.invalidator.set_phase(DrawPhase::Prepaint);
4075 self.frame_state.tooltip_bounds.take();
4076
4077 self.core.a11y.sync_active_flag();
4078 if self.core.a11y.is_active() {
4079 self.core.a11y.begin_frame();
4080 }
4081
4082 #[cfg(any(feature = "inspector", debug_assertions))]
4083 let inspector_width: Pixels = rems(30.0).to_pixels(self.rem_size());
4084 let root_size = {
4085 #[cfg(any(feature = "inspector", debug_assertions))]
4086 {
4087 if self.core.inspector.is_some() {
4088 let mut size = self.core.viewport_size;
4089 size.width = (size.width - inspector_width).max(px(0.0));
4090 size
4091 } else {
4092 self.core.viewport_size
4093 }
4094 }
4095 #[cfg(not(any(feature = "inspector", debug_assertions)))]
4096 {
4097 self.core.viewport_size
4098 }
4099 };
4100
4101 let scale_factor = self.scale_factor();
4105 let root_layout_id = roots.root.request_layout(self, cx);
4106 self.frame_state.layout_session.stretch_auto_size_to_fill(
4107 root_layout_id,
4108 root_size,
4109 scale_factor,
4110 );
4111 roots
4112 .root
4113 .prepaint_as_root(Point::default(), root_size.into(), self, cx);
4114
4115 #[cfg(any(feature = "inspector", debug_assertions))]
4116 {
4117 roots.inspector = self.prepaint_inspector(inspector_width, cx);
4118 }
4119
4120 self.prepaint_deferred_draws(cx);
4121
4122 if let Some(prompt) = roots.prompt.as_mut() {
4123 let prompt_layout_id = prompt.request_layout(self, cx);
4124 self.frame_state.layout_session.stretch_auto_size_to_fill(
4125 prompt_layout_id,
4126 root_size,
4127 scale_factor,
4128 );
4129 prompt.prepaint_as_root(Point::default(), root_size.into(), self, cx);
4130 } else if let Some((drag, origin)) = roots.drag.as_mut() {
4131 drag.prepaint_as_root(*origin, AvailableSpace::min_size(), self, cx);
4132 } else {
4133 roots.tooltip = self.prepaint_tooltip(cx);
4134 }
4135
4136 self.core.mouse_hit_test = self
4137 .frame_state
4138 .next_frame
4139 .hit_test(self.core.mouse_position);
4140 }
4141
4142 pub fn paint_roots(&mut self, mut roots: PreparedRoots, cx: &mut App) {
4144 #[cfg(debug_assertions)]
4145 self.frame_state.frame_phase.enter(
4146 &[FramePhase::LaidOut],
4147 FramePhase::Painted,
4148 "paint_roots",
4149 );
4150 self.core.invalidator.set_phase(DrawPhase::Paint);
4151 roots.root.paint(self, cx);
4152
4153 #[cfg(any(feature = "inspector", debug_assertions))]
4154 self.paint_inspector(roots.inspector.take(), cx);
4155
4156 self.paint_deferred_draws(cx);
4157
4158 if let Some(mut prompt) = roots.prompt.take() {
4159 prompt.paint(self, cx);
4160 } else if let Some((mut drag, _)) = roots.drag.take() {
4161 drag.paint(self, cx);
4162 } else if let Some(mut tooltip) = roots.tooltip.take() {
4163 tooltip.paint(self, cx);
4164 }
4165
4166 #[cfg(any(feature = "inspector", debug_assertions))]
4167 self.paint_inspector_hitbox(cx);
4168
4169 let a11y_active_start_of_frame = self.core.a11y.is_active();
4171 self.core.a11y.sync_active_flag();
4172 let a11y_active_end_of_frame = self.core.a11y.is_active();
4173
4174 let should_send_a11y_update = a11y_active_start_of_frame && a11y_active_end_of_frame;
4175
4176 if a11y_active_start_of_frame {
4177 let frame_info = crate::window::a11y::debug::FrameDebugInfo {
4180 viewport_size: self.core.viewport_size,
4181 scale_factor: self.core.scale_factor,
4182 tab_stop_count: self.frame_state.next_frame.tab_stops.tab_stop_count(),
4183 };
4184 let tree_update = self.core.a11y.end_frame(frame_info);
4186
4187 if should_send_a11y_update {
4188 log::debug!(
4189 "Sending a11y tree update: {} nodes",
4190 tree_update.nodes.len()
4191 );
4192 self.core.platform_window.a11y_tree_update(tree_update);
4193 }
4194 }
4195 }
4196
4197 pub fn draw_roots(&mut self, cx: &mut App) {
4203 let mut roots = self.evaluate_roots(cx);
4204 self.layout_roots(&mut roots, cx);
4205 self.paint_roots(roots, cx);
4206 }
4207
4208 fn prepaint_tooltip(&mut self, cx: &mut App) -> Option<AnyElement> {
4209 for tooltip_request_index in (0..self.frame_state.next_frame.tooltip_requests.len()).rev() {
4211 let Some(Some(tooltip_request)) = self
4212 .frame_state
4213 .next_frame
4214 .tooltip_requests
4215 .get(tooltip_request_index)
4216 .cloned()
4217 else {
4218 log::error!("Unexpectedly absent TooltipRequest");
4219 continue;
4220 };
4221 let mut element = tooltip_request.tooltip.view.clone().into_any_element();
4222 let mouse_position = tooltip_request.tooltip.mouse_position;
4223 let tooltip_size = element.layout_as_root(AvailableSpace::min_size(), self, cx);
4224
4225 let mut tooltip_bounds =
4226 Bounds::new(mouse_position + point(px(1.), px(1.)), tooltip_size);
4227 let window_bounds = Bounds {
4228 origin: Point::default(),
4229 size: self.viewport_size(),
4230 };
4231
4232 if tooltip_bounds.right() > window_bounds.right() {
4233 let new_x = mouse_position.x - tooltip_bounds.size.width - px(1.);
4234 if new_x >= Pixels::ZERO {
4235 tooltip_bounds.origin.x = new_x;
4236 } else {
4237 tooltip_bounds.origin.x = cmp::max(
4238 Pixels::ZERO,
4239 tooltip_bounds.origin.x - tooltip_bounds.right() - window_bounds.right(),
4240 );
4241 }
4242 }
4243
4244 if tooltip_bounds.bottom() > window_bounds.bottom() {
4245 let new_y = mouse_position.y - tooltip_bounds.size.height - px(1.);
4246 if new_y >= Pixels::ZERO {
4247 tooltip_bounds.origin.y = new_y;
4248 } else {
4249 tooltip_bounds.origin.y = cmp::max(
4250 Pixels::ZERO,
4251 tooltip_bounds.origin.y - tooltip_bounds.bottom() - window_bounds.bottom(),
4252 );
4253 }
4254 }
4255
4256 let is_visible =
4260 (tooltip_request.tooltip.check_visible_and_update)(tooltip_bounds, self, cx);
4261 if !is_visible {
4262 continue;
4263 }
4264
4265 self.with_absolute_element_offset(tooltip_bounds.origin, |window| {
4266 element.prepaint(window, cx)
4267 });
4268
4269 self.frame_state.tooltip_bounds = Some(TooltipBounds {
4270 id: tooltip_request.id,
4271 bounds: tooltip_bounds,
4272 });
4273 return Some(element);
4274 }
4275 None
4276 }
4277
4278 fn prepaint_deferred_draws(&mut self, cx: &mut App) {
4279 assert_eq!(self.frame_state.element_id_stack.len(), 0);
4280
4281 let mut round_start = 0;
4292 let mut depth = 0;
4293 loop {
4294 let round_end = self.frame_state.next_frame.deferred_draws.len();
4295 if round_start == round_end {
4296 break;
4297 }
4298 assert!(depth < 10, "Exceeded maximum (10) deferred depth");
4300 depth += 1;
4301
4302 let mut traversal_order = (round_start..round_end).collect::<SmallVec<[usize; 8]>>();
4304 traversal_order
4305 .sort_by_key(|ix| self.frame_state.next_frame.deferred_draws[*ix].priority);
4306
4307 for deferred_draw_ix in traversal_order {
4308 let (element, parent_node, current_view, rem_size, absolute_offset, prepaint_range) = {
4309 let deferred_draw =
4310 &mut self.frame_state.next_frame.deferred_draws[deferred_draw_ix];
4311 self.frame_state
4312 .element_id_stack
4313 .clone_from(&deferred_draw.element_id_stack);
4314 self.frame_state
4315 .text_style_stack
4316 .clone_from(&deferred_draw.text_style_stack);
4317 (
4318 deferred_draw.element.take(),
4319 deferred_draw.parent_node,
4320 deferred_draw.current_view,
4321 deferred_draw.rem_size,
4322 deferred_draw.absolute_offset,
4323 deferred_draw.prepaint_range.clone(),
4324 )
4325 };
4326 self.frame_state
4327 .next_frame
4328 .dispatch_tree
4329 .set_active_node(parent_node);
4330
4331 let prepaint_start = self.prepaint_index();
4332 if let Some(mut element) = element {
4333 self.with_rendered_view(current_view, |window| {
4334 window.with_rem_size(Some(rem_size), |window| {
4335 window.with_absolute_element_offset(absolute_offset, |window| {
4336 element.prepaint(window, cx);
4337 });
4338 });
4339 });
4340 self.frame_state.next_frame.deferred_draws[deferred_draw_ix].element =
4341 Some(element);
4342 } else {
4343 self.reuse_prepaint(prepaint_range);
4344 }
4345 let prepaint_end = self.prepaint_index();
4346 self.frame_state.next_frame.deferred_draws[deferred_draw_ix].prepaint_range =
4347 prepaint_start..prepaint_end;
4348 }
4349
4350 self.frame_state.element_id_stack.clear();
4351 self.frame_state.text_style_stack.clear();
4352 round_start = round_end;
4353 }
4354 }
4355
4356 fn paint_deferred_draws(&mut self, cx: &mut App) {
4357 assert_eq!(self.frame_state.element_id_stack.len(), 0);
4358
4359 if self.frame_state.next_frame.deferred_draws.len() == 0 {
4362 return;
4363 }
4364
4365 let traversal_order = self.deferred_draw_traversal_order();
4366 let mut deferred_draws = mem::take(&mut self.frame_state.next_frame.deferred_draws);
4367 for deferred_draw_ix in traversal_order {
4368 let mut deferred_draw = &mut deferred_draws[deferred_draw_ix];
4369 self.frame_state
4370 .element_id_stack
4371 .clone_from(&deferred_draw.element_id_stack);
4372 self.frame_state
4373 .next_frame
4374 .dispatch_tree
4375 .set_active_node(deferred_draw.parent_node);
4376
4377 let paint_start = self.paint_index();
4378 let content_mask = deferred_draw.content_mask;
4379 if let Some(element) = deferred_draw.element.as_mut() {
4380 self.with_rendered_view(deferred_draw.current_view, |window| {
4381 window.with_content_mask(content_mask, |window| {
4382 window.with_rem_size(Some(deferred_draw.rem_size), |window| {
4383 element.paint(window, cx);
4384 });
4385 })
4386 })
4387 } else {
4388 self.reuse_paint(deferred_draw.paint_range.clone());
4389 }
4390 let paint_end = self.paint_index();
4391 deferred_draw.paint_range = paint_start..paint_end;
4392 }
4393 self.frame_state.next_frame.deferred_draws = deferred_draws;
4394 self.frame_state.element_id_stack.clear();
4395 }
4396
4397 fn deferred_draw_traversal_order(&mut self) -> SmallVec<[usize; 8]> {
4398 let deferred_count = self.frame_state.next_frame.deferred_draws.len();
4399 let mut sorted_indices = (0..deferred_count).collect::<SmallVec<[_; 8]>>();
4400 sorted_indices.sort_by_key(|ix| self.frame_state.next_frame.deferred_draws[*ix].priority);
4401 sorted_indices
4402 }
4403
4404 pub(crate) fn prepaint_index(&self) -> PrepaintStateIndex {
4405 PrepaintStateIndex {
4406 hitboxes_index: self.frame_state.next_frame.hitboxes.len(),
4407 tooltips_index: self.frame_state.next_frame.tooltip_requests.len(),
4408 deferred_draws_index: self.frame_state.next_frame.deferred_draws.len(),
4409 dispatch_tree_index: self.frame_state.next_frame.dispatch_tree.len(),
4410 accessed_element_states_index: self
4411 .frame_state
4412 .next_frame
4413 .accessed_element_states
4414 .len(),
4415 line_layout_index: self.core.text_system.layout_index(),
4416 }
4417 }
4418
4419 pub(crate) fn reuse_prepaint(&mut self, range: Range<PrepaintStateIndex>) {
4420 self.frame_state.next_frame.hitboxes.extend(
4421 self.frame_state.rendered_frame.hitboxes
4422 [range.start.hitboxes_index..range.end.hitboxes_index]
4423 .iter()
4424 .cloned(),
4425 );
4426 self.frame_state.next_frame.hitbox_filters.extend(
4427 self.frame_state.rendered_frame.hitbox_filters
4428 [range.start.hitboxes_index..range.end.hitboxes_index]
4429 .iter()
4430 .cloned(),
4431 );
4432 self.frame_state.next_frame.tooltip_requests.extend(
4433 self.frame_state.rendered_frame.tooltip_requests
4434 [range.start.tooltips_index..range.end.tooltips_index]
4435 .iter_mut()
4436 .map(|request| request.take()),
4437 );
4438 self.frame_state.next_frame.accessed_element_states.extend(
4439 self.frame_state.rendered_frame.accessed_element_states[range
4440 .start
4441 .accessed_element_states_index
4442 ..range.end.accessed_element_states_index]
4443 .iter()
4444 .map(|(id, type_id)| (id.clone(), *type_id)),
4445 );
4446 self.core
4447 .text_system
4448 .reuse_layouts(range.start.line_layout_index..range.end.line_layout_index);
4449
4450 let reused_subtree = self.frame_state.next_frame.dispatch_tree.reuse_subtree(
4451 range.start.dispatch_tree_index..range.end.dispatch_tree_index,
4452 &mut self.frame_state.rendered_frame.dispatch_tree,
4453 self.core.focus,
4454 );
4455
4456 if reused_subtree.contains_focus() {
4457 self.frame_state.next_frame.focus = self.core.focus;
4458 }
4459
4460 self.frame_state.next_frame.deferred_draws.extend(
4461 self.frame_state.rendered_frame.deferred_draws
4462 [range.start.deferred_draws_index..range.end.deferred_draws_index]
4463 .iter()
4464 .map(|deferred_draw| DeferredDraw {
4465 current_view: deferred_draw.current_view,
4466 parent_node: reused_subtree.refresh_node_id(deferred_draw.parent_node),
4467 element_id_stack: deferred_draw.element_id_stack.clone(),
4468 text_style_stack: deferred_draw.text_style_stack.clone(),
4469 content_mask: deferred_draw.content_mask,
4470 rem_size: deferred_draw.rem_size,
4471 priority: deferred_draw.priority,
4472 element: None,
4473 absolute_offset: deferred_draw.absolute_offset,
4474 prepaint_range: deferred_draw.prepaint_range.clone(),
4475 paint_range: deferred_draw.paint_range.clone(),
4476 }),
4477 );
4478 }
4479
4480 pub(crate) fn paint_index(&self) -> PaintIndex {
4481 PaintIndex {
4482 scene_index: self.frame_state.next_frame.scene.len(),
4483 #[cfg(any(test, feature = "test-support"))]
4484 debug_bounds_index: self.frame_state.next_frame.debug_bounds_records.len(),
4485 mouse_listeners_index: self.frame_state.next_frame.mouse_listeners.len(),
4486 input_handlers_index: self.frame_state.next_frame.input_handlers.len(),
4487 cursor_styles_index: self.frame_state.next_frame.cursor_styles.len(),
4488 accessed_element_states_index: self
4489 .frame_state
4490 .next_frame
4491 .accessed_element_states
4492 .len(),
4493 tab_handle_index: self.frame_state.next_frame.tab_stops.paint_index(),
4494 line_layout_index: self.core.text_system.layout_index(),
4495 }
4496 }
4497
4498 pub(crate) fn reuse_paint(&mut self, range: Range<PaintIndex>) {
4499 #[cfg(any(test, feature = "test-support"))]
4501 for (selector, bounds) in &self.frame_state.rendered_frame.debug_bounds_records
4502 [range.start.debug_bounds_index..range.end.debug_bounds_index]
4503 {
4504 self.frame_state
4505 .next_frame
4506 .record_debug_bounds(selector.clone(), *bounds);
4507 }
4508 self.frame_state.next_frame.cursor_styles.extend(
4509 self.frame_state.rendered_frame.cursor_styles
4510 [range.start.cursor_styles_index..range.end.cursor_styles_index]
4511 .iter()
4512 .cloned(),
4513 );
4514 self.frame_state.next_frame.input_handlers.extend(
4515 self.frame_state.rendered_frame.input_handlers
4516 [range.start.input_handlers_index..range.end.input_handlers_index]
4517 .iter_mut()
4518 .map(|handler| handler.take()),
4519 );
4520 self.frame_state.next_frame.mouse_listeners.extend(
4521 self.frame_state.rendered_frame.mouse_listeners
4522 [range.start.mouse_listeners_index..range.end.mouse_listeners_index]
4523 .iter_mut()
4524 .map(|listener| listener.take()),
4525 );
4526 self.frame_state.next_frame.accessed_element_states.extend(
4527 self.frame_state.rendered_frame.accessed_element_states[range
4528 .start
4529 .accessed_element_states_index
4530 ..range.end.accessed_element_states_index]
4531 .iter()
4532 .map(|(id, type_id)| (id.clone(), *type_id)),
4533 );
4534 self.frame_state.next_frame.tab_stops.replay(
4535 &self.frame_state.rendered_frame.tab_stops.insertion_history
4536 [range.start.tab_handle_index..range.end.tab_handle_index],
4537 );
4538
4539 self.core
4540 .text_system
4541 .reuse_layouts(range.start.line_layout_index..range.end.line_layout_index);
4542 self.frame_state.next_frame.scene.replay(
4543 range.start.scene_index..range.end.scene_index,
4544 &self.frame_state.rendered_frame.scene,
4545 );
4546 }
4547
4548 pub fn with_text_style<F, R>(&mut self, style: Option<TextStyleRefinement>, f: F) -> R
4552 where
4553 F: FnOnce(&mut Self) -> R,
4554 {
4555 self.core.invalidator.debug_assert_paint_or_prepaint();
4556 if let Some(style) = style {
4557 self.frame_state.text_style_stack.push(style);
4558 let result = f(self);
4559 self.frame_state.text_style_stack.pop();
4560 result
4561 } else {
4562 f(self)
4563 }
4564 }
4565
4566 pub fn set_cursor_style(&mut self, style: CursorStyle, hitbox: &Hitbox) {
4569 self.core.invalidator.debug_assert_paint();
4570 self.frame_state
4571 .next_frame
4572 .cursor_styles
4573 .push(CursorStyleRequest {
4574 hitbox_id: Some(hitbox.id),
4575 style,
4576 });
4577 }
4578
4579 pub fn set_window_cursor_style(&mut self, style: CursorStyle) {
4584 self.core.invalidator.debug_assert_paint();
4585 self.frame_state
4586 .next_frame
4587 .cursor_styles
4588 .push(CursorStyleRequest {
4589 hitbox_id: None,
4590 style,
4591 })
4592 }
4593
4594 pub fn set_tooltip(&mut self, tooltip: AnyTooltip) -> TooltipId {
4597 self.core.invalidator.debug_assert_prepaint();
4598 let id = TooltipId(post_inc(&mut self.frame_state.next_tooltip_id.0));
4599 self.frame_state
4600 .next_frame
4601 .tooltip_requests
4602 .push(Some(TooltipRequest { id, tooltip }));
4603 id
4604 }
4605
4606 #[inline]
4611 pub fn with_content_mask<R>(
4612 &mut self,
4613 mask: Option<ContentMask<Pixels>>,
4614 f: impl FnOnce(&mut Self) -> R,
4615 ) -> R {
4616 self.core.invalidator.debug_assert_paint_or_prepaint();
4617 if let Some(mask) = mask {
4618 let mask = mask.intersect(&self.content_mask());
4619 self.frame_state.content_mask_stack.push(mask);
4620 let result = f(self);
4621 self.frame_state.content_mask_stack.pop();
4622 result
4623 } else {
4624 f(self)
4625 }
4626 }
4627
4628 pub fn with_element_offset<R>(
4631 &mut self,
4632 offset: Point<Pixels>,
4633 f: impl FnOnce(&mut Self) -> R,
4634 ) -> R {
4635 self.core.invalidator.debug_assert_prepaint();
4636
4637 if offset.is_zero() {
4638 return f(self);
4639 };
4640
4641 let abs_offset = self.element_offset() + offset;
4642 self.with_absolute_element_offset(abs_offset, f)
4643 }
4644
4645 pub fn with_absolute_element_offset<R>(
4649 &mut self,
4650 offset: Point<Pixels>,
4651 f: impl FnOnce(&mut Self) -> R,
4652 ) -> R {
4653 self.core.invalidator.debug_assert_prepaint();
4654 self.frame_state.element_offset_stack.push(offset);
4655 let result = f(self);
4656 self.frame_state.element_offset_stack.pop();
4657 result
4658 }
4659
4660 pub(crate) fn with_element_opacity<R>(
4661 &mut self,
4662 opacity: Option<f32>,
4663 f: impl FnOnce(&mut Self) -> R,
4664 ) -> R {
4665 self.core.invalidator.debug_assert_paint_or_prepaint();
4666
4667 let Some(opacity) = opacity else {
4668 return f(self);
4669 };
4670
4671 let previous_opacity = self.frame_state.element_opacity;
4672 self.frame_state.element_opacity = previous_opacity * opacity;
4673 let result = f(self);
4674 self.frame_state.element_opacity = previous_opacity;
4675 result
4676 }
4677
4678 pub fn transact<T, U>(&mut self, f: impl FnOnce(&mut Self) -> Result<T, U>) -> Result<T, U> {
4684 self.core.invalidator.debug_assert_prepaint();
4685 let index = self.prepaint_index();
4686 let result = f(self);
4687 if result.is_err() {
4688 self.frame_state
4689 .next_frame
4690 .hitboxes
4691 .truncate(index.hitboxes_index);
4692 self.frame_state
4693 .next_frame
4694 .tooltip_requests
4695 .truncate(index.tooltips_index);
4696 self.frame_state
4697 .next_frame
4698 .deferred_draws
4699 .truncate(index.deferred_draws_index);
4700 self.frame_state
4701 .next_frame
4702 .dispatch_tree
4703 .truncate(index.dispatch_tree_index);
4704 self.frame_state
4705 .next_frame
4706 .accessed_element_states
4707 .truncate(index.accessed_element_states_index);
4708 self.core
4709 .text_system
4710 .truncate_layouts(index.line_layout_index);
4711 }
4712 result
4713 }
4714
4715 pub fn request_autoscroll(&mut self, bounds: Bounds<Pixels>) {
4721 self.core.invalidator.debug_assert_prepaint();
4722 self.frame_state.requested_autoscroll = Some(bounds);
4723 }
4724
4725 pub fn take_autoscroll(&mut self) -> Option<Bounds<Pixels>> {
4728 self.core.invalidator.debug_assert_prepaint();
4729 self.frame_state.requested_autoscroll.take()
4730 }
4731
4732 pub fn use_asset<A: Asset>(&mut self, source: &A::Source, cx: &mut App) -> Option<A::Output> {
4738 cx.asset_entry::<A>(source).use_by(self.current_view())
4739 }
4740
4741 pub fn get_asset<A: Asset>(&mut self, source: &A::Source, cx: &mut App) -> Option<A::Output> {
4747 cx.fetch_asset::<A>(source)
4748 }
4749 pub fn element_offset(&self) -> Point<Pixels> {
4752 self.core.invalidator.debug_assert_prepaint();
4753 self.frame_state
4754 .element_offset_stack
4755 .last()
4756 .copied()
4757 .unwrap_or_default()
4758 }
4759
4760 #[inline]
4763 pub(crate) fn element_opacity(&self) -> f32 {
4764 self.core.invalidator.debug_assert_paint_or_prepaint();
4765 self.frame_state.element_opacity
4766 }
4767
4768 pub fn content_mask(&self) -> ContentMask<Pixels> {
4770 self.core.invalidator.debug_assert_paint_or_prepaint();
4771 self.frame_state
4772 .content_mask_stack
4773 .last()
4774 .cloned()
4775 .unwrap_or_else(|| ContentMask {
4776 bounds: Bounds {
4777 origin: Point::default(),
4778 size: self.core.viewport_size,
4779 },
4780 })
4781 }
4782
4783 pub fn with_element_namespace<R>(
4786 &mut self,
4787 element_id: impl Into<ElementId>,
4788 f: impl FnOnce(&mut Self) -> R,
4789 ) -> R {
4790 self.frame_state.element_id_stack.push(element_id.into());
4791 let result = f(self);
4792 self.frame_state.element_id_stack.pop();
4793 result
4794 }
4795
4796 pub fn use_keyed_state<S: 'static>(
4798 &mut self,
4799 key: impl Into<ElementId>,
4800 cx: &mut App,
4801 init: impl FnOnce(&mut Self, &mut Context<S>) -> S,
4802 ) -> Entity<S> {
4803 let current_view = self.current_view();
4804 self.with_global_id(key.into(), |global_id, window| {
4805 window.with_element_state(global_id, |state: Option<Entity<S>>, window| {
4806 if let Some(state) = state {
4807 (state.clone(), state)
4808 } else {
4809 let new_state = cx.new(|cx| init(window, cx));
4810 Self::observe_keyed_state(&new_state, current_view, cx);
4811 (new_state.clone(), new_state)
4812 }
4813 })
4814 })
4815 }
4816
4817 #[track_caller]
4823 pub fn use_state<S: 'static>(
4824 &mut self,
4825 cx: &mut App,
4826 init: impl FnOnce(&mut Self, &mut Context<S>) -> S,
4827 ) -> Entity<S> {
4828 self.use_keyed_state(
4829 ElementId::CodeLocation(*core::panic::Location::caller()),
4830 cx,
4831 init,
4832 )
4833 }
4834
4835 #[inline(always)]
4840 pub fn with_element_state<S, R>(
4841 &mut self,
4842 global_id: &GlobalElementId,
4843 f: impl FnOnce(Option<S>, &mut Self) -> (R, S),
4844 ) -> R
4845 where
4846 S: 'static,
4847 {
4848 self.core.invalidator.debug_assert_paint_or_prepaint();
4849
4850 let (key, state) = self.take_element_state(global_id, TypeId::of::<S>());
4851
4852 if let Some(any) = state {
4853 let ElementStateBox {
4854 inner,
4855 #[cfg(debug_assertions)]
4856 type_name,
4857 } = any;
4858 let mut state_box = inner
4860 .downcast::<Option<S>>()
4861 .map_err(|_| {
4862 #[cfg(debug_assertions)]
4863 {
4864 anyhow::anyhow!(
4865 "invalid element state type for id, requested {:?}, actual: {:?}",
4866 std::any::type_name::<S>(),
4867 type_name
4868 )
4869 }
4870
4871 #[cfg(not(debug_assertions))]
4872 {
4873 anyhow::anyhow!(
4874 "invalid element state type for id, requested {:?}",
4875 std::any::type_name::<S>(),
4876 )
4877 }
4878 })
4879 .unwrap();
4880
4881 let state = state_box.take().expect(
4882 "reentrant call to with_element_state for the same state type and element id",
4883 );
4884 let (result, state) = f(Some(state), self);
4885 state_box.replace(state);
4886 self.insert_element_state(
4887 key,
4888 ElementStateBox {
4889 inner: state_box,
4890 #[cfg(debug_assertions)]
4891 type_name,
4892 },
4893 );
4894 result
4895 } else {
4896 let (result, state) = f(None, self);
4897 self.insert_element_state(
4898 key,
4899 ElementStateBox {
4900 inner: Box::new(Some(state)),
4901 #[cfg(debug_assertions)]
4902 type_name: std::any::type_name::<S>(),
4903 },
4904 );
4905 result
4906 }
4907 }
4908
4909 pub fn with_optional_element_state<S, R>(
4916 &mut self,
4917 global_id: Option<&GlobalElementId>,
4918 f: impl FnOnce(Option<Option<S>>, &mut Self) -> (R, Option<S>),
4919 ) -> R
4920 where
4921 S: 'static,
4922 {
4923 self.core.invalidator.debug_assert_paint_or_prepaint();
4924
4925 if let Some(global_id) = global_id {
4926 self.with_element_state(global_id, |state, cx| {
4927 let (result, state) = f(Some(state), cx);
4928 let state =
4929 state.expect("you must return some state when you pass some element id");
4930 (result, state)
4931 })
4932 } else {
4933 let (result, state) = f(None, self);
4934 debug_assert!(
4935 state.is_none(),
4936 "you must not return an element state when passing None for the global id"
4937 );
4938 result
4939 }
4940 }
4941
4942 #[inline]
4944 pub fn with_tab_group<R>(&mut self, index: Option<isize>, f: impl FnOnce(&mut Self) -> R) -> R {
4945 if let Some(index) = index {
4946 self.frame_state.next_frame.tab_stops.begin_group(index);
4947 let result = f(self);
4948 self.frame_state.next_frame.tab_stops.end_group();
4949 result
4950 } else {
4951 f(self)
4952 }
4953 }
4954
4955 pub fn defer_draw(
4964 &mut self,
4965 element: AnyElement,
4966 absolute_offset: Point<Pixels>,
4967 priority: usize,
4968 content_mask: Option<ContentMask<Pixels>>,
4969 ) {
4970 self.core.invalidator.debug_assert_prepaint();
4971 let parent_node = self
4972 .frame_state
4973 .next_frame
4974 .dispatch_tree
4975 .active_node_id()
4976 .unwrap();
4977 self.frame_state
4978 .next_frame
4979 .deferred_draws
4980 .push(DeferredDraw {
4981 current_view: self.current_view(),
4982 parent_node,
4983 element_id_stack: self.frame_state.element_id_stack.clone(),
4984 text_style_stack: self.frame_state.text_style_stack.clone(),
4985 content_mask,
4986 rem_size: self.rem_size(),
4987 priority,
4988 element: Some(element),
4989 absolute_offset,
4990 prepaint_range: PrepaintStateIndex::default()..PrepaintStateIndex::default(),
4991 paint_range: PaintIndex::default()..PaintIndex::default(),
4992 });
4993 }
4994
4995 pub fn paint_layer<R>(&mut self, bounds: Bounds<Pixels>, f: impl FnOnce(&mut Self) -> R) -> R {
5001 self.core.invalidator.debug_assert_paint();
5002
5003 let content_mask = self.content_mask();
5004 let clipped_bounds = bounds.intersect(&content_mask.bounds);
5005 if !clipped_bounds.is_empty() {
5006 self.frame_state
5007 .next_frame
5008 .scene
5009 .push_layer(self.cover_bounds(clipped_bounds));
5010 }
5011
5012 let result = f(self);
5013
5014 if !clipped_bounds.is_empty() {
5015 self.frame_state.next_frame.scene.pop_layer();
5016 }
5017
5018 result
5019 }
5020
5021 pub fn paint_drop_shadows(
5028 &mut self,
5029 bounds: Bounds<Pixels>,
5030 corner_radii: Corners<Pixels>,
5031 shadows: &[BoxShadow],
5032 ) {
5033 self.core.invalidator.debug_assert_paint();
5034
5035 let scale_factor = self.scale_factor();
5036 let content_mask = self.snapped_content_mask();
5037 let opacity = self.element_opacity();
5038 let element_bounds = self.cover_bounds(bounds);
5039 let element_corner_radii = corner_radii.scale(scale_factor);
5040 for shadow in shadows {
5041 if shadow.inset {
5042 continue;
5043 }
5044 let shadow_bounds = (bounds + shadow.offset).dilate(shadow.spread_radius);
5045 self.frame_state.next_frame.scene.insert_primitive(Shadow {
5046 order: 0,
5047 blur_radius: shadow.blur_radius.scale(scale_factor),
5048 bounds: self.cover_bounds(shadow_bounds),
5049 content_mask,
5050 corner_radii: corner_radii.scale(scale_factor),
5051 color: shadow.color.opacity(opacity),
5052 element_bounds,
5053 element_corner_radii,
5054 inset: 0,
5055 pad: 0,
5056 });
5057 }
5058 }
5059
5060 pub fn paint_inset_shadows(
5065 &mut self,
5066 bounds: Bounds<Pixels>,
5067 corner_radii: Corners<Pixels>,
5068 shadows: &[BoxShadow],
5069 ) {
5070 self.core.invalidator.debug_assert_paint();
5071
5072 let scale_factor = self.scale_factor();
5073 let content_mask = self.snapped_content_mask();
5074 let opacity = self.element_opacity();
5075 let element_bounds = self.cover_bounds(bounds);
5076 let element_corner_radii = corner_radii.scale(scale_factor);
5077 for shadow in shadows {
5078 if !shadow.inset {
5079 continue;
5080 }
5081 let hole = (bounds + shadow.offset).dilate(-shadow.spread_radius);
5082 let zero = Pixels::ZERO;
5085 let hole_corner_radii = Corners {
5086 top_left: (corner_radii.top_left - shadow.spread_radius).max(zero),
5087 top_right: (corner_radii.top_right - shadow.spread_radius).max(zero),
5088 bottom_right: (corner_radii.bottom_right - shadow.spread_radius).max(zero),
5089 bottom_left: (corner_radii.bottom_left - shadow.spread_radius).max(zero),
5090 };
5091 self.frame_state.next_frame.scene.insert_primitive(Shadow {
5092 order: 0,
5093 blur_radius: shadow.blur_radius.scale(scale_factor),
5094 bounds: self.cover_bounds(hole),
5095 content_mask,
5096 corner_radii: hole_corner_radii.scale(scale_factor),
5097 color: shadow.color.opacity(opacity),
5098 element_bounds,
5099 element_corner_radii,
5100 inset: 1,
5101 pad: 0,
5102 });
5103 }
5104 }
5105
5106 fn largest_border_interior(quad: &Quad) -> Bounds<ScaledPixels> {
5107 let radii = &quad.corner_radii;
5108 let widths = &quad.border_widths;
5109 let edge_radii = Edges {
5110 top: radii.top_left.max(radii.top_right),
5111 right: radii.top_right.max(radii.bottom_right),
5112 bottom: radii.bottom_left.max(radii.bottom_right),
5113 left: radii.top_left.max(radii.bottom_left),
5114 };
5115
5116 let antialias_inset = point(ScaledPixels(1.0), ScaledPixels(1.0));
5117 let inset_bounds = |top_left_inset, bottom_right_inset| {
5118 Bounds::from_corners(
5119 quad.bounds.origin + top_left_inset + antialias_inset,
5120 quad.bounds.bottom_right() - bottom_right_inset - antialias_inset,
5121 )
5122 };
5123
5124 let horizontal_band = inset_bounds(
5127 point(widths.left, widths.top.max(edge_radii.top)),
5128 point(widths.right, widths.bottom.max(edge_radii.bottom)),
5129 );
5130 let vertical_band = inset_bounds(
5131 point(widths.left.max(edge_radii.left), widths.top),
5132 point(widths.right.max(edge_radii.right), widths.bottom),
5133 );
5134
5135 let area = |bounds: &Bounds<ScaledPixels>| {
5136 bounds.size.width.0.max(0.) * bounds.size.height.0.max(0.)
5137 };
5138 if area(&horizontal_band) >= area(&vertical_band) {
5139 horizontal_band
5140 } else {
5141 vertical_band
5142 }
5143 }
5144
5145 pub(crate) fn paint_imported_texture(
5152 &mut self,
5153 handle: ImportedTextureHandle,
5154 bounds: Bounds<Pixels>,
5155 corner_radii: Corners<Pixels>,
5156 opacity: f32,
5157 flip_v: bool,
5158 ) {
5159 self.core.invalidator.debug_assert_paint();
5160
5161 let primitive = CustomRenderPrimitive::Texture {
5162 order: 0,
5163 handle,
5164 bounds: self.snap_bounds(bounds),
5165 content_mask: self.snapped_content_mask(),
5166 radii: corner_radii.scale(self.scale_factor()),
5167 opacity: opacity * self.element_opacity(),
5168 flip_v,
5169 };
5170 self.frame_state
5171 .next_frame
5172 .scene
5173 .insert_primitive(primitive);
5174 }
5175
5176 pub fn paint_quad(&mut self, quad: PaintQuad) {
5187 self.core.invalidator.debug_assert_paint();
5188
5189 let opacity = self.element_opacity();
5190 let snapped_bounds = self.snap_bounds(quad.bounds);
5191 let snapped_border_widths = self.snap_border_widths(quad.border_widths);
5192 let quad = Quad {
5193 order: 0,
5194 bounds: snapped_bounds,
5195 content_mask: self.snapped_content_mask(),
5196 background: quad.background.opacity(opacity),
5197 border_color: quad.border_color.opacity(opacity),
5198 corner_radii: quad.corner_radii.scale(self.scale_factor()),
5199 border_widths: snapped_border_widths,
5200 border_style: quad.border_style,
5201 };
5202
5203 if !quad.background.is_transparent() {
5204 self.frame_state.next_frame.scene.insert_primitive(quad);
5205 return;
5206 }
5207
5208 let outer_bounds = quad.bounds;
5211 let inner_bounds = Self::largest_border_interior(&quad);
5212
5213 if inner_bounds.is_empty() {
5214 self.frame_state.next_frame.scene.insert_primitive(quad);
5215 return;
5216 }
5217
5218 let strips = [
5219 Bounds::from_corners(
5221 outer_bounds.origin,
5222 point(outer_bounds.right(), inner_bounds.top()),
5223 ),
5224 Bounds::from_corners(
5226 point(outer_bounds.left(), inner_bounds.bottom()),
5227 outer_bounds.bottom_right(),
5228 ),
5229 Bounds::from_corners(
5231 point(outer_bounds.left(), inner_bounds.top()),
5232 inner_bounds.bottom_left(),
5233 ),
5234 Bounds::from_corners(
5236 inner_bounds.top_right(),
5237 point(outer_bounds.right(), inner_bounds.bottom()),
5238 ),
5239 ];
5240
5241 for strip in strips {
5242 let content_mask_bounds = quad.content_mask.bounds.intersect(&strip);
5243 if !content_mask_bounds.is_empty() {
5244 self.frame_state.next_frame.scene.insert_primitive(Quad {
5245 content_mask: ContentMask {
5246 bounds: content_mask_bounds,
5247 },
5248 ..quad
5249 });
5250 }
5251 }
5252 }
5253
5254 pub fn paint_path(&mut self, mut path: Path<Pixels>, color: impl Into<Background>) {
5259 self.core.invalidator.debug_assert_paint();
5260
5261 let scale_factor = self.scale_factor();
5262 let content_mask = self.content_mask();
5263 let opacity = self.element_opacity();
5264 path.content_mask = content_mask;
5265 let color: Background = color.into();
5266 path.color = color.opacity(opacity);
5267 self.frame_state
5268 .next_frame
5269 .scene
5270 .insert_primitive(path.scale(scale_factor));
5271 }
5272
5273 pub fn paint_underline(
5277 &mut self,
5278 origin: Point<Pixels>,
5279 width: Pixels,
5280 style: &UnderlineStyle,
5281 ) {
5282 self.core.invalidator.debug_assert_paint();
5283 let underline = self.underline(origin, width, style);
5284 self.frame_state
5285 .next_frame
5286 .scene
5287 .insert_primitive(underline);
5288 }
5289
5290 pub fn paint_strikethrough(
5294 &mut self,
5295 origin: Point<Pixels>,
5296 width: Pixels,
5297 style: &StrikethroughStyle,
5298 ) {
5299 self.core.invalidator.debug_assert_paint();
5300
5301 let scale_factor = self.scale_factor();
5302 let height = style.thickness;
5303 let bounds = Bounds {
5304 origin: origin.map(|c| ScaledPixels(round_to_device_pixel(c.0, scale_factor))),
5305 size: size(self.snap_stroke(width), self.snap_stroke(height)),
5306 };
5307 let opacity = self.element_opacity();
5308
5309 self.frame_state
5310 .next_frame
5311 .scene
5312 .insert_primitive(Underline {
5313 order: 0,
5314 pad: 0,
5315 bounds,
5316 content_mask: self.snapped_content_mask(),
5317 thickness: self.snap_stroke(style.thickness),
5318 color: style.color.unwrap_or_default().opacity(opacity),
5319 wavy: false.into(),
5320 });
5321 }
5322
5323 pub fn paint_glyph(
5332 &mut self,
5333 origin: Point<Pixels>,
5334 font_id: FontId,
5335 glyph_id: GlyphId,
5336 font_size: Pixels,
5337 color: Hsla,
5338 ) -> Result<()> {
5339 self.core.invalidator.debug_assert_paint();
5340
5341 let element_opacity = self.element_opacity();
5342 let scale_factor = self.scale_factor();
5343 let glyph_origin = origin.scale(scale_factor);
5344
5345 let quantized_origin = Point::new(
5346 round_half_toward_zero(glyph_origin.x.0 * SUBPIXEL_VARIANTS_X as f32)
5347 / SUBPIXEL_VARIANTS_X as f32,
5348 round_half_toward_zero(glyph_origin.y.0 * SUBPIXEL_VARIANTS_Y as f32)
5349 / SUBPIXEL_VARIANTS_Y as f32,
5350 );
5351 let subpixel_variant = Point::new(
5352 (quantized_origin.x.fract() * SUBPIXEL_VARIANTS_X as f32) as u8,
5353 (quantized_origin.y.fract() * SUBPIXEL_VARIANTS_Y as f32) as u8,
5354 );
5355 let integer_origin = quantized_origin.map(|c| ScaledPixels(c.trunc()));
5356 let subpixel_rendering = self.should_use_subpixel_rendering(font_id, font_size);
5357 let dilation = self.text_system().glyph_dilation_for_color(color);
5358 let params = RenderGlyphParams {
5359 font_id,
5360 glyph_id,
5361 font_size,
5362 subpixel_variant,
5363 scale_factor,
5364 is_emoji: false,
5365 subpixel_rendering,
5366 dilation,
5367 };
5368
5369 let raster_bounds = self.text_system().raster_bounds(¶ms)?;
5370 if !raster_bounds.is_zero() {
5371 let tile = self
5372 .core
5373 .sprite_atlas
5374 .get_or_insert_with(params.clone().into(), &mut || {
5375 let (size, bytes) = self.text_system().rasterize_glyph(¶ms)?;
5376 Ok(Some((size, Cow::Owned(bytes))))
5377 })?
5378 .expect("Callback above only errors or returns Some");
5379 let bounds = Bounds {
5380 origin: integer_origin + raster_bounds.origin.map(Into::into),
5381 size: tile.bounds.size.map(Into::into),
5382 };
5383 let content_mask = self.snapped_content_mask();
5384
5385 if subpixel_rendering {
5386 self.frame_state
5387 .next_frame
5388 .scene
5389 .insert_primitive(SubpixelSprite {
5390 order: 0,
5391 pad: 0,
5392 bounds,
5393 content_mask,
5394 color: color.opacity(element_opacity),
5395 tile,
5396 transformation: TransformationMatrix::unit(),
5397 });
5398 } else {
5399 self.frame_state
5400 .next_frame
5401 .scene
5402 .insert_primitive(MonochromeSprite {
5403 order: 0,
5404 pad: 0,
5405 bounds,
5406 content_mask,
5407 color: color.opacity(element_opacity),
5408 tile,
5409 transformation: TransformationMatrix::unit(),
5410 });
5411 }
5412 }
5413 Ok(())
5414 }
5415
5416 fn should_use_subpixel_rendering(&self, font_id: FontId, font_size: Pixels) -> bool {
5417 if self.core.platform_window.background_appearance() != WindowBackgroundAppearance::Opaque {
5418 return false;
5419 }
5420
5421 if !self.core.platform_window.is_subpixel_rendering_supported() {
5422 return false;
5423 }
5424
5425 let mode = match self.core.text_rendering_mode.get() {
5426 TextRenderingMode::PlatformDefault => self
5427 .text_system()
5428 .recommended_rendering_mode(font_id, font_size),
5429 mode => mode,
5430 };
5431
5432 mode == TextRenderingMode::Subpixel
5433 }
5434
5435 pub fn paint_emoji(
5444 &mut self,
5445 origin: Point<Pixels>,
5446 font_id: FontId,
5447 glyph_id: GlyphId,
5448 font_size: Pixels,
5449 ) -> Result<()> {
5450 self.core.invalidator.debug_assert_paint();
5451
5452 let scale_factor = self.scale_factor();
5453 let glyph_origin = origin.scale(scale_factor);
5454 let integer_origin = glyph_origin.map(|c| ScaledPixels(round_half_toward_zero(c.0)));
5455 let params = RenderGlyphParams {
5456 font_id,
5457 glyph_id,
5458 font_size,
5459 subpixel_variant: Default::default(),
5460 scale_factor,
5461 is_emoji: true,
5462 subpixel_rendering: false,
5463 dilation: 0,
5464 };
5465
5466 let raster_bounds = self.text_system().raster_bounds(¶ms)?;
5467 if !raster_bounds.is_zero() {
5468 let tile = self
5469 .core
5470 .sprite_atlas
5471 .get_or_insert_with(params.clone().into(), &mut || {
5472 let (size, bytes) = self.text_system().rasterize_glyph(¶ms)?;
5473 Ok(Some((size, Cow::Owned(bytes))))
5474 })?
5475 .expect("Callback above only errors or returns Some");
5476
5477 let bounds = Bounds {
5478 origin: integer_origin + raster_bounds.origin.map(Into::into),
5479 size: tile.bounds.size.map(Into::into),
5480 };
5481 let content_mask = self.snapped_content_mask();
5482 let opacity = self.element_opacity();
5483
5484 self.frame_state
5485 .next_frame
5486 .scene
5487 .insert_primitive(PolychromeSprite {
5488 order: 0,
5489 pad: 0,
5490 grayscale: false.into(),
5491 bounds,
5492 corner_radii: Default::default(),
5493 content_mask,
5494 tile,
5495 opacity,
5496 });
5497 }
5498 Ok(())
5499 }
5500
5501 pub fn paint_svg(
5505 &mut self,
5506 bounds: Bounds<Pixels>,
5507 path: SharedString,
5508 mut data: Option<&[u8]>,
5509 transformation: TransformationMatrix,
5510 color: Hsla,
5511 cx: &App,
5512 ) -> Result<()> {
5513 self.core.invalidator.debug_assert_paint();
5514
5515 let element_opacity = self.element_opacity();
5516 let bounds = self.snap_bounds(bounds);
5517
5518 let params = RenderSvgParams {
5519 path,
5520 size: bounds.size.map(|pixels| {
5521 DevicePixels::from((pixels.0 * SMOOTH_SVG_SCALE_FACTOR).ceil() as i32)
5522 }),
5523 };
5524
5525 let Some(tile) =
5526 self.core
5527 .sprite_atlas
5528 .get_or_insert_with(params.clone().into(), &mut || {
5529 let Some((size, bytes)) = cx.svg_renderer.render_alpha_mask(¶ms, data)?
5530 else {
5531 return Ok(None);
5532 };
5533 Ok(Some((size, Cow::Owned(bytes))))
5534 })?
5535 else {
5536 return Ok(());
5537 };
5538 let content_mask = self.snapped_content_mask();
5539 let svg_bounds = Bounds {
5540 origin: bounds.center()
5541 - Point::new(
5542 ScaledPixels(tile.bounds.size.width.0 as f32 / SMOOTH_SVG_SCALE_FACTOR / 2.),
5543 ScaledPixels(tile.bounds.size.height.0 as f32 / SMOOTH_SVG_SCALE_FACTOR / 2.),
5544 ),
5545 size: tile
5546 .bounds
5547 .size
5548 .map(|value| ScaledPixels(value.0 as f32 / SMOOTH_SVG_SCALE_FACTOR)),
5549 };
5550 let final_bounds = svg_bounds
5551 .map_origin(|value| ScaledPixels(round_half_toward_zero(value.0)))
5552 .map_size(|size| size.ceil());
5553
5554 self.frame_state
5555 .next_frame
5556 .scene
5557 .insert_primitive(MonochromeSprite {
5558 order: 0,
5559 pad: 0,
5560 bounds: final_bounds,
5561 content_mask,
5562 color: color.opacity(element_opacity),
5563 tile,
5564 transformation,
5565 });
5566
5567 Ok(())
5568 }
5569
5570 pub fn paint_image(
5580 &mut self,
5581 bounds: Bounds<Pixels>,
5582 image_bounds: Bounds<Pixels>,
5583 corner_radii: Corners<Pixels>,
5584 data: Arc<RenderImage>,
5585 frame_index: usize,
5586 grayscale: bool,
5587 ) -> Result<()> {
5588 self.core.invalidator.debug_assert_paint();
5589
5590 let visible_bounds = bounds.intersect(&image_bounds);
5591 if visible_bounds.size.width <= Pixels::ZERO || visible_bounds.size.height <= Pixels::ZERO {
5592 return Ok(());
5593 }
5594 if image_bounds.size.width <= Pixels::ZERO || image_bounds.size.height <= Pixels::ZERO {
5595 return Ok(());
5596 }
5597
5598 let params = RenderImageParams {
5599 image_id: data.id,
5600 frame_index,
5601 };
5602
5603 let tile = self
5604 .core
5605 .sprite_atlas
5606 .get_or_insert_with(params.into(), &mut || {
5607 Ok(Some((
5608 data.size(frame_index),
5609 Cow::Borrowed(
5610 data.as_bytes(frame_index)
5611 .expect("It's the caller's job to pass a valid frame index"),
5612 ),
5613 )))
5614 })?
5615 .expect("Callback above only returns Some");
5616
5617 let visible_bounds_snapped = self.snap_bounds(visible_bounds);
5618
5619 let sub_tile = if visible_bounds == image_bounds {
5620 tile
5621 } else {
5622 let x_offset_ratio =
5623 (visible_bounds.origin.x - image_bounds.origin.x) / image_bounds.size.width;
5624 let y_offset_ratio =
5625 (visible_bounds.origin.y - image_bounds.origin.y) / image_bounds.size.height;
5626 let width_ratio = visible_bounds.size.width / image_bounds.size.width;
5627 let height_ratio = visible_bounds.size.height / image_bounds.size.height;
5628
5629 let tile_origin_x = tile.bounds.origin.x.0;
5630 let tile_origin_y = tile.bounds.origin.y.0;
5631 let tile_width = tile.bounds.size.width.0;
5632 let tile_height = tile.bounds.size.height.0;
5633
5634 let sub_origin_x = tile_origin_x + (x_offset_ratio * tile_width as f32).round() as i32;
5635 let sub_origin_y = tile_origin_y + (y_offset_ratio * tile_height as f32).round() as i32;
5636 let sub_width = (width_ratio * tile_width as f32).round() as i32;
5637 let sub_height = (height_ratio * tile_height as f32).round() as i32;
5638
5639 let max_x = tile_origin_x + tile_width;
5640 let max_y = tile_origin_y + tile_height;
5641
5642 let clamped_origin_x = sub_origin_x.clamp(tile_origin_x, max_x);
5643 let clamped_origin_y = sub_origin_y.clamp(tile_origin_y, max_y);
5644 let clamped_width = sub_width.min(max_x - clamped_origin_x).max(0);
5645 let clamped_height = sub_height.min(max_y - clamped_origin_y).max(0);
5646
5647 AtlasTile {
5648 bounds: Bounds {
5649 origin: point(
5650 DevicePixels(clamped_origin_x),
5651 DevicePixels(clamped_origin_y),
5652 ),
5653 size: size(DevicePixels(clamped_width), DevicePixels(clamped_height)),
5654 },
5655 ..tile
5656 }
5657 };
5658
5659 let content_mask = self.snapped_content_mask();
5660 let corner_radii = corner_radii
5661 .clamp_radii_for_quad_size(visible_bounds.size)
5662 .scale(self.scale_factor());
5663 let opacity = self.element_opacity();
5664
5665 self.frame_state
5666 .next_frame
5667 .scene
5668 .insert_primitive(PolychromeSprite {
5669 order: 0,
5670 pad: 0,
5671 grayscale: grayscale.into(),
5672 bounds: visible_bounds_snapped,
5673 content_mask,
5674 corner_radii,
5675 tile: sub_tile,
5676 opacity,
5677 });
5678 Ok(())
5679 }
5680
5681 pub fn drop_image(&mut self, data: Arc<RenderImage>) -> Result<()> {
5683 for frame_index in 0..data.frame_count() {
5684 let params = RenderImageParams {
5685 image_id: data.id,
5686 frame_index,
5687 };
5688
5689 self.core.sprite_atlas.remove(¶ms.clone().into());
5690 }
5691
5692 Ok(())
5693 }
5694
5695 #[cfg(any(test, feature = "test-support"))]
5697 pub fn has_image_atlas_entry(&self, data: &RenderImage) -> bool {
5698 data.frame_count() > 0
5699 && (0..data.frame_count()).all(|frame_index| {
5700 self.core.sprite_atlas.contains(
5701 &RenderImageParams {
5702 image_id: data.id,
5703 frame_index,
5704 }
5705 .into(),
5706 )
5707 })
5708 }
5709
5710 #[must_use]
5717 pub fn request_layout(
5718 &mut self,
5719 style: Style,
5720 children: impl IntoIterator<Item = LayoutId>,
5721 cx: &mut App,
5722 ) -> LayoutId {
5723 self.core.invalidator.debug_assert_prepaint();
5724
5725 cx.layout_id_buffer.clear();
5726 cx.layout_id_buffer.extend(children);
5727 let rem_size = self.rem_size();
5728 let scale_factor = self.scale_factor();
5729 let engine_style = to_engine_layout_style(&style);
5730
5731 self.frame_state.layout_session.request_layout(
5732 &engine_style,
5733 rem_size,
5734 scale_factor,
5735 &cx.layout_id_buffer,
5736 )
5737 }
5738
5739 pub fn request_measured_layout<F>(&mut self, style: Style, measure: F) -> LayoutId
5749 where
5750 F: Fn(Size<Option<Pixels>>, Size<AvailableSpace>, &mut Window, &mut App) -> Size<Pixels>
5751 + 'static,
5752 {
5753 self.core.invalidator.debug_assert_prepaint();
5754
5755 let rem_size = self.rem_size();
5756 let scale_factor = self.scale_factor();
5757 let engine_style = to_engine_layout_style(&style);
5758 let measure = move |known_dimensions, available_space, context: &mut dyn MeasureContext| {
5759 let MeasureHandles { window, app } = context.handles();
5760 let (core, frame_state) = window;
5761 let core = core
5762 .downcast_mut::<WindowHostCore>()
5763 .expect("measure context window half should be a window's core");
5764 let frame_state = frame_state
5765 .downcast_mut::<WindowFrameState>()
5766 .expect("measure context window half should be a window's frame state");
5767 let cx = app
5768 .downcast_mut::<App>()
5769 .expect("measure context app should be an App");
5770 measure(
5771 known_dimensions,
5772 available_space,
5773 &mut Window { core, frame_state },
5774 cx,
5775 )
5776 };
5777 self.frame_state.layout_session.request_measured_layout(
5778 &engine_style,
5779 rem_size,
5780 scale_factor,
5781 Box::new(measure),
5782 )
5783 }
5784
5785 pub(crate) fn compute_layout(
5791 &mut self,
5792 layout_id: LayoutId,
5793 available_space: Size<AvailableSpace>,
5794 cx: &mut App,
5795 ) {
5796 self.core.invalidator.debug_assert_prepaint();
5797
5798 let scale_factor = self.scale_factor();
5799 let layout_session = self.frame_state.layout_session.clone();
5800 let core = &mut *self.core;
5801 let frame_state = &mut *self.frame_state;
5802 layout_session.compute_layout(
5803 layout_id,
5804 available_space,
5805 scale_factor,
5806 &mut WindowMeasureContext {
5807 core,
5808 frame_state,
5809 cx,
5810 },
5811 );
5812 }
5813
5814 pub fn layout_bounds(&mut self, layout_id: LayoutId) -> Bounds<Pixels> {
5820 self.core.invalidator.debug_assert_prepaint();
5821
5822 let scale_factor = self.scale_factor();
5823 let mut bounds = self
5824 .frame_state
5825 .layout_session
5826 .layout_bounds(layout_id, scale_factor)
5827 .map(Into::into);
5828 let snapped_offset = self.pixel_snap_point(self.element_offset());
5829 bounds.origin += snapped_offset;
5830 bounds
5831 }
5832
5833 pub fn insert_hitbox(&mut self, bounds: Bounds<Pixels>, behavior: HitboxBehavior) -> Hitbox {
5840 self.insert_hitbox_with_filter(bounds, behavior, None)
5841 }
5842
5843 pub fn insert_hitbox_with_filter(
5848 &mut self,
5849 bounds: Bounds<Pixels>,
5850 behavior: HitboxBehavior,
5851 filter: Option<HitboxFilter>,
5852 ) -> Hitbox {
5853 self.core.invalidator.debug_assert_prepaint();
5854
5855 let content_mask = self.content_mask();
5856 let mut id = self.frame_state.next_hitbox_id;
5857 self.frame_state.next_hitbox_id = self.frame_state.next_hitbox_id.next();
5858 let hitbox = Hitbox {
5859 id,
5860 bounds,
5861 content_mask,
5862 behavior,
5863 };
5864 self.frame_state.next_frame.hitboxes.push(hitbox.clone());
5865 self.frame_state.next_frame.hitbox_filters.push(filter);
5866 hitbox
5867 }
5868
5869 pub fn insert_window_control_hitbox(&mut self, area: WindowControlArea, hitbox: Hitbox) {
5873 self.core.invalidator.debug_assert_paint();
5874 self.frame_state
5875 .next_frame
5876 .window_control_hitboxes
5877 .push((area, hitbox));
5878 }
5879
5880 pub fn set_key_context(&mut self, context: KeyContext) {
5885 self.core.invalidator.debug_assert_paint();
5886 self.frame_state
5887 .next_frame
5888 .dispatch_tree
5889 .set_key_context(context);
5890 }
5891
5892 pub fn set_focus_handle(&mut self, focus_handle: &FocusHandle, _: &App) {
5897 self.core.invalidator.debug_assert_prepaint();
5898 if focus_handle.is_focused(self) {
5899 self.frame_state.next_frame.focus = Some(focus_handle.id);
5900 }
5901 self.frame_state
5902 .next_frame
5903 .dispatch_tree
5904 .set_focus_id(focus_handle.id);
5905 }
5906
5907 pub fn set_view_id(&mut self, view_id: EntityId) {
5913 self.core.invalidator.debug_assert_prepaint();
5914 self.frame_state
5915 .next_frame
5916 .dispatch_tree
5917 .set_view_id(view_id);
5918 }
5919
5920 pub fn current_view(&self) -> EntityId {
5922 self.core.invalidator.debug_assert_paint_or_prepaint();
5923 self.frame_state
5924 .rendered_entity_stack
5925 .last()
5926 .copied()
5927 .unwrap()
5928 }
5929
5930 #[inline]
5931 pub(crate) fn with_rendered_view<R>(
5932 &mut self,
5933 id: EntityId,
5934 f: impl FnOnce(&mut Self) -> R,
5935 ) -> R {
5936 self.frame_state.rendered_entity_stack.push(id);
5937 let result = f(self);
5938 self.frame_state.rendered_entity_stack.pop();
5939 result
5940 }
5941
5942 pub fn with_image_cache<F, R>(&mut self, image_cache: Option<AnyImageCache>, f: F) -> R
5944 where
5945 F: FnOnce(&mut Self) -> R,
5946 {
5947 if let Some(image_cache) = image_cache {
5948 self.frame_state.image_cache_stack.push(image_cache);
5949 let result = f(self);
5950 self.frame_state.image_cache_stack.pop();
5951 result
5952 } else {
5953 f(self)
5954 }
5955 }
5956
5957 pub fn handle_input(
5966 &mut self,
5967 focus_handle: &FocusHandle,
5968 input_handler: impl InputHandler,
5969 cx: &App,
5970 ) {
5971 self.core.invalidator.debug_assert_paint();
5972
5973 if focus_handle.is_focused(self) {
5974 let cx = self.to_async(cx);
5975 self.frame_state
5976 .next_frame
5977 .input_handlers
5978 .push(Some(new_platform_input_handler(
5979 cx,
5980 Box::new(input_handler),
5981 )));
5982 }
5983 }
5984
5985 fn apply_text_input_configuration(&mut self, cx: &mut App) {
5990 let configuration = match self.core.platform_window.take_input_handler() {
5991 Some(mut input_handler) => {
5992 let configuration = input_handler.text_input_configuration(self, cx);
5993 self.core.platform_window.set_input_handler(input_handler);
5994 configuration
5995 }
5996 None => TextInputConfiguration::default(),
5997 };
5998 if self.core.last_text_input_configuration.as_ref() != Some(&configuration) {
5999 self.core
6000 .platform_window
6001 .set_text_input_configuration(configuration.clone());
6002 self.core.last_text_input_configuration = Some(configuration);
6003 }
6004 }
6005
6006 pub fn on_mouse_event<Event: MouseEvent>(
6012 &mut self,
6013 mut listener: impl FnMut(&Event, DispatchPhase, &mut Window, &mut App) + 'static,
6014 ) {
6015 self.core.invalidator.debug_assert_paint();
6016
6017 self.frame_state
6018 .next_frame
6019 .mouse_listeners
6020 .push(Some(Box::new(
6021 move |event: &dyn Any, phase: DispatchPhase, window: &mut Window, cx: &mut App| {
6022 if let Some(event) = event.downcast_ref() {
6023 listener(event, phase, window, cx)
6024 }
6025 },
6026 )));
6027 }
6028
6029 pub fn on_key_event<Event: KeyEvent>(
6038 &mut self,
6039 listener: impl Fn(&Event, DispatchPhase, &mut Window, &mut App) + 'static,
6040 ) {
6041 self.core.invalidator.debug_assert_paint();
6042
6043 self.frame_state
6044 .next_frame
6045 .dispatch_tree
6046 .on_key_event(Rc::new(
6047 move |event: &dyn Any, phase, window: &mut Window, cx: &mut App| {
6048 if let Some(event) = event.downcast_ref::<Event>() {
6049 listener(event, phase, window, cx)
6050 }
6051 },
6052 ));
6053 }
6054
6055 pub fn on_modifiers_changed(
6062 &mut self,
6063 listener: impl Fn(&ModifiersChangedEvent, &mut Window, &mut App) + 'static,
6064 ) {
6065 self.core.invalidator.debug_assert_paint();
6066
6067 self.frame_state
6068 .next_frame
6069 .dispatch_tree
6070 .on_modifiers_changed(Rc::new(
6071 move |event: &ModifiersChangedEvent, window: &mut Window, cx: &mut App| {
6072 listener(event, window, cx)
6073 },
6074 ));
6075 }
6076
6077 pub fn on_focus_in(
6081 &mut self,
6082 handle: &FocusHandle,
6083 cx: &mut App,
6084 mut listener: impl FnMut(&mut Window, &mut App) + 'static,
6085 ) -> Subscription {
6086 let focus_id = handle.id;
6087 let (subscription, activate) =
6088 self.new_focus_listener(Box::new(move |event, window, cx| {
6089 if event.is_focus_in(focus_id) {
6090 listener(window, cx);
6091 }
6092 true
6093 }));
6094 cx.defer(move |_| activate());
6095 subscription
6096 }
6097
6098 pub fn on_focus_out(
6101 &mut self,
6102 handle: &FocusHandle,
6103 cx: &mut App,
6104 mut listener: impl FnMut(FocusOutEvent, &mut Window, &mut App) + 'static,
6105 ) -> Subscription {
6106 let focus_id = handle.id;
6107 let (subscription, activate) =
6108 self.new_focus_listener(Box::new(move |event, window, cx| {
6109 if let Some(blurred_id) = event.previous_focus_path.last().copied()
6110 && event.is_focus_out(focus_id)
6111 {
6112 let event = FocusOutEvent {
6113 blurred: WeakFocusHandle {
6114 id: blurred_id,
6115 handles: Arc::downgrade(&cx.focus_handles),
6116 },
6117 };
6118 listener(event, window, cx)
6119 }
6120 true
6121 }));
6122 cx.defer(move |_| activate());
6123 subscription
6124 }
6125
6126 fn reset_cursor_style(&self, cx: &mut App) {
6127 if self.is_window_hovered() {
6129 let style = self
6130 .frame_state
6131 .rendered_frame
6132 .cursor_style(self)
6133 .unwrap_or(CursorStyle::Arrow);
6134 cx.platform.set_cursor_style(style);
6135 }
6136 }
6137
6138 pub fn dispatch_keystroke(&mut self, keystroke: Keystroke, cx: &mut App) -> bool {
6141 let keystroke = keystroke.with_simulated_ime();
6142 let result = self.dispatch_event(
6143 PlatformInput::KeyDown(KeyDownEvent {
6144 keystroke: keystroke.clone(),
6145 is_held: false,
6146 prefer_character_input: false,
6147 }),
6148 cx,
6149 );
6150 if !result.propagate {
6151 return true;
6152 }
6153
6154 if let Some(input) = keystroke.key_char
6155 && let Some(mut input_handler) = self.core.platform_window.take_input_handler()
6156 {
6157 input_handler.dispatch_input(&input, self, cx);
6158 self.core.platform_window.set_input_handler(input_handler);
6159 return true;
6160 }
6161
6162 false
6163 }
6164
6165 pub fn keystroke_text_for(&self, action: &dyn Action) -> String {
6168 self.highest_precedence_binding_for_action(action)
6169 .map(|binding| {
6170 binding
6171 .keystrokes()
6172 .iter()
6173 .map(ToString::to_string)
6174 .collect::<Vec<_>>()
6175 .join(" ")
6176 })
6177 .unwrap_or_else(|| action.name().to_string())
6178 }
6179
6180 #[profiling::function]
6182 pub fn dispatch_event(&mut self, event: PlatformInput, cx: &mut App) -> DispatchEventResult {
6183 #[cfg(feature = "profiler")]
6184 self.core.window_profiler.begin_input(event.kind_name());
6185 let update_count_before = self.core.invalidator.update_count();
6186 let old_modality = self.core.last_input_modality;
6190 self.core.last_input_modality = match &event {
6191 PlatformInput::KeyDown(_) => InputModality::Keyboard,
6192 PlatformInput::MouseMove(_) | PlatformInput::MouseDown(_) => InputModality::Mouse,
6193 PlatformInput::Touch(_) => InputModality::Touch,
6194 _ => self.core.last_input_modality,
6195 };
6196 if self.core.last_input_modality != old_modality {
6197 self.refresh();
6198 }
6199
6200 cx.propagate_event = true;
6202 self.core.default_prevented = false;
6204
6205 let event = match event {
6206 PlatformInput::MouseMove(mouse_move) => {
6209 self.core.mouse_position = mouse_move.position;
6210 self.core.modifiers = mouse_move.modifiers;
6211 PlatformInput::MouseMove(mouse_move)
6212 }
6213 PlatformInput::MouseDown(mouse_down) => {
6214 self.core.mouse_position = mouse_down.position;
6215 self.core.modifiers = mouse_down.modifiers;
6216 PlatformInput::MouseDown(mouse_down)
6217 }
6218 PlatformInput::MouseUp(mouse_up) => {
6219 self.core.mouse_position = mouse_up.position;
6220 self.core.modifiers = mouse_up.modifiers;
6221 PlatformInput::MouseUp(mouse_up)
6222 }
6223 PlatformInput::MousePressure(mouse_pressure) => {
6224 PlatformInput::MousePressure(mouse_pressure)
6225 }
6226 PlatformInput::MouseExited(mouse_exited) => {
6227 self.core.modifiers = mouse_exited.modifiers;
6228 PlatformInput::MouseExited(mouse_exited)
6229 }
6230 PlatformInput::ModifiersChanged(modifiers_changed) => {
6231 self.core.modifiers = modifiers_changed.modifiers;
6232 self.core.capslock = modifiers_changed.capslock;
6233 PlatformInput::ModifiersChanged(modifiers_changed)
6234 }
6235 PlatformInput::ScrollWheel(scroll_wheel) => {
6236 self.core.mouse_position = scroll_wheel.position;
6237 self.core.modifiers = scroll_wheel.modifiers;
6238 PlatformInput::ScrollWheel(scroll_wheel)
6239 }
6240 PlatformInput::Pinch(pinch) => {
6241 self.core.mouse_position = pinch.position;
6242 self.core.modifiers = pinch.modifiers;
6243 PlatformInput::Pinch(pinch)
6244 }
6245 PlatformInput::FileDrop(file_drop) => match file_drop {
6248 FileDropEvent::Entered { position, paths } => {
6249 self.core.mouse_position = position;
6250 let source_window = self.core.handle.window_id();
6251 if !cx.restore_platform_drag(source_window) && cx.active_drag.is_none() {
6252 cx.active_drag = Some(AnyDrag {
6253 value: Arc::new(paths.clone()),
6254 view: cx.new(|_| paths).into(),
6255 cursor_offset: position,
6256 cursor_style: None,
6257 external_payload_source: None,
6258 });
6259 }
6260 PlatformInput::MouseMove(MouseMoveEvent {
6261 position,
6262 pressed_button: Some(MouseButton::Left),
6263 modifiers: Modifiers::default(),
6264 })
6265 }
6266 FileDropEvent::Pending { position } => {
6267 self.core.mouse_position = position;
6268 PlatformInput::MouseMove(MouseMoveEvent {
6269 position,
6270 pressed_button: Some(MouseButton::Left),
6271 modifiers: Modifiers::default(),
6272 })
6273 }
6274 FileDropEvent::Submit { position } => {
6275 cx.activate(true);
6276 self.core.mouse_position = position;
6277 PlatformInput::MouseUp(MouseUpEvent {
6278 button: MouseButton::Left,
6279 position,
6280 modifiers: Modifiers::default(),
6281 click_count: 1,
6282 })
6283 }
6284 FileDropEvent::Exited => {
6285 if !cx.hand_restored_drag_to_platform(self.core.handle.window_id()) {
6286 cx.active_drag.take();
6287 }
6288 self.refresh();
6289 PlatformInput::FileDrop(FileDropEvent::Exited)
6290 }
6291 FileDropEvent::Ended => {
6292 cx.end_platform_drag(self.core.handle.window_id());
6293 self.refresh();
6294 PlatformInput::FileDrop(FileDropEvent::Ended)
6295 }
6296 },
6297 PlatformInput::Touch(touch) => PlatformInput::Touch(touch),
6298 PlatformInput::LongPress(long_press) => {
6299 self.core.mouse_position = if long_press.phase == crate::TouchPhase::Started {
6300 long_press.start_position
6301 } else {
6302 long_press.position
6303 };
6304 if long_press.phase == crate::TouchPhase::Started {
6305 self.core.long_press_capture = None;
6306 }
6307 PlatformInput::LongPress(long_press)
6308 }
6309 PlatformInput::TouchDrag(touch_drag) => {
6310 self.core.mouse_position = touch_drag.start_position;
6311 PlatformInput::TouchDrag(touch_drag)
6312 }
6313 PlatformInput::KeyDown(_) | PlatformInput::KeyUp(_) => event,
6314 };
6315
6316 if let Some(any_mouse_event) = event.mouse_event() {
6317 self.dispatch_mouse_event(any_mouse_event, cx);
6318 } else if let Some(any_key_event) = event.keyboard_event() {
6319 self.dispatch_key_event(any_key_event, cx);
6320 } else if let Some(touch_event) = event.touch_event() {
6321 self.dispatch_touch_event(touch_event, cx);
6322 }
6323 if let PlatformInput::LongPress(long_press) = &event {
6324 match long_press.phase {
6325 crate::TouchPhase::Started if !self.core.default_prevented => {
6326 self.core.long_press_capture = None;
6327 }
6328 crate::TouchPhase::Ended | crate::TouchPhase::Cancelled => {
6329 self.core.long_press_capture = None;
6330 }
6331 crate::TouchPhase::Started | crate::TouchPhase::Moved => {}
6332 }
6333 }
6334
6335 self.promote_external_drag_to_platform(&event, cx);
6338
6339 let caused_invalidation = self.core.invalidator.update_count() > update_count_before;
6340 if caused_invalidation {
6341 self.core.input_rate_tracker.borrow_mut().record_input();
6342 }
6343 #[cfg(feature = "profiler")]
6344 self.core.window_profiler.end_input(caused_invalidation);
6345
6346 DispatchEventResult {
6347 propagate: cx.propagate_event,
6348 default_prevented: self.core.default_prevented,
6349 }
6350 }
6351
6352 fn promote_external_drag_to_platform(&mut self, event: &PlatformInput, cx: &mut App) {
6353 let PlatformInput::MouseMove(mouse_move) = event else {
6354 return;
6355 };
6356 if mouse_move.pressed_button != Some(MouseButton::Left) {
6357 return;
6358 }
6359 if Bounds::new(Point::default(), self.core.viewport_size).contains(&mouse_move.position) {
6360 return;
6361 }
6362 if !self.core.platform_window.can_start_external_drag() {
6363 return;
6364 }
6365 let Some(payload_source) = cx
6366 .active_drag
6367 .as_mut()
6368 .and_then(|drag| drag.external_payload_source.take())
6369 else {
6370 return;
6371 };
6372 let Some(payload) = payload_source(self, cx) else {
6373 return;
6374 };
6375 if self.core.platform_window.start_external_drag(&payload)
6376 && cx.hand_active_drag_to_platform(self.core.handle.window_id())
6377 {
6378 self.refresh();
6379 }
6380 }
6381
6382 pub fn touch_prediction_enabled(&self) -> bool {
6386 self.core.touch_prediction_enabled
6387 }
6388
6389 pub fn set_touch_prediction_enabled(&mut self, enabled: bool) {
6393 self.core.touch_prediction_enabled = enabled;
6394 }
6395
6396 fn dispatch_touch_event(&mut self, event: &TouchEvent, cx: &mut App) {
6400 let mut event = event.clone();
6401 if !self.core.touch_prediction_enabled {
6402 event.predicted_position = None;
6403 }
6404 let recognized_gestures = self.core.touch_gestures.handle_event(&event);
6405 if event.phase == crate::TouchPhase::Started
6406 && let Some(touch_drag) = self.core.touch_gestures.offer_touch_drag(event.id)
6407 {
6408 self.dispatch_recognized_touch_gesture(touch_drag, cx);
6409 }
6410 if event.phase == crate::TouchPhase::Started
6411 && self.core.touch_gestures.pending_long_press().is_some()
6412 {
6413 self.core.long_press_capture = None;
6414 }
6415 let mut tapped = false;
6416 for gesture in recognized_gestures {
6417 tapped |= matches!(gesture, RecognizedTouchGesture::Tap { .. });
6418 self.dispatch_recognized_touch_gesture(gesture, cx);
6419 }
6420 if event.phase == crate::TouchPhase::Started {
6421 self.schedule_long_press_timer(cx);
6422 } else if self.core.touch_gestures.pending_long_press().is_none() {
6423 self.core.long_press_timer.take();
6424 }
6425 if tapped && self.core.invalidator.is_dirty() {
6431 self.draw(cx).clear(cx);
6432 }
6433 if self.core.touch_gestures.has_momentum() {
6434 self.schedule_touch_momentum_tick();
6435 }
6436 }
6437
6438 fn dispatch_recognized_touch_gesture(&mut self, gesture: RecognizedTouchGesture, cx: &mut App) {
6439 match gesture {
6440 RecognizedTouchGesture::Scroll(scroll_wheel) => {
6441 self.core.mouse_position = scroll_wheel.position;
6442 cx.propagate_event = true;
6443 self.dispatch_mouse_event(&scroll_wheel, cx);
6444 }
6445 RecognizedTouchGesture::Tap { down, up } => {
6446 self.core.mouse_position = up.position;
6447 cx.propagate_event = true;
6448 self.dispatch_mouse_event(&down, cx);
6449 cx.propagate_event = true;
6450 self.dispatch_mouse_event(&up, cx);
6451 }
6452 RecognizedTouchGesture::TouchDrag(touch_drag) => {
6453 self.core.mouse_position = touch_drag.start_position;
6454 cx.propagate_event = true;
6455 self.core.default_prevented = false;
6456 let started = touch_drag.phase == crate::TouchPhase::Started;
6457 self.dispatch_mouse_event(&touch_drag, cx);
6458 if started {
6459 self.core
6460 .touch_gestures
6461 .resolve_touch_drag(self.core.default_prevented);
6462 }
6463 }
6464 RecognizedTouchGesture::LongPress(long_press) => {
6465 self.core.mouse_position = if long_press.phase == crate::TouchPhase::Started {
6466 long_press.start_position
6467 } else {
6468 long_press.position
6469 };
6470 cx.propagate_event = true;
6471 self.core.default_prevented = false;
6472 let started = long_press.phase == crate::TouchPhase::Started;
6473 let ended = matches!(
6474 long_press.phase,
6475 crate::TouchPhase::Ended | crate::TouchPhase::Cancelled
6476 );
6477 self.dispatch_mouse_event(&long_press, cx);
6478 if started {
6479 let claimed = self.core.default_prevented;
6480 self.core.touch_gestures.resolve_long_press(claimed);
6481 if !claimed {
6482 self.core.long_press_capture = None;
6483 }
6484 }
6485 if ended {
6486 self.core.long_press_capture = None;
6487 }
6488 }
6489 }
6490 }
6491
6492 fn schedule_long_press_timer(&mut self, cx: &mut App) {
6493 self.core.long_press_timer.take();
6494 let Some((touch_id, duration)) = self.core.touch_gestures.pending_long_press() else {
6495 return;
6496 };
6497 self.core.long_press_timer = Some(self.spawn(cx, async move |cx| {
6498 cx.background_executor.timer(duration).await;
6499 cx.update(move |window, cx| {
6500 window.core.long_press_timer.take();
6501 if let Some(gesture) = window.core.touch_gestures.offer_long_press(touch_id) {
6502 window.dispatch_recognized_touch_gesture(gesture, cx);
6503 }
6504 })
6505 .log_err();
6506 }));
6507 }
6508
6509 fn schedule_touch_momentum_tick(&mut self) {
6510 self.on_next_frame(|window, cx| {
6511 if let Some(gesture) = window.core.touch_gestures.tick_momentum() {
6512 window.dispatch_recognized_touch_gesture(gesture, cx);
6513 }
6514 if window.core.touch_gestures.has_momentum() {
6515 window.schedule_touch_momentum_tick();
6516 }
6517 });
6518 }
6519
6520 fn dispatch_mouse_event(&mut self, event: &dyn Any, cx: &mut App) {
6521 let hit_test = self
6522 .frame_state
6523 .rendered_frame
6524 .hit_test(self.mouse_position());
6525 if hit_test != self.core.mouse_hit_test {
6526 self.core.mouse_hit_test = hit_test;
6527 self.reset_cursor_style(cx);
6528 }
6529
6530 #[cfg(any(feature = "inspector", debug_assertions))]
6531 if self.is_inspector_picking(cx) {
6532 self.handle_inspector_mouse_event(event, cx);
6533 return;
6535 }
6536
6537 let mut mouse_listeners = mem::take(&mut self.frame_state.rendered_frame.mouse_listeners);
6538
6539 for listener in &mut mouse_listeners {
6542 let listener = listener.as_mut().unwrap();
6543 listener(event, DispatchPhase::Capture, self, cx);
6544 if !cx.propagate_event {
6545 break;
6546 }
6547 }
6548
6549 if cx.propagate_event {
6551 for listener in mouse_listeners.iter_mut().rev() {
6552 let listener = listener.as_mut().unwrap();
6553 listener(event, DispatchPhase::Bubble, self, cx);
6554 if !cx.propagate_event {
6555 break;
6556 }
6557 }
6558 }
6559
6560 self.frame_state.rendered_frame.mouse_listeners = mouse_listeners;
6561
6562 if cx.has_active_drag() {
6563 if event.is::<MouseMoveEvent>() {
6564 self.refresh();
6567 } else if event.is::<MouseUpEvent>() {
6568 cx.active_drag = None;
6571 self.refresh();
6572 }
6573 }
6574
6575 if event.is::<MouseUpEvent>() && self.core.captured_hitbox.is_some() {
6577 self.core.captured_hitbox = None;
6578 }
6579 }
6580
6581 fn input_preference(&mut self, event: &dyn Any, cx: &mut App) -> InputPreference {
6584 let prefer_character_input = event
6585 .downcast_ref::<KeyDownEvent>()
6586 .is_some_and(|key_down_event| key_down_event.prefer_character_input);
6587 if !prefer_character_input {
6588 return InputPreference::KeyBindings;
6589 }
6590 let Some(mut input_handler) = self.core.platform_window.take_input_handler() else {
6591 return InputPreference::KeyBindings;
6592 };
6593 let accepts_text_input = input_handler.accepts_text_input(self, cx);
6594 self.core.platform_window.set_input_handler(input_handler);
6595 if accepts_text_input {
6596 InputPreference::CharacterInput
6597 } else {
6598 InputPreference::KeyBindings
6599 }
6600 }
6601
6602 fn dispatch_key_event(&mut self, event: &dyn Any, cx: &mut App) {
6603 if self.core.invalidator.is_dirty() {
6604 self.draw(cx).clear(cx);
6605 }
6606
6607 let node_id = self.focus_node_id_in_rendered_frame(self.core.focus);
6608 let dispatch_path = self
6609 .frame_state
6610 .rendered_frame
6611 .dispatch_tree
6612 .dispatch_path(node_id);
6613
6614 let mut keystroke: Option<Keystroke> = None;
6615
6616 if let Some(event) = event.downcast_ref::<ModifiersChangedEvent>() {
6617 if event.modifiers.number_of_modifiers() == 0
6618 && self.core.pending_modifier.modifiers.number_of_modifiers() == 1
6619 && !self.core.pending_modifier.saw_other_input
6620 {
6621 let key = match self.core.pending_modifier.modifiers {
6622 modifiers if modifiers.shift => Some("shift"),
6623 modifiers if modifiers.control => Some("control"),
6624 modifiers if modifiers.alt => Some("alt"),
6625 modifiers if modifiers.platform => Some("platform"),
6626 modifiers if modifiers.function => Some("function"),
6627 _ => None,
6628 };
6629 if let Some(key) = key {
6630 keystroke = Some(Keystroke {
6631 key: key.to_string(),
6632 key_char: None,
6633 modifiers: Modifiers::default(),
6634 });
6635 }
6636 }
6637
6638 if self.core.pending_modifier.modifiers.number_of_modifiers() == 0
6639 && event.modifiers.number_of_modifiers() == 1
6640 {
6641 self.core.pending_modifier.saw_other_input = false
6642 } else if event.modifiers.number_of_modifiers() > 1 {
6643 self.core.pending_modifier.saw_other_input = true
6644 }
6645 self.core.pending_modifier.modifiers = event.modifiers
6646 } else if let Some(key_down_event) = event.downcast_ref::<KeyDownEvent>() {
6647 self.core.pending_modifier.saw_other_input = true;
6648 keystroke = Some(key_down_event.keystroke.clone());
6649 if key_down_event.keystroke.key_char.is_some()
6650 && matches!(
6651 cx.cursor_hide_mode,
6652 CursorHideMode::OnTyping | CursorHideMode::OnTypingAndAction
6653 )
6654 {
6655 cx.platform.hide_cursor_until_mouse_moves();
6656 }
6657 }
6658
6659 let Some(keystroke) = keystroke else {
6660 self.finish_dispatch_key_event(
6661 event,
6662 None,
6663 InputPreference::KeyBindings,
6664 dispatch_path,
6665 self.context_stack(),
6666 cx,
6667 );
6668 return;
6669 };
6670
6671 let input_preference = self.input_preference(event, cx);
6672
6673 cx.propagate_event = true;
6674 self.dispatch_keystroke_interceptors(
6675 &keystroke,
6676 input_preference,
6677 self.context_stack(),
6678 cx,
6679 );
6680 if !cx.propagate_event {
6681 self.finish_dispatch_key_event(
6682 event,
6683 Some(&keystroke),
6684 input_preference,
6685 dispatch_path,
6686 self.context_stack(),
6687 cx,
6688 );
6689 return;
6690 }
6691
6692 let mut currently_pending = self.core.pending_input.take().unwrap_or_default();
6693 if currently_pending.focus.is_some() && currently_pending.focus != self.core.focus {
6694 currently_pending = PendingInput::default();
6695 }
6696
6697 let match_result = self.frame_state.rendered_frame.dispatch_tree.dispatch_key(
6698 currently_pending.keystrokes,
6699 keystroke.clone(),
6700 &dispatch_path,
6701 );
6702
6703 if !match_result.to_replay.is_empty() {
6704 self.replay_pending_input(match_result.to_replay, cx);
6705 cx.propagate_event = true;
6706 }
6707
6708 if !match_result.pending.is_empty() {
6709 let previous_timeout = currently_pending.timeout.take();
6710 currently_pending.keystrokes = match_result.pending;
6711 currently_pending.focus = self.core.focus;
6712
6713 let text_input_requires_timeout = event
6714 .downcast_ref::<KeyDownEvent>()
6715 .filter(|key_down| key_down.keystroke.key_char.is_some())
6716 .and_then(|_| self.core.platform_window.take_input_handler())
6717 .map_or(false, |mut input_handler| {
6718 let accepts = input_handler.accepts_text_input(self, cx);
6719 self.core.platform_window.set_input_handler(input_handler);
6720 accepts
6721 });
6722
6723 let needs_timeout = previous_timeout.is_some()
6724 || match_result.pending_has_binding
6725 || text_input_requires_timeout;
6726 currently_pending.timeout = if needs_timeout {
6727 match previous_timeout {
6728 Some(mut timeout) if timeout.is_paused() => {
6729 timeout.reset_duration(PENDING_INPUT_TIMEOUT);
6730 Some(timeout)
6731 }
6732 previous_timeout => {
6733 drop(previous_timeout);
6734 Some(self.new_pending_input_timeout(PENDING_INPUT_TIMEOUT, cx))
6735 }
6736 }
6737 } else {
6738 None
6739 };
6740 self.core.pending_input = Some(currently_pending);
6741 self.pending_input_changed(cx);
6742 cx.propagate_event = false;
6743 return;
6744 }
6745
6746 let input_preference = self.input_preference(event, cx);
6748 if input_preference == InputPreference::KeyBindings {
6749 for binding in match_result.bindings {
6750 self.dispatch_action_on_node(node_id, binding.action.as_ref(), cx);
6751 if !cx.propagate_event {
6752 self.dispatch_keystroke_observers(
6753 &keystroke,
6754 input_preference,
6755 Some(binding.action.as_ref()),
6756 match_result.context_stack,
6757 cx,
6758 );
6759 self.pending_input_changed(cx);
6760 return;
6761 }
6762 }
6763 }
6764
6765 self.finish_dispatch_key_event(
6766 event,
6767 Some(&keystroke),
6768 input_preference,
6769 dispatch_path,
6770 match_result.context_stack,
6771 cx,
6772 );
6773 self.pending_input_changed(cx);
6774 }
6775
6776 fn new_pending_input_timeout(&self, duration: Duration, cx: &App) -> PendingInputTimeout {
6777 let (started_at, task) = self.start_pending_input_timeout(duration, cx);
6778 PendingInputTimeout {
6779 duration,
6780 remaining: duration,
6781 state: PendingInputTimeoutState::Running { started_at, task },
6782 }
6783 }
6784
6785 fn start_pending_input_timeout(&self, remaining: Duration, cx: &App) -> (Instant, Task<()>) {
6786 let started_at = cx.background_executor().now();
6787 let task = self.spawn(cx, async move |cx| {
6788 cx.background_executor.timer(remaining).await;
6789 cx.update(move |window, cx| {
6790 let Some(currently_pending) = window
6791 .core
6792 .pending_input
6793 .take()
6794 .filter(|pending| pending.focus == window.core.focus)
6795 else {
6796 return;
6797 };
6798
6799 let node_id = window.focus_node_id_in_rendered_frame(window.core.focus);
6800 let dispatch_path = window
6801 .frame_state
6802 .rendered_frame
6803 .dispatch_tree
6804 .dispatch_path(node_id);
6805
6806 let to_replay = window
6807 .frame_state
6808 .rendered_frame
6809 .dispatch_tree
6810 .flush_dispatch(currently_pending.keystrokes, &dispatch_path);
6811
6812 window.pending_input_changed(cx);
6813 window.replay_pending_input(to_replay, cx)
6814 })
6815 .log_err();
6816 });
6817 (started_at, task)
6818 }
6819
6820 fn finish_dispatch_key_event(
6821 &mut self,
6822 event: &dyn Any,
6823 recognized_keystroke: Option<&Keystroke>,
6824 input_preference: InputPreference,
6825 dispatch_path: SmallVec<[DispatchNodeId; 32]>,
6826 context_stack: Vec<KeyContext>,
6827 cx: &mut App,
6828 ) {
6829 self.dispatch_key_down_up_event(event, &dispatch_path, cx);
6830 if !cx.propagate_event {
6831 return;
6832 }
6833
6834 self.dispatch_modifiers_changed_event(event, &dispatch_path, cx);
6835 if !cx.propagate_event {
6836 return;
6837 }
6838
6839 if let Some(keystroke) = recognized_keystroke {
6840 self.dispatch_keystroke_observers(keystroke, input_preference, None, context_stack, cx);
6841 }
6842 }
6843
6844 pub(crate) fn pending_input_changed(&mut self, cx: &mut App) {
6845 self.core
6846 .pending_input_observers
6847 .clone()
6848 .retain(&(), |callback| callback(self, cx));
6849 }
6850
6851 fn defer_pending_input_changed(&self, cx: &mut App) {
6852 let window_handle = self.core.handle;
6855 cx.defer(move |cx| {
6856 window_handle
6857 .update(cx, |_, window, cx| {
6858 window.pending_input_changed(cx);
6859 })
6860 .ok();
6861 });
6862 }
6863
6864 fn dispatch_key_down_up_event(
6865 &mut self,
6866 event: &dyn Any,
6867 dispatch_path: &SmallVec<[DispatchNodeId; 32]>,
6868 cx: &mut App,
6869 ) {
6870 for node_id in dispatch_path {
6872 let node = self.frame_state.rendered_frame.dispatch_tree.node(*node_id);
6873
6874 for key_listener in node.key_listeners.clone() {
6875 key_listener(event, DispatchPhase::Capture, self, cx);
6876 if !cx.propagate_event {
6877 return;
6878 }
6879 }
6880 }
6881
6882 for node_id in dispatch_path.iter().rev() {
6884 let node = self.frame_state.rendered_frame.dispatch_tree.node(*node_id);
6886 for key_listener in node.key_listeners.clone() {
6887 key_listener(event, DispatchPhase::Bubble, self, cx);
6888 if !cx.propagate_event {
6889 return;
6890 }
6891 }
6892 }
6893 }
6894
6895 fn dispatch_modifiers_changed_event(
6896 &mut self,
6897 event: &dyn Any,
6898 dispatch_path: &SmallVec<[DispatchNodeId; 32]>,
6899 cx: &mut App,
6900 ) {
6901 let Some(event) = event.downcast_ref::<ModifiersChangedEvent>() else {
6902 return;
6903 };
6904 for node_id in dispatch_path.iter().rev() {
6905 let node = self.frame_state.rendered_frame.dispatch_tree.node(*node_id);
6906 for listener in node.modifiers_changed_listeners.clone() {
6907 listener(event, self, cx);
6908 if !cx.propagate_event {
6909 return;
6910 }
6911 }
6912 }
6913 }
6914
6915 pub fn has_pending_keystrokes(&self) -> bool {
6917 self.pending_input().is_some()
6918 }
6919
6920 #[cfg(test)]
6921 pub(crate) fn pending_input_is_none(&self) -> bool {
6922 self.core.pending_input.is_none()
6923 }
6924
6925 pub(crate) fn clear_pending_keystrokes(&mut self, cx: &mut App) {
6926 if self.core.pending_input.take().is_some() {
6927 self.defer_pending_input_changed(cx);
6928 }
6929 }
6930
6931 pub fn pending_input(&self) -> Option<PendingInputStatus<'_>> {
6934 self.core
6935 .pending_input
6936 .as_ref()
6937 .filter(|pending_input| pending_input.focus == self.core.focus)
6938 .map(|pending_input| PendingInputStatus {
6939 keystrokes: pending_input.keystrokes.as_slice(),
6940 timeout: pending_input
6941 .timeout
6942 .as_ref()
6943 .map(PendingInputTimeout::status),
6944 })
6945 }
6946
6947 pub fn set_pending_input_timeout_paused<T: 'static>(
6952 &mut self,
6953 owner: &Entity<T>,
6954 paused: bool,
6955 cx: &mut App,
6956 ) -> bool {
6957 let owner_id = owner.entity_id();
6958 if !paused {
6959 return self.resume_pending_input_timeout(owner_id, cx);
6960 }
6961
6962 let timeout = self
6963 .core
6964 .pending_input
6965 .as_ref()
6966 .filter(|pending_input| pending_input.focus == self.core.focus)
6967 .and_then(|pending_input| pending_input.timeout.as_ref());
6968 let Some(timeout) = timeout else {
6969 return false;
6970 };
6971 if timeout.is_paused() {
6972 return false;
6973 }
6974
6975 let release_subscription = self.observe_release(owner, cx, move |_, window, cx| {
6976 window.resume_pending_input_timeout(owner_id, cx);
6977 });
6978 let now = cx.background_executor().now();
6979 let changed = self
6980 .core
6981 .pending_input
6982 .as_mut()
6983 .filter(|pending_input| pending_input.focus == self.core.focus)
6984 .and_then(|pending_input| pending_input.timeout.as_mut())
6985 .is_some_and(|timeout| {
6986 timeout.pause(
6987 PendingInputTimeoutPause {
6988 owner_id,
6989 _release_subscription: release_subscription,
6990 },
6991 now,
6992 )
6993 });
6994
6995 if changed {
6996 self.defer_pending_input_changed(cx);
6997 }
6998 changed
6999 }
7000
7001 fn resume_pending_input_timeout(&mut self, owner_id: EntityId, cx: &mut App) -> bool {
7002 let Some(remaining) = self
7003 .core
7004 .pending_input
7005 .as_ref()
7006 .and_then(|pending_input| pending_input.timeout.as_ref())
7007 .filter(|timeout| timeout.pause_owner_id() == Some(owner_id))
7008 .map(|timeout| timeout.remaining)
7009 else {
7010 return false;
7011 };
7012
7013 let (started_at, task) = self.start_pending_input_timeout(remaining, cx);
7014 let changed = self
7015 .core
7016 .pending_input
7017 .as_mut()
7018 .and_then(|pending_input| pending_input.timeout.as_mut())
7019 .is_some_and(|timeout| timeout.resume(owner_id, started_at, task));
7020
7021 if changed {
7022 self.defer_pending_input_changed(cx);
7023 }
7024 changed
7025 }
7026
7027 pub fn pending_input_keystrokes(&self) -> Option<&[Keystroke]> {
7029 self.pending_input()
7030 .map(|pending_input| pending_input.keystrokes())
7031 }
7032
7033 fn replay_pending_input(&mut self, replays: SmallVec<[Replay; 1]>, cx: &mut App) {
7034 let node_id = self.focus_node_id_in_rendered_frame(self.core.focus);
7035 let dispatch_path = self
7036 .frame_state
7037 .rendered_frame
7038 .dispatch_tree
7039 .dispatch_path(node_id);
7040
7041 'replay: for replay in replays {
7042 let event = KeyDownEvent {
7043 keystroke: replay.keystroke.clone(),
7044 is_held: false,
7045 prefer_character_input: true,
7046 };
7047
7048 cx.propagate_event = true;
7049 for binding in replay.bindings {
7050 self.dispatch_action_on_node(node_id, binding.action.as_ref(), cx);
7051 if !cx.propagate_event {
7052 self.dispatch_keystroke_observers(
7053 &replay.keystroke,
7054 InputPreference::KeyBindings,
7055 Some(binding.action.as_ref()),
7056 Vec::default(),
7057 cx,
7058 );
7059 continue 'replay;
7060 }
7061 }
7062
7063 self.dispatch_key_down_up_event(&event, &dispatch_path, cx);
7064 if !cx.propagate_event {
7065 continue 'replay;
7066 }
7067 if let Some(input) = replay.keystroke.key_char.as_ref().cloned()
7068 && let Some(mut input_handler) = self.core.platform_window.take_input_handler()
7069 {
7070 input_handler.dispatch_input(&input, self, cx);
7071 self.core.platform_window.set_input_handler(input_handler)
7072 }
7073 }
7074 }
7075
7076 fn focus_node_id_in_rendered_frame(&self, focus_id: Option<FocusId>) -> DispatchNodeId {
7077 focus_id
7078 .and_then(|focus_id| {
7079 self.frame_state
7080 .rendered_frame
7081 .dispatch_tree
7082 .focusable_node_id(focus_id)
7083 })
7084 .unwrap_or_else(|| self.frame_state.rendered_frame.dispatch_tree.root_node_id())
7085 }
7086
7087 fn dispatch_action_on_node(
7088 &mut self,
7089 node_id: DispatchNodeId,
7090 action: &dyn Action,
7091 cx: &mut App,
7092 ) {
7093 self.dispatch_action_on_node_inner(node_id, action, cx);
7094
7095 if !cx.propagate_event
7096 && cx.cursor_hide_mode == CursorHideMode::OnTypingAndAction
7097 && self.last_input_was_keyboard()
7098 {
7099 cx.platform.hide_cursor_until_mouse_moves();
7100 }
7101 }
7102
7103 fn dispatch_action_on_node_inner(
7104 &mut self,
7105 node_id: DispatchNodeId,
7106 action: &dyn Action,
7107 cx: &mut App,
7108 ) {
7109 let dispatch_path = self
7110 .frame_state
7111 .rendered_frame
7112 .dispatch_tree
7113 .dispatch_path(node_id);
7114
7115 cx.propagate_event = true;
7117 if let Some(mut global_listeners) = cx
7118 .global_action_listeners
7119 .remove(&action.as_any().type_id())
7120 {
7121 for listener in &global_listeners {
7122 #[cfg(feature = "profiler")]
7123 self.core.window_profiler.begin_action_handler(action, cx);
7124 listener(action.as_any(), DispatchPhase::Capture, cx);
7125 #[cfg(feature = "profiler")]
7126 self.core.window_profiler.end_action_handler();
7127 if !cx.propagate_event {
7128 break;
7129 }
7130 }
7131
7132 global_listeners.extend(
7133 cx.global_action_listeners
7134 .remove(&action.as_any().type_id())
7135 .unwrap_or_default(),
7136 );
7137
7138 cx.global_action_listeners
7139 .insert(action.as_any().type_id(), global_listeners);
7140 }
7141
7142 if !cx.propagate_event {
7143 return;
7144 }
7145
7146 for node_id in &dispatch_path {
7148 let node = self.frame_state.rendered_frame.dispatch_tree.node(*node_id);
7149 for DispatchActionListener {
7150 action_type,
7151 listener,
7152 } in node.action_listeners.clone()
7153 {
7154 let any_action = action.as_any();
7155 if action_type == any_action.type_id() {
7156 #[cfg(feature = "profiler")]
7157 self.core.window_profiler.begin_action_handler(action, cx);
7158 listener(any_action, DispatchPhase::Capture, self, cx);
7159 #[cfg(feature = "profiler")]
7160 self.core.window_profiler.end_action_handler();
7161
7162 if !cx.propagate_event {
7163 return;
7164 }
7165 }
7166 }
7167 }
7168
7169 for node_id in dispatch_path.iter().rev() {
7171 let node = self.frame_state.rendered_frame.dispatch_tree.node(*node_id);
7172 for DispatchActionListener {
7173 action_type,
7174 listener,
7175 } in node.action_listeners.clone()
7176 {
7177 let any_action = action.as_any();
7178 if action_type == any_action.type_id() {
7179 cx.propagate_event = false; #[cfg(feature = "profiler")]
7181 self.core.window_profiler.begin_action_handler(action, cx);
7182 listener(any_action, DispatchPhase::Bubble, self, cx);
7183 #[cfg(feature = "profiler")]
7184 self.core.window_profiler.end_action_handler();
7185
7186 if !cx.propagate_event {
7187 return;
7188 }
7189 }
7190 }
7191 }
7192
7193 if let Some(mut global_listeners) = cx
7195 .global_action_listeners
7196 .remove(&action.as_any().type_id())
7197 {
7198 for listener in global_listeners.iter().rev() {
7199 cx.propagate_event = false; #[cfg(feature = "profiler")]
7202 self.core.window_profiler.begin_action_handler(action, cx);
7203 listener(action.as_any(), DispatchPhase::Bubble, cx);
7204 #[cfg(feature = "profiler")]
7205 self.core.window_profiler.end_action_handler();
7206 if !cx.propagate_event {
7207 break;
7208 }
7209 }
7210
7211 global_listeners.extend(
7212 cx.global_action_listeners
7213 .remove(&action.as_any().type_id())
7214 .unwrap_or_default(),
7215 );
7216
7217 cx.global_action_listeners
7218 .insert(action.as_any().type_id(), global_listeners);
7219 }
7220 }
7221
7222 pub fn observe_global<G: Global>(
7225 &mut self,
7226 cx: &mut App,
7227 f: impl Fn(&mut Window, &mut App) + 'static,
7228 ) -> Subscription {
7229 let window_handle = self.core.handle;
7230 let (subscription, activate) = cx.global_observers.insert(
7231 TypeId::of::<G>(),
7232 Box::new(move |cx| {
7233 window_handle
7234 .update(cx, |_, window, cx| f(window, cx))
7235 .is_ok()
7236 }),
7237 );
7238 cx.defer(move |_| activate());
7239 subscription
7240 }
7241
7242 pub fn activate_window(&self) {
7244 self.core.platform_window.activate();
7245 }
7246
7247 pub fn request_attention(&self) {
7249 self.core.platform_window.request_attention();
7250 }
7251
7252 pub fn minimize_window(&self) {
7254 self.core.platform_window.minimize();
7255 }
7256
7257 pub fn toggle_fullscreen(&self) {
7259 self.core.platform_window.toggle_fullscreen();
7260 }
7261
7262 pub fn toggle_simple_fullscreen(&self) {
7267 self.core.platform_window.toggle_simple_fullscreen();
7268 }
7269
7270 pub fn invalidate_character_coordinates(&self) {
7272 self.on_next_frame(|window, cx| {
7273 if let Some(mut input_handler) = window.core.platform_window.take_input_handler() {
7274 if let Some(bounds) = input_handler.selected_bounds(window, cx) {
7275 window.core.platform_window.update_ime_position(bounds);
7276 }
7277 window.core.platform_window.set_input_handler(input_handler);
7278 }
7279 });
7280 }
7281
7282 pub fn prompt<T>(
7286 &mut self,
7287 level: PromptLevel,
7288 message: &str,
7289 detail: Option<&str>,
7290 answers: &[T],
7291 cx: &mut App,
7292 ) -> oneshot::Receiver<usize>
7293 where
7294 T: Clone + Into<PromptButton>,
7295 {
7296 let prompt_builder = cx.prompt_builder.take();
7297 let Some(prompt_builder) = prompt_builder else {
7298 unreachable!("Re-entrant window prompting is not supported by GPUI");
7299 };
7300
7301 let answers = answers
7302 .iter()
7303 .map(|answer| answer.clone().into())
7304 .collect::<Vec<_>>();
7305
7306 let receiver = match &prompt_builder {
7307 PromptBuilder::Default => self
7308 .core
7309 .platform_window
7310 .prompt(level, message, detail, &answers)
7311 .unwrap_or_else(|| {
7312 self.build_custom_prompt(&prompt_builder, level, message, detail, &answers, cx)
7313 }),
7314 PromptBuilder::Custom(_) => {
7315 self.build_custom_prompt(&prompt_builder, level, message, detail, &answers, cx)
7316 }
7317 };
7318
7319 cx.prompt_builder = Some(prompt_builder);
7320
7321 receiver
7322 }
7323
7324 fn build_custom_prompt(
7325 &mut self,
7326 prompt_builder: &PromptBuilder,
7327 level: PromptLevel,
7328 message: &str,
7329 detail: Option<&str>,
7330 answers: &[PromptButton],
7331 cx: &mut App,
7332 ) -> oneshot::Receiver<usize> {
7333 let (sender, receiver) = oneshot::channel();
7334 let handle = PromptHandle::new(sender);
7335 let handle = (prompt_builder)(level, message, detail, answers, handle, self, cx);
7336 self.core.prompt = Some(handle);
7337 receiver
7338 }
7339
7340 pub fn has_active_prompt(&self) -> bool {
7345 self.core.prompt.is_some()
7346 }
7347
7348 pub fn context_stack(&self) -> Vec<KeyContext> {
7350 let node_id = self.focus_node_id_in_rendered_frame(self.core.focus);
7351 let dispatch_tree = &self.frame_state.rendered_frame.dispatch_tree;
7352 dispatch_tree
7353 .dispatch_path(node_id)
7354 .iter()
7355 .filter_map(move |&node_id| dispatch_tree.node(node_id).context.clone())
7356 .collect()
7357 }
7358
7359 pub fn available_actions(&self, cx: &App) -> Vec<Box<dyn Action>> {
7361 let node_id = self.focus_node_id_in_rendered_frame(self.core.focus);
7362 let mut actions = self
7363 .frame_state
7364 .rendered_frame
7365 .dispatch_tree
7366 .available_actions(node_id);
7367 for action_type in cx.global_action_listeners.keys() {
7368 if let Err(ix) = actions.binary_search_by_key(action_type, |a| a.as_any().type_id()) {
7369 let action = cx.actions.build_action_type(action_type).ok();
7370 if let Some(action) = action {
7371 actions.insert(ix, action);
7372 }
7373 }
7374 }
7375 actions
7376 }
7377
7378 pub fn bindings_for_action(&self, action: &dyn Action) -> Vec<KeyBinding> {
7381 self.frame_state
7382 .rendered_frame
7383 .dispatch_tree
7384 .bindings_for_action(
7385 action,
7386 &self.frame_state.rendered_frame.dispatch_tree.context_stack,
7387 )
7388 }
7389
7390 pub fn highest_precedence_binding_for_action(&self, action: &dyn Action) -> Option<KeyBinding> {
7393 self.frame_state
7394 .rendered_frame
7395 .dispatch_tree
7396 .highest_precedence_binding_for_action(
7397 action,
7398 &self.frame_state.rendered_frame.dispatch_tree.context_stack,
7399 )
7400 }
7401
7402 pub fn bindings_for_action_in_context(
7404 &self,
7405 action: &dyn Action,
7406 context: KeyContext,
7407 ) -> Vec<KeyBinding> {
7408 let dispatch_tree = &self.frame_state.rendered_frame.dispatch_tree;
7409 dispatch_tree.bindings_for_action(action, &[context])
7410 }
7411
7412 pub fn highest_precedence_binding_for_action_in_context(
7415 &self,
7416 action: &dyn Action,
7417 context: KeyContext,
7418 ) -> Option<KeyBinding> {
7419 let dispatch_tree = &self.frame_state.rendered_frame.dispatch_tree;
7420 dispatch_tree.highest_precedence_binding_for_action(action, &[context])
7421 }
7422
7423 pub fn bindings_for_action_in(
7427 &self,
7428 action: &dyn Action,
7429 focus_handle: &FocusHandle,
7430 ) -> Vec<KeyBinding> {
7431 let dispatch_tree = &self.frame_state.rendered_frame.dispatch_tree;
7432 let Some(context_stack) = self.context_stack_for_focus_handle(focus_handle) else {
7433 return vec![];
7434 };
7435 dispatch_tree.bindings_for_action(action, &context_stack)
7436 }
7437
7438 pub fn highest_precedence_binding_for_action_in(
7442 &self,
7443 action: &dyn Action,
7444 focus_handle: &FocusHandle,
7445 ) -> Option<KeyBinding> {
7446 let dispatch_tree = &self.frame_state.rendered_frame.dispatch_tree;
7447 let context_stack = self.context_stack_for_focus_handle(focus_handle)?;
7448 dispatch_tree.highest_precedence_binding_for_action(action, &context_stack)
7449 }
7450
7451 pub fn possible_bindings_for_input(&self, input: &[Keystroke]) -> Vec<KeyBinding> {
7453 self.frame_state
7454 .rendered_frame
7455 .dispatch_tree
7456 .possible_next_bindings_for_input(input, &self.context_stack())
7457 }
7458
7459 fn context_stack_for_focus_handle(
7460 &self,
7461 focus_handle: &FocusHandle,
7462 ) -> Option<Vec<KeyContext>> {
7463 let dispatch_tree = &self.frame_state.rendered_frame.dispatch_tree;
7464 let node_id = dispatch_tree.focusable_node_id(focus_handle.id)?;
7465 let context_stack: Vec<_> = dispatch_tree
7466 .dispatch_path(node_id)
7467 .into_iter()
7468 .filter_map(|node_id| dispatch_tree.node(node_id).context.clone())
7469 .collect();
7470 Some(context_stack)
7471 }
7472
7473 pub fn listener_for<T: 'static, E>(
7475 &self,
7476 view: &Entity<T>,
7477 f: impl Fn(&mut T, &E, &mut Window, &mut Context<T>) + 'static,
7478 ) -> impl Fn(&E, &mut Window, &mut App) + 'static {
7479 let view = view.downgrade();
7480 move |e: &E, window: &mut Window, cx: &mut App| {
7481 view.update(cx, |view, cx| f(view, e, window, cx)).ok();
7482 }
7483 }
7484
7485 pub fn handler_for<E: 'static, Callback: Fn(&mut E, &mut Window, &mut Context<E>) + 'static>(
7487 &self,
7488 entity: &Entity<E>,
7489 f: Callback,
7490 ) -> impl Fn(&mut Window, &mut App) + 'static {
7491 let entity = entity.downgrade();
7492 move |window: &mut Window, cx: &mut App| {
7493 entity.update(cx, |entity, cx| f(entity, window, cx)).ok();
7494 }
7495 }
7496
7497 pub fn on_window_should_close(
7500 &self,
7501 cx: &App,
7502 f: impl Fn(&mut Window, &mut App) -> bool + 'static,
7503 ) {
7504 let mut cx = self.to_async(cx);
7505 self.core.platform_window.on_should_close(Box::new(move || {
7506 cx.update(|window, cx| f(window, cx)).unwrap_or(true)
7507 }))
7508 }
7509
7510 pub fn on_action(
7519 &mut self,
7520 action_type: TypeId,
7521 listener: impl Fn(&dyn Any, DispatchPhase, &mut Window, &mut App) + 'static,
7522 ) {
7523 self.core.invalidator.debug_assert_paint();
7524
7525 self.frame_state
7526 .next_frame
7527 .dispatch_tree
7528 .on_action(action_type, Rc::new(listener));
7529 }
7530
7531 pub fn on_action_when(
7540 &mut self,
7541 condition: bool,
7542 action_type: TypeId,
7543 listener: impl Fn(&dyn Any, DispatchPhase, &mut Window, &mut App) + 'static,
7544 ) {
7545 self.core.invalidator.debug_assert_paint();
7546
7547 if condition {
7548 self.frame_state
7549 .next_frame
7550 .dispatch_tree
7551 .on_action(action_type, Rc::new(listener));
7552 }
7553 }
7554
7555 pub fn gpu_specs(&self) -> Option<GpuSpecs> {
7558 self.core.platform_window.gpu_specs()
7559 }
7560
7561 pub fn titlebar_double_click(&self) {
7564 self.core
7565 .platform_window
7566 .titlebar_double_click(self.core.is_resizable, self.core.is_minimizable);
7567 }
7568
7569 pub fn window_title(&self) -> String {
7572 self.core.platform_window.get_title()
7573 }
7574
7575 pub fn tabbed_windows(&self) -> Option<Vec<SystemWindowTab>> {
7578 self.core.platform_window.tabbed_windows()
7579 }
7580
7581 pub fn tab_bar_visible(&self) -> bool {
7584 self.core.platform_window.tab_bar_visible()
7585 }
7586
7587 pub fn merge_all_windows(&self) {
7590 self.core.platform_window.merge_all_windows()
7591 }
7592
7593 pub fn move_tab_to_new_window(&self) {
7596 self.core.platform_window.move_tab_to_new_window()
7597 }
7598
7599 pub fn toggle_window_tab_overview(&self) {
7602 self.core.platform_window.toggle_window_tab_overview()
7603 }
7604
7605 pub fn set_tabbing_identifier(&self, tabbing_identifier: Option<String>) {
7608 self.core
7609 .platform_window
7610 .set_tabbing_identifier(tabbing_identifier)
7611 }
7612
7613 pub fn play_system_bell(&self) {
7616 self.core.platform_window.play_system_bell()
7617 }
7618
7619 pub fn is_a11y_enabled(&self) -> bool {
7626 self.core.a11y.is_enabled()
7627 }
7628
7629 pub fn is_a11y_active(&self) -> bool {
7640 self.core.a11y.is_active()
7641 }
7642
7643 pub fn debug_a11y_tree_json(&self) -> Option<String> {
7645 self.core.a11y.debug_tree_json()
7646 }
7647
7648 pub fn on_a11y_action(
7654 &mut self,
7655 node_id: accesskit::NodeId,
7656 action: accesskit::Action,
7657 listener: impl FnMut(Option<&accesskit::ActionData>, &mut Window, &mut App) + 'static,
7658 ) {
7659 self.core
7660 .a11y
7661 .action_listeners
7662 .entry(node_id)
7663 .or_default()
7664 .push((action, Box::new(listener)));
7665 }
7666
7667 #[cfg(not(target_family = "wasm"))]
7668 pub(crate) fn handle_a11y_action(&mut self, request: accesskit::ActionRequest, cx: &mut App) {
7669 if let Some(mut listeners) = self.core.a11y.action_listeners.remove(&request.target_node) {
7672 let extra_data = request.data.as_ref();
7673 let mut matched = false;
7674 for (action, listener) in &mut listeners {
7675 if *action == request.action {
7676 listener(extra_data, self, cx);
7677 matched = true;
7678 }
7679 }
7680 self.core
7681 .a11y
7682 .action_listeners
7683 .insert(request.target_node, listeners);
7684 if matched {
7685 return;
7686 }
7687 }
7688
7689 match request.action {
7691 accesskit::Action::Click => {
7692 if let Some(bounds) = self
7693 .core
7694 .a11y
7695 .node_bounds
7696 .get(&request.target_node)
7697 .copied()
7698 {
7699 let center = bounds.center();
7700 let mouse_down = PlatformInput::MouseDown(crate::MouseDownEvent {
7701 button: MouseButton::Left,
7702 position: center,
7703 modifiers: Modifiers::default(),
7704 click_count: 1,
7705 first_mouse: false,
7706 });
7707 let mouse_up = PlatformInput::MouseUp(MouseUpEvent {
7708 button: MouseButton::Left,
7709 position: center,
7710 modifiers: Modifiers::default(),
7711 click_count: 1,
7712 });
7713 self.dispatch_event(mouse_down, cx);
7714 self.dispatch_event(mouse_up, cx);
7715 }
7716 }
7717 accesskit::Action::Focus => {
7718 if let Some(focus_id) = self.core.a11y.focus_ids.get(&request.target_node).copied()
7719 && let Some(handle) = FocusHandle::for_id(focus_id, &cx.focus_handles)
7720 {
7721 self.focus(&handle, cx);
7722 }
7723 }
7724 accesskit::Action::Blur => {
7725 self.blur(cx);
7726 }
7727 _ => {
7728 log::debug!(
7729 "Unhandled a11y action: {:?} on {:?}",
7730 request.action,
7731 request.target_node
7732 );
7733 }
7734 }
7735 }
7736
7737 #[cfg(any(feature = "inspector", debug_assertions))]
7739 pub fn toggle_inspector(&mut self, cx: &mut App) {
7740 self.core.inspector = match self.core.inspector {
7741 None => Some(cx.new(|_| Inspector::new())),
7742 Some(_) => {
7743 self.frame_state.rendered_frame.next_inspector_instance_ids = FxHashMap::default();
7744 self.frame_state.rendered_frame.inspector_hitboxes = FxHashMap::default();
7745 self.frame_state.next_frame.next_inspector_instance_ids = FxHashMap::default();
7746 self.frame_state.next_frame.inspector_hitboxes = FxHashMap::default();
7747 None
7748 }
7749 };
7750 self.refresh();
7751 }
7752
7753 pub fn is_inspector_picking(&self, _cx: &App) -> bool {
7755 #[cfg(any(feature = "inspector", debug_assertions))]
7756 {
7757 if let Some(inspector) = &self.core.inspector {
7758 return inspector.read(_cx).is_picking();
7759 }
7760 }
7761 false
7762 }
7763
7764 pub(crate) fn set_inspector_element_id(
7768 &mut self,
7769 inspector_element_id: Option<crate::InspectorElementId>,
7770 ) -> Option<crate::InspectorElementId> {
7771 std::mem::replace(
7772 &mut self.frame_state.inspector_element_id,
7773 inspector_element_id,
7774 )
7775 }
7776
7777 #[cfg(any(feature = "inspector", debug_assertions))]
7782 pub fn with_inspector_state<T: 'static, R>(
7783 &mut self,
7784 inspector_id: Option<&crate::InspectorElementId>,
7785 cx: &mut App,
7786 f: impl FnOnce(&mut Option<T>, &mut Self) -> R,
7787 ) -> Option<R> {
7788 let inspector_id = inspector_id?;
7789 let inspector = self.core.inspector.as_ref()?;
7790 if inspector.read(cx).active_element_id() != Some(inspector_id) {
7791 return None;
7792 }
7793 let inspector = inspector.clone();
7794 Some(inspector.update(cx, |inspector, _cx| {
7795 inspector.with_active_element_state(self, f)
7796 }))
7797 }
7798
7799 #[cfg(any(feature = "inspector", debug_assertions))]
7800 pub(crate) fn inspector_enabled(&self) -> bool {
7801 self.core.inspector.is_some()
7802 }
7803
7804 #[cfg(any(feature = "inspector", debug_assertions))]
7810 pub fn with_current_inspector_state<T: 'static, R>(
7811 &mut self,
7812 cx: &mut App,
7813 f: impl FnOnce(&mut Option<T>, &mut Self) -> R,
7814 ) -> Option<R> {
7815 let inspector_id = self.frame_state.inspector_element_id.clone();
7816 self.with_inspector_state(inspector_id.as_ref(), cx, f)
7817 }
7818
7819 #[cfg(any(feature = "inspector", debug_assertions))]
7820 pub(crate) fn build_inspector_element_id(
7821 &mut self,
7822 path: crate::InspectorElementPath,
7823 ) -> crate::InspectorElementId {
7824 self.core.invalidator.debug_assert_paint_or_prepaint();
7825 let path = Rc::new(path);
7826 let next_instance_id = self
7827 .frame_state
7828 .next_frame
7829 .next_inspector_instance_ids
7830 .entry(path.clone())
7831 .or_insert(0);
7832 let instance_id = *next_instance_id;
7833 *next_instance_id += 1;
7834 crate::InspectorElementId { path, instance_id }
7835 }
7836
7837 #[cfg(any(feature = "inspector", debug_assertions))]
7838 fn prepaint_inspector(&mut self, inspector_width: Pixels, cx: &mut App) -> Option<AnyElement> {
7839 if let Some(inspector) = self.core.inspector.take() {
7840 let mut inspector_element = AnyView::from(inspector.clone()).into_any_element();
7841 inspector_element.prepaint_as_root(
7842 point(self.core.viewport_size.width - inspector_width, px(0.0)),
7843 size(inspector_width, self.core.viewport_size.height).into(),
7844 self,
7845 cx,
7846 );
7847 self.core.inspector = Some(inspector);
7848 Some(inspector_element)
7849 } else {
7850 None
7851 }
7852 }
7853
7854 #[cfg(any(feature = "inspector", debug_assertions))]
7855 fn paint_inspector(&mut self, mut inspector_element: Option<AnyElement>, cx: &mut App) {
7856 if let Some(mut inspector_element) = inspector_element {
7857 inspector_element.paint(self, cx);
7858 };
7859 }
7860
7861 #[cfg(any(feature = "inspector", debug_assertions))]
7867 pub(crate) fn insert_inspector_hitbox(&mut self, hitbox_id: HitboxId, cx: &App) {
7868 self.core.invalidator.debug_assert_paint_or_prepaint();
7869 if !self.is_inspector_picking(cx) {
7870 return;
7871 }
7872 if let Some(inspector_id) = self.frame_state.inspector_element_id.clone() {
7873 self.frame_state
7874 .next_frame
7875 .inspector_hitboxes
7876 .insert(hitbox_id, inspector_id);
7877 }
7878 }
7879
7880 #[cfg(any(feature = "inspector", debug_assertions))]
7881 fn paint_inspector_hitbox(&mut self, cx: &App) {
7882 if let Some(inspector) = self.core.inspector.as_ref() {
7883 let inspector = inspector.read(cx);
7884 if let Some((hitbox_id, _)) =
7885 self.hovered_inspector_hitbox(inspector, &self.frame_state.next_frame)
7886 && let Some(hitbox) = self
7887 .frame_state
7888 .next_frame
7889 .hitboxes
7890 .iter()
7891 .find(|hitbox| hitbox.id == hitbox_id)
7892 {
7893 self.paint_quad(crate::fill(hitbox.bounds, crate::rgba(0x61afef4d)));
7894 }
7895 }
7896 }
7897
7898 #[cfg(any(feature = "inspector", debug_assertions))]
7899 fn handle_inspector_mouse_event(&mut self, event: &dyn Any, cx: &mut App) {
7900 let Some(inspector) = self.core.inspector.clone() else {
7901 return;
7902 };
7903 if event.downcast_ref::<MouseMoveEvent>().is_some() {
7904 inspector.update(cx, |inspector, _cx| {
7905 if let Some((_, inspector_id)) =
7906 self.hovered_inspector_hitbox(inspector, &self.frame_state.rendered_frame)
7907 {
7908 inspector.hover(inspector_id, self);
7909 }
7910 });
7911 } else if event.downcast_ref::<crate::MouseDownEvent>().is_some() {
7912 inspector.update(cx, |inspector, _cx| {
7913 if let Some((_, inspector_id)) =
7914 self.hovered_inspector_hitbox(inspector, &self.frame_state.rendered_frame)
7915 {
7916 inspector.select(inspector_id, self);
7917 }
7918 });
7919 } else if let Some(event) = event.downcast_ref::<crate::ScrollWheelEvent>() {
7920 const SCROLL_LINES: f32 = 3.0;
7922 const SCROLL_PIXELS_PER_LAYER: f32 = 36.0;
7923 let delta_y = event
7924 .delta
7925 .pixel_delta(px(SCROLL_PIXELS_PER_LAYER / SCROLL_LINES))
7926 .y;
7927 if let Some(inspector) = self.core.inspector.clone() {
7928 inspector.update(cx, |inspector, _cx| {
7929 if let Some(depth) = inspector.pick_depth.as_mut() {
7930 *depth += f32::from(delta_y) / SCROLL_PIXELS_PER_LAYER;
7931 let max_depth = self.core.mouse_hit_test.ids.len() as f32 - 0.5;
7932 if *depth < 0.0 {
7933 *depth = 0.0;
7934 } else if *depth > max_depth {
7935 *depth = max_depth;
7936 }
7937 if let Some((_, inspector_id)) = self
7938 .hovered_inspector_hitbox(inspector, &self.frame_state.rendered_frame)
7939 {
7940 inspector.set_active_element_id(inspector_id, self);
7941 }
7942 }
7943 });
7944 }
7945 }
7946 }
7947
7948 #[cfg(any(feature = "inspector", debug_assertions))]
7949 fn hovered_inspector_hitbox(
7950 &self,
7951 inspector: &Inspector,
7952 frame: &Frame,
7953 ) -> Option<(HitboxId, crate::InspectorElementId)> {
7954 if let Some(pick_depth) = inspector.pick_depth {
7955 let depth = (pick_depth as i64).try_into().unwrap_or(0);
7956 let max_skipped = self.core.mouse_hit_test.ids.len().saturating_sub(1);
7957 let skip_count = (depth as usize).min(max_skipped);
7958 for hitbox_id in self.core.mouse_hit_test.ids.iter().skip(skip_count) {
7959 if let Some(inspector_id) = frame.inspector_hitboxes.get(hitbox_id) {
7960 return Some((*hitbox_id, inspector_id.clone()));
7961 }
7962 }
7963 }
7964 None
7965 }
7966
7967 #[cfg(any(test, feature = "test-support"))]
7970 pub fn set_modifiers(&mut self, modifiers: Modifiers) {
7971 self.core.modifiers = modifiers;
7972 }
7973
7974 #[cfg(any(test, feature = "test-support"))]
7978 pub fn simulate_mouse_move(&mut self, position: Point<Pixels>, cx: &mut App) {
7979 let event = PlatformInput::MouseMove(MouseMoveEvent {
7980 position,
7981 modifiers: self.core.modifiers,
7982 pressed_button: None,
7983 });
7984 let _ = self.dispatch_event(event, cx);
7985 }
7986
7987 #[inline(never)]
7988 fn take_element_state(
7989 &mut self,
7990 global_id: &GlobalElementId,
7991 state_type: TypeId,
7992 ) -> ((GlobalElementId, TypeId), Option<ElementStateBox>) {
7993 let key = (global_id.clone(), state_type);
7994 self.frame_state
7995 .next_frame
7996 .accessed_element_states
7997 .push(key.clone());
7998 let state = self
7999 .frame_state
8000 .next_frame
8001 .element_states
8002 .remove(&key)
8003 .or_else(|| self.frame_state.rendered_frame.element_states.remove(&key));
8004 (key, state)
8005 }
8006
8007 #[inline(never)]
8008 fn insert_element_state(
8009 &mut self,
8010 key: (GlobalElementId, TypeId),
8011 state: ElementStateBox,
8012 ) -> Option<ElementStateBox> {
8013 self.frame_state
8014 .next_frame
8015 .element_states
8016 .insert(key, state)
8017 }
8018
8019 #[inline(never)]
8020 fn observe_keyed_state<S: 'static>(state: &Entity<S>, current_view: EntityId, cx: &mut App) {
8021 cx.observe(state, move |_, cx| {
8022 cx.notify(current_view);
8023 })
8024 .detach();
8025 }
8026}
8027
8028#[derive(Deref, DerefMut)]
8031pub struct WindowHandle<V> {
8032 #[deref]
8033 #[deref_mut]
8034 pub(crate) any_handle: AnyWindowHandle,
8035 state_type: PhantomData<fn(V) -> V>,
8036}
8037
8038impl<V> Debug for WindowHandle<V> {
8039 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
8040 f.debug_struct("WindowHandle")
8041 .field("any_handle", &self.any_handle.id.as_u64())
8042 .finish()
8043 }
8044}
8045
8046impl<V: 'static + Render> WindowHandle<V> {
8047 pub fn new(id: WindowId) -> Self {
8050 WindowHandle {
8051 any_handle: AnyWindowHandle {
8052 id,
8053 state_type: TypeId::of::<V>(),
8054 root_entity_type_name: std::any::type_name::<V>(),
8055 },
8056 state_type: PhantomData,
8057 }
8058 }
8059
8060 #[cfg(any(test, feature = "test-support"))]
8064 pub fn root<C>(&self, cx: &mut C) -> Result<Entity<V>>
8065 where
8066 C: AppContext,
8067 {
8068 cx.update_window(self.any_handle, |root_view, _, _| {
8069 root_view
8070 .downcast::<V>()
8071 .map_err(|_| anyhow!("the type of the window's root view has changed"))
8072 })?
8073 }
8074
8075 pub fn update<C, R>(
8079 &self,
8080 cx: &mut C,
8081 update: impl FnOnce(&mut V, &mut Window, &mut Context<V>) -> R,
8082 ) -> Result<R>
8083 where
8084 C: AppContext,
8085 {
8086 cx.update_window(self.any_handle, |root_view, window, cx| {
8087 let view = root_view
8088 .downcast::<V>()
8089 .map_err(|_| anyhow!("the type of the window's root view has changed"))?;
8090
8091 Ok(view.update(cx, |view, cx| update(view, window, cx)))
8092 })?
8093 }
8094
8095 pub fn read<'a>(&self, cx: &'a App) -> Result<&'a V> {
8099 let x = cx
8100 .windows
8101 .cell(self.id)
8102 .and_then(|cell| cell.borrow().core.root.clone())
8103 .map(|root_view| root_view.downcast::<V>())
8104 .context("window not found")?
8105 .map_err(|_| anyhow!("the type of the window's root view has changed"))?;
8106
8107 Ok(x.read(cx))
8108 }
8109
8110 pub fn read_with<C, R>(&self, cx: &C, read_with: impl FnOnce(&V, &App) -> R) -> Result<R>
8114 where
8115 C: AppContext,
8116 {
8117 cx.read_window(self, |root_view, cx| read_with(root_view.read(cx), cx))
8118 }
8119
8120 pub fn entity<C>(&self, cx: &C) -> Result<Entity<V>>
8124 where
8125 C: AppContext,
8126 {
8127 cx.read_window(self, |root_view, _cx| root_view)
8128 }
8129
8130 pub fn is_active(&self, cx: &mut App) -> Option<bool> {
8135 cx.update_window(self.any_handle, |_, window, _| window.is_window_active())
8136 .ok()
8137 }
8138}
8139
8140impl<V> Copy for WindowHandle<V> {}
8141
8142impl<V> Clone for WindowHandle<V> {
8143 fn clone(&self) -> Self {
8144 *self
8145 }
8146}
8147
8148impl<V> PartialEq for WindowHandle<V> {
8149 fn eq(&self, other: &Self) -> bool {
8150 self.any_handle == other.any_handle
8151 }
8152}
8153
8154impl<V> Eq for WindowHandle<V> {}
8155
8156impl<V> Hash for WindowHandle<V> {
8157 fn hash<H: Hasher>(&self, state: &mut H) {
8158 self.any_handle.hash(state);
8159 }
8160}
8161
8162impl<V: 'static> From<WindowHandle<V>> for AnyWindowHandle {
8163 fn from(val: WindowHandle<V>) -> Self {
8164 val.any_handle
8165 }
8166}
8167
8168#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
8170pub struct AnyWindowHandle {
8171 pub(crate) id: WindowId,
8172 state_type: TypeId,
8173 root_entity_type_name: &'static str,
8174}
8175
8176impl AnyWindowHandle {
8177 pub fn window_id(&self) -> WindowId {
8179 self.id
8180 }
8181
8182 pub fn metrics(&self, cx: &App) -> Option<WindowMetricsHandle> {
8189 cx.windows
8190 .cell(self.id)
8191 .map(|cell| cell.borrow().core.metrics_handle())
8192 }
8193
8194 pub fn root_entity_type_name(&self) -> &'static str {
8196 self.root_entity_type_name
8197 }
8198
8199 pub fn downcast<T: 'static>(&self) -> Option<WindowHandle<T>> {
8202 if TypeId::of::<T>() == self.state_type {
8203 Some(WindowHandle {
8204 any_handle: *self,
8205 state_type: PhantomData,
8206 })
8207 } else {
8208 None
8209 }
8210 }
8211
8212 pub fn update<C, R>(
8216 self,
8217 cx: &mut C,
8218 update: impl FnOnce(AnyView, &mut Window, &mut App) -> R,
8219 ) -> Result<R>
8220 where
8221 C: AppContext,
8222 {
8223 cx.update_window(self, update)
8224 }
8225
8226 pub fn read<T, C, R>(self, cx: &C, read: impl FnOnce(Entity<T>, &App) -> R) -> Result<R>
8230 where
8231 C: AppContext,
8232 T: 'static,
8233 {
8234 let view = self
8235 .downcast::<T>()
8236 .context("the type of the window's root view has changed")?;
8237
8238 cx.read_window(&view, read)
8239 }
8240}
8241
8242impl HasWindowHandle for Window<'_> {
8243 fn window_handle(&self) -> Result<raw_window_handle::WindowHandle<'_>, HandleError> {
8244 self.core.platform_window.window_handle()
8245 }
8246}
8247
8248impl HasDisplayHandle for Window<'_> {
8249 fn display_handle(
8250 &self,
8251 ) -> std::result::Result<raw_window_handle::DisplayHandle<'_>, HandleError> {
8252 self.core.platform_window.display_handle()
8253 }
8254}
8255
8256#[derive(Clone, Debug, Eq, PartialEq, Hash)]
8261pub enum ElementId {
8262 View(EntityId),
8264 Integer(u64),
8266 Name(SharedString),
8268 Uuid(Uuid),
8270 FocusHandle(FocusId),
8272 NamedInteger(SharedString, u64),
8274 Path(Arc<std::path::Path>),
8276 CodeLocation(core::panic::Location<'static>),
8278 NamedChild(Arc<ElementId>, SharedString),
8280 OpaqueId([u8; 20]),
8282}
8283
8284impl ElementId {
8285 pub fn named_usize(name: impl Into<SharedString>, integer: usize) -> ElementId {
8287 Self::NamedInteger(name.into(), integer as u64)
8288 }
8289}
8290
8291impl Display for ElementId {
8292 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
8293 match self {
8294 ElementId::View(entity_id) => write!(f, "view-{}", entity_id)?,
8295 ElementId::Integer(ix) => write!(f, "{}", ix)?,
8296 ElementId::Name(name) => write!(f, "{}", name)?,
8297 ElementId::FocusHandle(_) => write!(f, "FocusHandle")?,
8298 ElementId::NamedInteger(s, i) => write!(f, "{}-{}", s, i)?,
8299 ElementId::Uuid(uuid) => write!(f, "{}", uuid)?,
8300 ElementId::Path(path) => write!(f, "{}", path.display())?,
8301 ElementId::CodeLocation(location) => write!(f, "{}", location)?,
8302 ElementId::NamedChild(id, name) => write!(f, "{}-{}", id, name)?,
8303 ElementId::OpaqueId(opaque_id) => write!(f, "{:x?}", opaque_id)?,
8304 }
8305
8306 Ok(())
8307 }
8308}
8309
8310impl TryInto<SharedString> for ElementId {
8311 type Error = anyhow::Error;
8312
8313 fn try_into(self) -> anyhow::Result<SharedString> {
8314 if let ElementId::Name(name) = self {
8315 Ok(name)
8316 } else {
8317 anyhow::bail!("element id is not string")
8318 }
8319 }
8320}
8321
8322impl From<u64> for ElementId {
8323 fn from(id: u64) -> Self {
8324 ElementId::Integer(id)
8325 }
8326}
8327
8328impl From<usize> for ElementId {
8329 fn from(id: usize) -> Self {
8330 ElementId::Integer(id as u64)
8331 }
8332}
8333
8334impl From<i32> for ElementId {
8335 fn from(id: i32) -> Self {
8336 Self::Integer(id as u64)
8337 }
8338}
8339
8340impl From<SharedString> for ElementId {
8341 fn from(name: SharedString) -> Self {
8342 ElementId::Name(name)
8343 }
8344}
8345
8346impl From<String> for ElementId {
8347 fn from(name: String) -> Self {
8348 ElementId::Name(name.into())
8349 }
8350}
8351
8352impl From<Arc<str>> for ElementId {
8353 fn from(name: Arc<str>) -> Self {
8354 ElementId::Name(name.into())
8355 }
8356}
8357
8358impl From<Arc<std::path::Path>> for ElementId {
8359 fn from(path: Arc<std::path::Path>) -> Self {
8360 ElementId::Path(path)
8361 }
8362}
8363
8364impl From<&'static str> for ElementId {
8365 fn from(name: &'static str) -> Self {
8366 ElementId::Name(SharedString::new_static(name))
8367 }
8368}
8369
8370impl<'a> From<&'a FocusHandle> for ElementId {
8371 fn from(handle: &'a FocusHandle) -> Self {
8372 ElementId::FocusHandle(handle.id)
8373 }
8374}
8375
8376impl From<(&'static str, EntityId)> for ElementId {
8377 fn from((name, id): (&'static str, EntityId)) -> Self {
8378 ElementId::NamedInteger(SharedString::new_static(name), id.as_u64())
8379 }
8380}
8381
8382impl From<(&'static str, usize)> for ElementId {
8383 fn from((name, id): (&'static str, usize)) -> Self {
8384 ElementId::NamedInteger(SharedString::new_static(name), id as u64)
8385 }
8386}
8387
8388impl From<(SharedString, usize)> for ElementId {
8389 fn from((name, id): (SharedString, usize)) -> Self {
8390 ElementId::NamedInteger(name, id as u64)
8391 }
8392}
8393
8394impl From<(&'static str, u64)> for ElementId {
8395 fn from((name, id): (&'static str, u64)) -> Self {
8396 ElementId::NamedInteger(SharedString::new_static(name), id)
8397 }
8398}
8399
8400impl From<Uuid> for ElementId {
8401 fn from(value: Uuid) -> Self {
8402 Self::Uuid(value)
8403 }
8404}
8405
8406impl From<(&'static str, u32)> for ElementId {
8407 fn from((name, id): (&'static str, u32)) -> Self {
8408 ElementId::NamedInteger(SharedString::new_static(name), u64::from(id))
8409 }
8410}
8411
8412impl<T: Into<SharedString>> From<(ElementId, T)> for ElementId {
8413 fn from((id, name): (ElementId, T)) -> Self {
8414 ElementId::NamedChild(Arc::new(id), name.into())
8415 }
8416}
8417
8418impl From<&'static core::panic::Location<'static>> for ElementId {
8419 fn from(location: &'static core::panic::Location<'static>) -> Self {
8420 ElementId::CodeLocation(*location)
8421 }
8422}
8423
8424impl From<[u8; 20]> for ElementId {
8425 fn from(opaque_id: [u8; 20]) -> Self {
8426 ElementId::OpaqueId(opaque_id)
8427 }
8428}
8429
8430#[derive(Clone)]
8433pub struct PaintQuad {
8434 pub bounds: Bounds<Pixels>,
8436 pub corner_radii: Corners<Pixels>,
8438 pub background: Background,
8440 pub border_widths: Edges<Pixels>,
8442 pub border_color: Hsla,
8444 pub border_style: BorderStyle,
8446}
8447
8448impl PaintQuad {
8449 pub fn corner_radii(self, corner_radii: impl Into<Corners<Pixels>>) -> Self {
8451 PaintQuad {
8452 corner_radii: corner_radii.into(),
8453 ..self
8454 }
8455 }
8456
8457 pub fn border_widths(self, border_widths: impl Into<Edges<Pixels>>) -> Self {
8459 PaintQuad {
8460 border_widths: border_widths.into(),
8461 ..self
8462 }
8463 }
8464
8465 pub fn border_color(self, border_color: impl Into<Hsla>) -> Self {
8467 PaintQuad {
8468 border_color: border_color.into(),
8469 ..self
8470 }
8471 }
8472
8473 pub fn background(self, background: impl Into<Background>) -> Self {
8475 PaintQuad {
8476 background: background.into(),
8477 ..self
8478 }
8479 }
8480}
8481
8482pub fn quad(
8484 bounds: Bounds<Pixels>,
8485 corner_radii: impl Into<Corners<Pixels>>,
8486 background: impl Into<Background>,
8487 border_widths: impl Into<Edges<Pixels>>,
8488 border_color: impl Into<Hsla>,
8489 border_style: BorderStyle,
8490) -> PaintQuad {
8491 PaintQuad {
8492 bounds,
8493 corner_radii: corner_radii.into(),
8494 background: background.into(),
8495 border_widths: border_widths.into(),
8496 border_color: border_color.into(),
8497 border_style,
8498 }
8499}
8500
8501pub fn fill(bounds: impl Into<Bounds<Pixels>>, background: impl Into<Background>) -> PaintQuad {
8503 PaintQuad {
8504 bounds: bounds.into(),
8505 corner_radii: (0.).into(),
8506 background: background.into(),
8507 border_widths: (0.).into(),
8508 border_color: transparent_black(),
8509 border_style: BorderStyle::default(),
8510 }
8511}
8512
8513pub fn outline(
8515 bounds: impl Into<Bounds<Pixels>>,
8516 border_color: impl Into<Hsla>,
8517 border_style: BorderStyle,
8518) -> PaintQuad {
8519 PaintQuad {
8520 bounds: bounds.into(),
8521 corner_radii: (0.).into(),
8522 background: transparent_black().into(),
8523 border_widths: (1.).into(),
8524 border_color: border_color.into(),
8525 border_style,
8526 }
8527}
8528
8529#[inline(never)]
8530fn with_element_arena_erased(callback: &mut dyn FnMut(&mut Arena)) -> Result<(), AccessError> {
8531 if let Some(arena_pointer) = CURRENT_ELEMENT_ARENA.try_with(Cell::get)? {
8532 let arena_cell = unsafe { &*arena_pointer };
8535 callback(&mut arena_cell.borrow_mut());
8536 Ok(())
8537 } else {
8538 ELEMENT_ARENA.try_with(|arena| callback(&mut arena.borrow_mut()))
8539 }
8540}
8541
8542#[cfg(test)]
8543mod tests {
8544 use std::{
8545 cell::{Cell, RefCell},
8546 path::PathBuf,
8547 rc::Rc,
8548 time::Duration,
8549 };
8550
8551 use crate::{
8552 AnyWindowHandle, App, AppContext as _, ArenaClearNeeded, Bounds, ContentMask, Context,
8553 Corners, CustomRenderPrimitive, DispatchPhase, DragMoveEvent, Empty, ExternalDragPayload,
8554 ExternalPaths, FileDragPaths, FileDropEvent, FocusHandle, FocusId, FramePipeline,
8555 ImportedTextureHandle, InputEvent as _, InteractiveElement as _, IntoElement, KeyDownEvent,
8556 Keystroke, LongPressEvent, MouseButton, MouseDownEvent, MouseMoveEvent, ParentElement,
8557 Pixels, PlatformInput, Point, Render, RequestFrameOptions, ScaledPixels,
8558 StandardImmediatePipeline, StatefulInteractiveElement as _, Styled, TestAppContext,
8559 TouchDragEvent, TouchEvent, TouchId, TouchPhase, Underline, UnderlineStyle, Window,
8560 WindowAppearance, WindowMetrics, WindowOptions, canvas, div, gpu_canvas, hsla, point, px,
8561 size,
8562 };
8563
8564 #[gpui::test]
8568 fn test_window_visibility(cx: &mut TestAppContext) {
8569 use crate::WindowVisibility;
8570
8571 let window = cx.add_window(|_, _| EmptyView);
8572 let observed = Rc::new(RefCell::new(Vec::new()));
8573 let _subscription = window
8574 .update(cx, {
8575 let observed = observed.clone();
8576 move |_, window, _| {
8577 assert_eq!(window.visibility(), WindowVisibility::Visible);
8578 assert!(window.is_visible());
8579 window.observe_window_visibility(move |visibility, window, _| {
8580 assert_eq!(window.visibility(), visibility);
8581 observed.borrow_mut().push(visibility);
8582 })
8583 }
8584 })
8585 .unwrap();
8586 let test_window = cx.test_window(window.into());
8587 let frame_wake_count = test_window.frame_wake_count();
8588
8589 test_window.simulate_visibility_change(WindowVisibility::Hidden);
8590 assert_eq!(*observed.borrow(), [WindowVisibility::Hidden]);
8591 window
8592 .update(cx, |_, window, _| assert!(!window.is_visible()))
8593 .unwrap();
8594
8595 test_window.simulate_visibility_change(WindowVisibility::Hidden);
8597 assert_eq!(observed.borrow().len(), 1);
8598
8599 test_window.simulate_visibility_change(WindowVisibility::Visible);
8600 assert_eq!(
8601 *observed.borrow(),
8602 [WindowVisibility::Hidden, WindowVisibility::Visible]
8603 );
8604 window
8605 .update(cx, |_, window, _| assert!(window.is_visible()))
8606 .unwrap();
8607 assert_eq!(test_window.frame_wake_count(), frame_wake_count);
8608 }
8609
8610 #[gpui::test]
8613 fn a_window_draws_through_its_frame_pipeline(cx: &mut TestAppContext) {
8614 let recorded: Rc<RefCell<Vec<&'static str>>> = Rc::new(RefCell::new(Vec::new()));
8615 let recorder = recorded.clone();
8616 cx.update(move |cx| {
8617 cx.set_frame_pipeline_factory(Rc::new(move |_| {
8618 Box::new(RecordingPipeline(recorder.clone()))
8619 }));
8620 });
8621
8622 let window = cx.add_window(|_, _| EmptyView);
8623 recorded.borrow_mut().clear();
8624 cx.update_window(window.into(), |_, window, cx| window.draw(cx).clear(cx))
8625 .unwrap();
8626
8627 let phases = recorded.borrow();
8628 assert!(
8629 phases.starts_with(&[
8630 "begin_frame",
8631 "draw_roots",
8632 "finish_frame",
8633 "complete_frame",
8634 "end_frame"
8635 ]),
8636 "frame ran {phases:?}"
8637 );
8638 }
8639
8640 struct RecordingPipeline(Rc<RefCell<Vec<&'static str>>>);
8643
8644 impl FramePipeline for RecordingPipeline {
8645 fn begin_frame(&mut self, window: &mut Window, cx: &mut App) {
8646 self.0.borrow_mut().push("begin_frame");
8647 window.begin_frame(cx);
8648 }
8649
8650 fn draw_roots(&mut self, window: &mut Window, cx: &mut App) {
8651 self.0.borrow_mut().push("draw_roots");
8652 window.draw_roots(cx);
8653 }
8654
8655 fn finish_frame(&mut self, window: &mut Window, cx: &mut App) {
8656 self.0.borrow_mut().push("finish_frame");
8657 window.finish_frame(cx);
8658 }
8659
8660 fn complete_frame(&mut self, window: &mut Window, cx: &mut App) -> Option<FocusId> {
8661 self.0.borrow_mut().push("complete_frame");
8662 window.complete_frame(cx)
8663 }
8664
8665 fn end_frame(
8666 &mut self,
8667 window: &mut Window,
8668 cx: &mut App,
8669 focus_before_listeners: Option<FocusId>,
8670 ) {
8671 self.0.borrow_mut().push("end_frame");
8672 window.end_frame(cx, focus_before_listeners);
8673 }
8674 }
8675
8676 #[gpui::test]
8679 fn a_frame_that_skips_drawing_still_completes(cx: &mut TestAppContext) {
8680 cx.skip_drawing();
8681 let window = cx.add_window(|_, _| EmptyView);
8682
8683 cx.update_window(window.into(), |_, window, cx| window.draw(cx).clear(cx))
8684 .unwrap();
8685 }
8686
8687 #[cfg(debug_assertions)]
8690 #[gpui::test]
8691 #[should_panic(expected = "paint_roots ran while the frame was Evaluated")]
8692 fn a_frame_pass_out_of_order_is_rejected(cx: &mut TestAppContext) {
8693 let window = cx.add_window(|_, _| EmptyView);
8694
8695 cx.update_window(window.into(), |_, window, cx| {
8696 window.begin_frame(cx);
8697 let roots = window.evaluate_roots(cx);
8698 window.paint_roots(roots, cx);
8701 })
8702 .unwrap();
8703 }
8704
8705 struct PacingPipeline {
8707 frames: Rc<Cell<usize>>,
8708 asks: Rc<Cell<usize>>,
8709 allow: bool,
8710 }
8711
8712 impl FramePipeline for PacingPipeline {
8713 fn should_render(&mut self, is_dirty: bool, _metrics: &WindowMetrics) -> bool {
8714 self.asks.set(self.asks.get() + 1);
8715 self.allow && is_dirty
8716 }
8717
8718 fn draw(&mut self, window: &mut Window, cx: &mut App) -> ArenaClearNeeded {
8719 self.frames.set(self.frames.get() + 1);
8720 FramePipeline::draw(&mut StandardImmediatePipeline, window, cx)
8721 }
8722 }
8723
8724 fn install_pacing_pipeline(
8726 cx: &mut TestAppContext,
8727 frames: Rc<Cell<usize>>,
8728 asks: Rc<Cell<usize>>,
8729 allow: bool,
8730 ) {
8731 cx.update(move |cx| {
8732 cx.set_frame_pipeline_factory(Rc::new(move |_| {
8733 Box::new(PacingPipeline {
8734 frames: frames.clone(),
8735 asks: asks.clone(),
8736 allow,
8737 })
8738 }));
8739 });
8740 }
8741
8742 #[gpui::test]
8744 fn a_pipeline_can_defer_a_frame(cx: &mut TestAppContext) {
8745 let frames = Rc::new(Cell::new(0));
8746 let asks = Rc::new(Cell::new(0));
8747 install_pacing_pipeline(cx, frames.clone(), asks.clone(), false);
8748 let window = cx.add_window(|_, _| EmptyView);
8749 let test_window = cx.test_window(window.into());
8750 frames.set(0);
8751 asks.set(0);
8752
8753 window.update(cx, |_, _, cx| cx.notify()).unwrap();
8754 test_window.simulate_frame_request(RequestFrameOptions::default());
8755
8756 assert!(asks.get() > 0, "the pipeline was asked about the frame");
8757 assert_eq!(frames.get(), 0, "the deferred frame was never drawn");
8758 }
8759
8760 #[gpui::test]
8762 fn a_pipeline_can_allow_a_frame(cx: &mut TestAppContext) {
8763 let frames = Rc::new(Cell::new(0));
8764 let asks = Rc::new(Cell::new(0));
8765 install_pacing_pipeline(cx, frames.clone(), asks, true);
8766 let window = cx.add_window(|_, _| EmptyView);
8767 frames.set(0);
8768
8769 window.update(cx, |_, _, cx| cx.notify()).unwrap();
8770
8771 assert!(frames.get() > 0, "the allowed frame was drawn");
8772 }
8773
8774 #[gpui::test]
8775 fn test_fully_visible_bounds_preserve_layout_viewport(cx: &mut TestAppContext) {
8776 let window = cx.add_window(|_, _| EmptyView);
8777 let mut platform_window = cx.test_window(window.into());
8778 platform_window.simulate_resize(size(px(400.), px(800.)));
8779 window
8780 .update(cx, |_, window, _| {
8781 assert_eq!(
8782 window.visual_viewport_bounds(),
8783 Bounds::new(Point::default(), size(px(400.), px(800.)))
8784 );
8785 assert_eq!(
8786 window.fully_visible_bounds(),
8787 window.visual_viewport_bounds()
8788 );
8789 })
8790 .unwrap();
8791
8792 platform_window.simulate_frame_request(RequestFrameOptions::default());
8793 let wakes = platform_window.frame_wake_count();
8794 let visual_bounds = Bounds::new(point(px(10.), px(40.)), size(px(380.), px(460.)));
8795 platform_window.simulate_visual_viewport_change(visual_bounds);
8796 assert!(platform_window.frame_wake_count() > wakes);
8797 platform_window.simulate_frame_request(RequestFrameOptions::default());
8798 let wakes = platform_window.frame_wake_count();
8799 platform_window.simulate_insets_change(crate::WindowInsets {
8800 safe_area: crate::Edges {
8801 top: px(60.),
8802 right: px(20.),
8803 bottom: px(30.),
8804 left: px(-10.),
8805 },
8806 ime: crate::Edges {
8807 bottom: px(350.),
8808 ..Default::default()
8809 },
8810 });
8811 assert!(platform_window.frame_wake_count() > wakes);
8812 window
8813 .update(cx, |_, window, _| {
8814 assert_eq!(window.viewport_size(), size(px(400.), px(800.)));
8815 assert_eq!(window.visual_viewport_bounds(), visual_bounds);
8816 assert_eq!(
8817 window.fully_visible_bounds(),
8818 Bounds::new(point(px(10.), px(60.)), size(px(370.), px(390.)))
8819 );
8820 window.request_virtual_keyboard();
8821 window.dismiss_virtual_keyboard();
8822 assert_eq!(window.viewport_size(), size(px(400.), px(800.)));
8823 })
8824 .unwrap();
8825 assert_eq!(platform_window.virtual_keyboard_requests(), 1);
8826 assert_eq!(platform_window.virtual_keyboard_dismissals(), 1);
8827
8828 platform_window.simulate_insets_change(crate::WindowInsets {
8829 safe_area: crate::Edges {
8830 top: px(900.),
8831 left: px(500.),
8832 ..Default::default()
8833 },
8834 ..Default::default()
8835 });
8836 window
8837 .update(cx, |_, window, _| {
8838 assert_eq!(
8839 window.fully_visible_bounds().size,
8840 size(Pixels::ZERO, Pixels::ZERO)
8841 );
8842 })
8843 .unwrap();
8844 }
8845
8846 struct EmptyView;
8847
8848 impl Render for EmptyView {
8849 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
8850 div()
8851 }
8852 }
8853
8854 struct OpensWindowOnPaint {
8855 opened: Rc<Cell<bool>>,
8856 }
8857
8858 impl Render for OpensWindowOnPaint {
8859 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
8860 let opened = self.opened.clone();
8861 div()
8862 .size_full()
8863 .child(canvas(
8864 |_, _, _| {},
8865 move |_, _, _window, cx| {
8866 if !opened.replace(true) {
8867 cx.open_window(WindowOptions::default(), |_, cx| cx.new(|_| EmptyView))
8868 .unwrap();
8869 }
8870 },
8871 ))
8872 .child(div().child("after"))
8876 }
8877 }
8878
8879 #[test]
8885 fn test_window_opened_during_draw_defers_arena_clear() {
8886 let mut cx = TestAppContext::single();
8887
8888 let opened = Rc::new(Cell::new(false));
8889 let window = cx.add_window({
8891 let opened = opened.clone();
8892 move |_, _| OpensWindowOnPaint { opened }
8893 });
8894
8895 assert!(opened.get());
8896 assert_eq!(cx.windows().len(), 2);
8897
8898 cx.update_window(window.into(), |_, window, cx| window.draw(cx).clear(cx))
8901 .unwrap();
8902 }
8903
8904 #[test]
8905 fn test_scale_factor_change_preserves_bounds_and_survives_resize() {
8906 let mut cx = TestAppContext::single();
8907 let window = cx.add_window(|_, _| EmptyView);
8908 let handle: AnyWindowHandle = window.into();
8909 let window_state = |cx: &mut TestAppContext| {
8910 cx.update_window(handle, |_, window, _| {
8911 (
8912 window.scale_factor(),
8913 window.bounds(),
8914 window.viewport_size(),
8915 )
8916 })
8917 .unwrap()
8918 };
8919
8920 let (scale_factor, mut expected_bounds, _) = window_state(&mut cx);
8921 assert_eq!(scale_factor, 2.0);
8922
8923 for (scale_factor, resized_size) in [
8924 (1.0, size(px(800.), px(600.))),
8925 (1.25, size(px(640.), px(480.))),
8926 (2.0, size(px(1024.), px(768.))),
8927 ] {
8928 cx.simulate_window_scale_factor_change(handle, scale_factor);
8929 assert_eq!(
8930 window_state(&mut cx),
8931 (scale_factor, expected_bounds, expected_bounds.size)
8932 );
8933
8934 cx.simulate_window_resize(handle, resized_size);
8935 expected_bounds.size = resized_size;
8936 assert_eq!(
8937 window_state(&mut cx),
8938 (scale_factor, expected_bounds, resized_size)
8939 );
8940 }
8941 }
8942
8943 #[gpui::test]
8944 fn metrics_handle_agrees_with_the_window_and_tracks_resizes(cx: &mut TestAppContext) {
8945 let window = cx.add_window(|_, _| EmptyView);
8946 let handle: AnyWindowHandle = window.into();
8947
8948 let metrics = cx.read(|app| handle.metrics(app).expect("window is open"));
8949 assert_eq!(metrics.id(), handle.window_id());
8950 assert!(metrics.display_id().is_some());
8951
8952 let window_state = |cx: &mut TestAppContext| {
8954 cx.update_window(handle, |_, window, _| {
8955 assert_eq!(metrics.bounds(), window.bounds());
8956 assert_eq!(metrics.viewport(), window.visual_viewport_bounds());
8957 assert_eq!(metrics.content_size(), window.viewport_size());
8958 assert_eq!(metrics.scale_factor(), window.scale_factor());
8959 assert_eq!(metrics.is_active(), window.is_window_active());
8960 assert_eq!(metrics.is_fullscreen(), window.is_fullscreen());
8961 })
8962 .unwrap();
8963 };
8964 window_state(cx);
8965
8966 cx.simulate_window_resize(handle, size(px(800.), px(600.)));
8967 cx.simulate_window_scale_factor_change(handle, 1.25);
8968
8969 assert_eq!(metrics.content_size(), size(px(800.), px(600.)));
8972 assert_eq!(metrics.scale_factor(), 1.25);
8973 window_state(cx);
8974 }
8975
8976 #[gpui::test]
8980 fn metrics_track_viewport_changes_that_do_not_resize(cx: &mut TestAppContext) {
8981 let window = cx.add_window(|_, _| EmptyView);
8982 let handle: AnyWindowHandle = window.into();
8983 let metrics = cx.read(|app| handle.metrics(app).expect("window is open"));
8984
8985 let narrow = Bounds::new(point(px(0.), px(120.)), size(px(400.), px(680.)));
8986 assert_ne!(metrics.viewport(), narrow);
8987
8988 cx.simulate_window_visual_viewport_change(handle, narrow);
8989 assert_eq!(metrics.viewport(), narrow);
8990
8991 cx.update_window(handle, |_, window, _| {
8992 assert_eq!(metrics.viewport(), window.visual_viewport_bounds());
8993 assert_eq!(metrics.content_size(), window.viewport_size());
8995 })
8996 .unwrap();
8997 }
8998
8999 #[gpui::test]
9003 fn updating_a_window_from_within_its_own_update_reports_an_error(cx: &mut TestAppContext) {
9004 let window = cx.add_window(|_, _| EmptyView);
9005 let handle: AnyWindowHandle = window.into();
9006
9007 let nested_error = cx
9008 .update_window(handle, |_, _window, cx| {
9009 cx.update_window(handle, |_, _, _| ())
9010 .map_err(|error| error.to_string())
9011 .unwrap_err()
9012 })
9013 .expect("the outer update completes");
9014
9015 assert!(
9016 nested_error.contains("already being updated"),
9017 "unexpected error: {nested_error}"
9018 );
9019 }
9020
9021 #[gpui::test]
9024 fn a_window_can_be_updated_from_within_another_windows_update(cx: &mut TestAppContext) {
9025 let first: AnyWindowHandle = cx.add_window(|_, _| EmptyView).into();
9026 let second: AnyWindowHandle = cx.add_window(|_, _| EmptyView).into();
9027
9028 let expected = cx
9029 .update_window(second, |_, window, _| window.viewport_size())
9030 .expect("the window can be updated on its own");
9031
9032 let from_inner = cx
9033 .update_window(first, |_, _window, cx| {
9034 cx.update_window(second, |_, window, _| window.viewport_size())
9035 .expect("the inner update succeeds")
9036 })
9037 .expect("the outer update completes");
9038
9039 assert_eq!(from_inner, expected);
9040 }
9041
9042 #[gpui::test]
9045 fn metrics_handle_is_readable_from_another_thread(cx: &mut TestAppContext) {
9046 let window = cx.add_window(|_, _| EmptyView);
9047 let handle: AnyWindowHandle = window.into();
9048 cx.simulate_window_resize(handle, size(px(640.), px(480.)));
9049 let metrics = cx.read(|app| handle.metrics(app).expect("window is open"));
9050
9051 let (id, content_size, scale_factor) = std::thread::spawn(move || {
9052 (metrics.id(), metrics.content_size(), metrics.scale_factor())
9053 })
9054 .join()
9055 .expect("the metrics reader did not panic");
9056
9057 assert_eq!(id, handle.window_id());
9058 assert_eq!(content_size, size(px(640.), px(480.)));
9059 assert_eq!(scale_factor, 2.0);
9060 }
9061
9062 #[gpui::test]
9067 fn test_frame_waker_fires_on_frame_demand(cx: &mut TestAppContext) {
9068 let window = cx.add_window(|_, _| EmptyView);
9069 let test_window = cx.test_window(window.into());
9070
9071 assert!(
9075 test_window.frame_wake_count() >= 1,
9076 "opening a window must wake the frame source for the initial frame"
9077 );
9078
9079 test_window.simulate_frame_request(RequestFrameOptions::default());
9081
9082 let baseline = test_window.frame_wake_count();
9085 test_window.simulate_frame_request(RequestFrameOptions::default());
9086 window.update(cx, |_, _, _| {}).unwrap();
9087 assert_eq!(
9088 test_window.frame_wake_count(),
9089 baseline,
9090 "clean frames and non-notifying updates must not wake the frame source"
9091 );
9092
9093 window.update(cx, |_, _, cx| cx.notify()).unwrap();
9095 assert!(
9096 test_window.frame_wake_count() > baseline,
9097 "notifying a view in an idle window must wake the frame source"
9098 );
9099
9100 test_window.simulate_frame_request(RequestFrameOptions::default());
9102 let baseline = test_window.frame_wake_count();
9103 test_window.simulate_frame_request(RequestFrameOptions::default());
9104 assert_eq!(
9105 test_window.frame_wake_count(),
9106 baseline,
9107 "serving demand must return the window to idle"
9108 );
9109
9110 window
9112 .update(cx, |_, window, _| window.on_next_frame(|_, _| {}))
9113 .unwrap();
9114 assert!(
9115 test_window.frame_wake_count() > baseline,
9116 "scheduling a next-frame callback in an idle window must wake the frame source"
9117 );
9118 }
9119
9120 #[gpui::test]
9125 fn test_pending_next_frame_callbacks_are_not_stranded(cx: &mut TestAppContext) {
9126 let window = cx.add_window(|_, _| EmptyView);
9127 let test_window = cx.test_window(window.into());
9128 test_window.simulate_frame_request(RequestFrameOptions::default());
9131
9132 let callback_ran = Rc::new(Cell::new(false));
9133 window
9134 .update(cx, {
9135 let callback_ran = callback_ran.clone();
9136 move |_, window, _| {
9137 window.on_next_frame(move |_, _| callback_ran.set(true));
9138 }
9139 })
9140 .unwrap();
9141
9142 let baseline = test_window.frame_wake_count();
9143 test_window.simulate_frame_request(RequestFrameOptions::default());
9144 assert!(
9151 test_window.frame_wake_count() > baseline || callback_ran.get(),
9152 "a frame request with pending next-frame callbacks must either run them or re-arm the frame source"
9153 );
9154 }
9155
9156 #[gpui::test]
9157 fn test_window_reports_no_raw_handle_instead_of_panicking(cx: &mut TestAppContext) {
9158 use raw_window_handle::{HandleError, HasDisplayHandle as _, HasWindowHandle as _};
9159
9160 let window = cx.add_window(|_, _| EmptyView);
9161 window
9162 .update(cx, |_, window, _| {
9163 assert!(matches!(
9164 window.window_handle(),
9165 Err(HandleError::NotSupported)
9166 ));
9167 assert!(matches!(
9168 window.display_handle(),
9169 Err(HandleError::NotSupported)
9170 ));
9171 })
9172 .unwrap();
9173 }
9174
9175 #[gpui::test]
9176 fn test_appearance_change_runs_after_app_update(cx: &mut TestAppContext) {
9177 let window = cx.add_window(|_, _| EmptyView);
9178 let observed_appearance = Rc::new(Cell::new(None));
9179 let _subscription = window
9180 .update(cx, {
9181 let observed_appearance = observed_appearance.clone();
9182 move |_, window, _| {
9183 window.observe_window_appearance(move |window, _| {
9184 observed_appearance.set(Some(window.appearance()));
9185 })
9186 }
9187 })
9188 .unwrap();
9189 let test_window = cx.test_window(window.into());
9190
9191 cx.update(|_| {
9192 test_window.simulate_appearance_change(WindowAppearance::Dark);
9193 assert_eq!(observed_appearance.get(), None);
9194 });
9195 cx.run_until_parked();
9196
9197 assert_eq!(observed_appearance.get(), Some(WindowAppearance::Dark));
9198 }
9199
9200 #[gpui::test]
9201 fn queued_frame_callback_wakes_a_parked_render_loop(cx: &mut TestAppContext) {
9202 let window = cx.add_window(|_, _| Empty);
9203 let test_window = cx.test_window(window.into());
9204
9205 assert!(test_window.simulate_scheduled_frame());
9206 assert!(test_window.simulate_scheduled_frame());
9207 assert!(!test_window.frame_scheduled());
9208
9209 cx.update_window(window.into(), |_, window, _| {
9210 window.core.active.set(true);
9211 window.on_next_frame(|_, _| {});
9212 })
9213 .unwrap();
9214 assert!(
9215 test_window.frame_scheduled(),
9216 "queuing work on a parked window must wake the render loop"
9217 );
9218
9219 assert!(test_window.simulate_scheduled_frame());
9220 assert!(
9221 test_window.frame_scheduled(),
9222 "presenting the frame must await one compositor callback"
9223 );
9224 assert!(test_window.simulate_scheduled_frame());
9225 assert!(!test_window.frame_scheduled());
9226 }
9227
9228 #[gpui::test]
9229 fn pending_presentation_wakes_a_parked_render_loop(cx: &mut TestAppContext) {
9230 let window = cx.add_window(|_, _| Empty);
9231 let test_window = cx.test_window(window.into());
9232
9233 assert!(test_window.simulate_scheduled_frame());
9234 assert!(test_window.simulate_scheduled_frame());
9235 assert!(!test_window.frame_scheduled());
9236
9237 cx.update_window(window.into(), |_, window, cx| window.draw(cx).clear(cx))
9238 .unwrap();
9239
9240 assert!(
9241 test_window.frame_scheduled(),
9242 "a rendered scene awaiting presentation must wake the render loop"
9243 );
9244 }
9245
9246 #[gpui::test]
9247 fn callback_queued_during_a_frame_requests_a_follow_up(cx: &mut TestAppContext) {
9248 let window = cx.add_window(|_, _| Empty);
9249 let test_window = cx.test_window(window.into());
9250
9251 let callback_ran = Rc::new(Cell::new(false));
9252 cx.update_window(window.into(), |_, window, _| {
9253 window.core.active.set(true);
9256 let callback_ran = callback_ran.clone();
9257 window.on_next_frame(move |window, _| {
9258 window.on_next_frame(move |_, _| callback_ran.set(true));
9259 });
9260 })
9261 .unwrap();
9262
9263 assert!(test_window.simulate_scheduled_frame());
9264 assert!(!callback_ran.get());
9265 assert!(
9266 test_window.frame_scheduled(),
9267 "a callback queued mid-frame must schedule a follow-up before the loop parks"
9268 );
9269
9270 assert!(test_window.simulate_scheduled_frame());
9271 assert!(callback_ran.get());
9272 }
9273
9274 struct RootView {
9275 explicit_size: bool,
9276 child_bounds: Rc<Cell<Bounds<Pixels>>>,
9277 }
9278
9279 impl Render for RootView {
9280 fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
9281 let child_bounds = self.child_bounds.clone();
9282 let root = div().flex().flex_col().child(
9283 canvas(
9284 move |bounds, _, _| child_bounds.set(bounds),
9285 |_, _, _, _| {},
9286 )
9287 .size_full(),
9288 );
9289 if self.explicit_size {
9290 root.w(px(300.)).h(px(200.))
9291 } else {
9292 root
9293 }
9294 }
9295 }
9296
9297 #[test]
9298 fn auto_sized_window_root_fills_the_window() {
9299 let mut cx = TestAppContext::single();
9300 let child_bounds = Rc::new(Cell::new(Bounds::default()));
9301 let window = cx.add_window({
9302 let child_bounds = child_bounds.clone();
9303 move |_, _| RootView {
9304 explicit_size: false,
9305 child_bounds,
9306 }
9307 });
9308
9309 let viewport_size = cx
9310 .update_window(window.into(), |_, window, cx| {
9311 window.draw(cx).clear(cx);
9312 window.viewport_size()
9313 })
9314 .unwrap();
9315
9316 assert_eq!(child_bounds.get().size, viewport_size);
9317 }
9318
9319 #[test]
9320 fn explicitly_sized_window_root_keeps_its_size() {
9321 let mut cx = TestAppContext::single();
9322 let child_bounds = Rc::new(Cell::new(Bounds::default()));
9323 let window = cx.add_window({
9324 let child_bounds = child_bounds.clone();
9325 move |_, _| RootView {
9326 explicit_size: true,
9327 child_bounds,
9328 }
9329 });
9330
9331 cx.update_window(window.into(), |_, window, cx| {
9332 window.draw(cx).clear(cx);
9333 })
9334 .unwrap();
9335
9336 assert_eq!(child_bounds.get().size, size(px(300.), px(200.)));
9337 }
9338
9339 struct FileDragView {
9340 path: PathBuf,
9341 observed_drag_moves: Rc<RefCell<Vec<Point<Pixels>>>>,
9342 observed_drops: Rc<RefCell<Vec<PathBuf>>>,
9343 }
9344
9345 struct FileDropExitView(Rc<Cell<usize>>);
9346
9347 impl Render for FileDropExitView {
9348 fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
9349 div().size_full().on_file_drop_exit({
9350 let observed_file_drop_exit = self.0.clone();
9351 move |_, _, _| observed_file_drop_exit.set(observed_file_drop_exit.get() + 1)
9352 })
9353 }
9354 }
9355
9356 impl Render for FileDragView {
9357 fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
9358 div()
9359 .id("file-drag")
9360 .size_full()
9361 .on_drag(self.path.clone(), |_, _, _, cx| cx.new(|_| Empty))
9362 .external_drag_payload(|path: &PathBuf, _, _| {
9363 Some(ExternalDragPayload::Files(FileDragPaths::new([(
9364 path.clone(),
9365 true,
9366 )])))
9367 })
9368 .on_drag_move({
9369 let observed_drag_moves = self.observed_drag_moves.clone();
9370 move |event: &DragMoveEvent<PathBuf>, _, _| {
9371 observed_drag_moves.borrow_mut().push(event.event.position);
9372 }
9373 })
9374 .on_drop({
9375 let observed_drops = self.observed_drops.clone();
9376 move |path: &PathBuf, _, _| observed_drops.borrow_mut().push(path.clone())
9377 })
9378 }
9379 }
9380
9381 #[gpui::test]
9382 fn file_drag_is_promoted_once_and_restored_in_source_window(cx: &mut TestAppContext) {
9383 struct Drag {
9384 window: AnyWindowHandle,
9385 observed_drag_moves: Rc<RefCell<Vec<Point<Pixels>>>>,
9386 observed_drops: Rc<RefCell<Vec<PathBuf>>>,
9387 }
9388
9389 fn start_drag(cx: &mut TestAppContext, path: PathBuf, platform_result: bool) -> Drag {
9390 let observed_drag_moves = Rc::new(RefCell::new(Vec::new()));
9391 let observed_drops = Rc::new(RefCell::new(Vec::new()));
9392 let window: AnyWindowHandle = cx
9393 .add_window({
9394 let observed_drag_moves = observed_drag_moves.clone();
9395 let observed_drops = observed_drops.clone();
9396 move |_, _| FileDragView {
9397 path,
9398 observed_drag_moves,
9399 observed_drops,
9400 }
9401 })
9402 .into();
9403 cx.test_window(window)
9404 .set_start_external_drag_result(platform_result);
9405
9406 let update_result = cx.update_window(window, |_, window, cx| {
9407 window.draw(cx).clear(cx);
9408 window.dispatch_event(
9409 MouseDownEvent {
9410 position: point(px(10.), px(10.)),
9411 button: MouseButton::Left,
9412 modifiers: Default::default(),
9413 click_count: 1,
9414 first_mouse: false,
9415 }
9416 .to_platform_input(),
9417 cx,
9418 );
9419 window.dispatch_event(
9420 MouseMoveEvent {
9421 position: point(px(20.), px(20.)),
9422 pressed_button: Some(MouseButton::Left),
9423 modifiers: Default::default(),
9424 }
9425 .to_platform_input(),
9426 cx,
9427 );
9428 assert!(cx.active_drag.is_some());
9429 });
9430 assert!(
9431 update_result.is_ok(),
9432 "failed to start drag: {update_result:?}"
9433 );
9434
9435 assert!(cx.test_window(window).external_drag_files().is_empty());
9436 Drag {
9437 window,
9438 observed_drag_moves,
9439 observed_drops,
9440 }
9441 }
9442
9443 let successful_path = PathBuf::from("/tmp/successful-drag");
9444 let successful = start_drag(cx, successful_path.clone(), true);
9445 let outside_position = point(px(-1.), px(20.));
9446 let update_result = cx.update_window(successful.window, |_, window, cx| {
9447 window.dispatch_event(
9448 MouseMoveEvent {
9449 position: outside_position,
9450 pressed_button: Some(MouseButton::Left),
9451 modifiers: Default::default(),
9452 }
9453 .to_platform_input(),
9454 cx,
9455 );
9456 assert!(cx.active_drag.is_none());
9457 });
9458 assert!(
9459 update_result.is_ok(),
9460 "failed to promote drag: {update_result:?}"
9461 );
9462 assert_eq!(
9463 cx.test_window(successful.window).external_drag_files(),
9464 [(successful_path.clone(), true)]
9465 );
9466 assert_eq!(
9469 successful.observed_drag_moves.borrow().last(),
9470 Some(&outside_position)
9471 );
9472
9473 let first_destination_exit_count = Rc::new(Cell::new(0));
9474 let first_destination: AnyWindowHandle = cx
9475 .add_window({
9476 let first_destination_exit_count = first_destination_exit_count.clone();
9477 move |_, _| FileDropExitView(first_destination_exit_count)
9478 })
9479 .into();
9480 let second_destination_exit_count = Rc::new(Cell::new(0));
9481 let second_destination: AnyWindowHandle = cx
9482 .add_window({
9483 let second_destination_exit_count = second_destination_exit_count.clone();
9484 move |_, _| FileDropExitView(second_destination_exit_count)
9485 })
9486 .into();
9487 let reentry_position = point(px(30.), px(30.));
9488 let external_paths = || ExternalPaths([successful_path.clone()].into_iter().collect());
9489 let update_result = cx.update_window(first_destination, |_, window, cx| {
9490 window.draw(cx).clear(cx);
9491 window.dispatch_event(
9492 FileDropEvent::Entered {
9493 position: reentry_position,
9494 paths: external_paths(),
9495 }
9496 .to_platform_input(),
9497 cx,
9498 );
9499 assert!(
9500 cx.active_drag
9501 .as_ref()
9502 .is_some_and(|drag| drag.value.downcast_ref::<ExternalPaths>().is_some())
9503 );
9504 window.dispatch_event(FileDropEvent::Exited.to_platform_input(), cx);
9505 assert!(cx.active_drag.is_none());
9506 assert_eq!(first_destination_exit_count.get(), 1);
9507 assert_eq!(second_destination_exit_count.get(), 0);
9508 });
9509 assert!(
9510 update_result.is_ok(),
9511 "failed to handle drag in first destination window: {update_result:?}"
9512 );
9513
9514 let update_result = cx.update_window(second_destination, |_, window, cx| {
9515 window.draw(cx).clear(cx);
9516 window.dispatch_event(
9517 PlatformInput::KeyDown(KeyDownEvent {
9518 keystroke: Keystroke::parse("down").expect("valid keystroke"),
9519 is_held: false,
9520 prefer_character_input: false,
9521 }),
9522 cx,
9523 );
9524 window.dispatch_event(
9525 FileDropEvent::Entered {
9526 position: reentry_position,
9527 paths: external_paths(),
9528 }
9529 .to_platform_input(),
9530 cx,
9531 );
9532 assert!(
9533 cx.active_drag
9534 .as_ref()
9535 .is_some_and(|drag| drag.value.downcast_ref::<ExternalPaths>().is_some())
9536 );
9537 assert_eq!(first_destination_exit_count.get(), 1);
9538 assert_eq!(second_destination_exit_count.get(), 0);
9539
9540 window.dispatch_event(FileDropEvent::Exited.to_platform_input(), cx);
9541 assert!(cx.active_drag.is_none());
9542 assert_eq!(first_destination_exit_count.get(), 1);
9543 assert_eq!(second_destination_exit_count.get(), 1);
9544 });
9545 assert!(
9546 update_result.is_ok(),
9547 "failed to handle drag in second destination window: {update_result:?}"
9548 );
9549
9550 let update_result = cx.update_window(successful.window, |_, window, cx| {
9551 window.dispatch_event(
9552 FileDropEvent::Entered {
9553 position: reentry_position,
9554 paths: external_paths(),
9555 }
9556 .to_platform_input(),
9557 cx,
9558 );
9559 assert!(
9560 cx.active_drag
9561 .as_ref()
9562 .is_some_and(|drag| drag.value.downcast_ref::<PathBuf>().is_some())
9563 );
9564 assert_eq!(
9565 successful.observed_drag_moves.borrow().last(),
9566 Some(&reentry_position)
9567 );
9568
9569 window.dispatch_event(FileDropEvent::Exited.to_platform_input(), cx);
9570 assert!(cx.active_drag.is_none());
9571
9572 window.dispatch_event(
9573 FileDropEvent::Entered {
9574 position: reentry_position,
9575 paths: external_paths(),
9576 }
9577 .to_platform_input(),
9578 cx,
9579 );
9580 assert!(
9581 cx.active_drag
9582 .as_ref()
9583 .is_some_and(|drag| drag.value.downcast_ref::<PathBuf>().is_some())
9584 );
9585
9586 window.dispatch_event(
9587 FileDropEvent::Submit {
9588 position: reentry_position,
9589 }
9590 .to_platform_input(),
9591 cx,
9592 );
9593 assert_eq!(
9594 successful.observed_drops.borrow().as_slice(),
9595 std::slice::from_ref(&successful_path)
9596 );
9597 assert!(cx.active_drag.is_none());
9598
9599 window.dispatch_event(FileDropEvent::Exited.to_platform_input(), cx);
9600 assert!(cx.active_drag.is_none());
9601 window.dispatch_event(FileDropEvent::Ended.to_platform_input(), cx);
9602 assert!(cx.active_drag.is_none());
9603
9604 window.dispatch_event(
9605 FileDropEvent::Entered {
9606 position: reentry_position,
9607 paths: external_paths(),
9608 }
9609 .to_platform_input(),
9610 cx,
9611 );
9612 assert!(
9613 cx.active_drag
9614 .as_ref()
9615 .is_some_and(|drag| drag.value.downcast_ref::<ExternalPaths>().is_some())
9616 );
9617 window.dispatch_event(FileDropEvent::Exited.to_platform_input(), cx);
9618 });
9619 assert!(
9620 update_result.is_ok(),
9621 "failed to restore drag in source window: {update_result:?}"
9622 );
9623
9624 let cancelled_path = PathBuf::from("/tmp/cancelled-drag");
9625 let cancelled = start_drag(cx, cancelled_path.clone(), true);
9626 let update_result = cx.update_window(cancelled.window, |_, window, cx| {
9627 window.dispatch_event(
9628 MouseMoveEvent {
9629 position: outside_position,
9630 pressed_button: Some(MouseButton::Left),
9631 modifiers: Default::default(),
9632 }
9633 .to_platform_input(),
9634 cx,
9635 );
9636 assert!(cx.active_drag.is_none());
9637
9638 window.dispatch_event(
9639 FileDropEvent::Entered {
9640 position: reentry_position,
9641 paths: ExternalPaths([cancelled_path].into_iter().collect()),
9642 }
9643 .to_platform_input(),
9644 cx,
9645 );
9646 assert!(
9647 cx.active_drag
9648 .as_ref()
9649 .is_some_and(|drag| drag.value.downcast_ref::<PathBuf>().is_some())
9650 );
9651 assert!(cx.stop_active_drag(window));
9652 assert!(cx.active_drag.is_none());
9653 });
9654 assert!(
9655 update_result.is_ok(),
9656 "failed to cancel restored drag: {update_result:?}"
9657 );
9658 assert!(!cx.update(|cx| cx.end_platform_drag(cancelled.window.window_id())));
9659
9660 let removed_path = PathBuf::from("/tmp/removed-window-drag");
9661 let removed = start_drag(cx, removed_path, true);
9662 let removed_window_id = removed.window.window_id();
9663 let update_result = cx.update_window(removed.window, |_, window, cx| {
9664 window.dispatch_event(
9665 MouseMoveEvent {
9666 position: outside_position,
9667 pressed_button: Some(MouseButton::Left),
9668 modifiers: Default::default(),
9669 }
9670 .to_platform_input(),
9671 cx,
9672 );
9673 assert!(cx.active_drag.is_none());
9674 window.remove_window();
9675 });
9676 assert!(
9677 update_result.is_ok(),
9678 "failed to remove drag source window: {update_result:?}"
9679 );
9680 assert!(!cx.update(|cx| cx.end_platform_drag(removed_window_id)));
9681
9682 let failed_path = PathBuf::from("/tmp/failed-drag");
9683 let failed = start_drag(cx, failed_path.clone(), false);
9684 let update_result = cx.update_window(failed.window, |_, window, cx| {
9685 for x_position in [-1., -2.] {
9686 window.dispatch_event(
9687 MouseMoveEvent {
9688 position: point(px(x_position), px(20.)),
9689 pressed_button: Some(MouseButton::Left),
9690 modifiers: Default::default(),
9691 }
9692 .to_platform_input(),
9693 cx,
9694 );
9695 }
9696 assert!(cx.active_drag.is_some());
9697 });
9698 assert!(
9699 update_result.is_ok(),
9700 "failed to retain drag after platform failure: {update_result:?}"
9701 );
9702 assert_eq!(
9703 cx.test_window(failed.window).external_drag_files(),
9704 [(failed_path, true)]
9705 );
9706 }
9707
9708 struct FocusForwarder {
9709 a: FocusHandle,
9710 b: FocusHandle,
9711 }
9712
9713 impl Render for FocusForwarder {
9714 fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
9715 div()
9716 .size_full()
9717 .child(div().w(px(50.)).h(px(50.)).track_focus(&self.a))
9718 .child(div().w(px(50.)).h(px(50.)).track_focus(&self.b))
9719 }
9720 }
9721
9722 #[gpui::test]
9726 fn test_focus_moved_by_focus_listener_is_dispatched(cx: &mut TestAppContext) {
9727 let b_focus_count = Rc::new(Cell::new(0));
9728 let window = cx.add_window({
9729 let b_focus_count = b_focus_count.clone();
9730 move |window, cx| {
9731 let a = cx.focus_handle();
9732 let b = cx.focus_handle();
9733 cx.on_focus(&a, window, |this: &mut FocusForwarder, window, cx| {
9734 let b = this.b.clone();
9735 window.focus(&b, cx);
9736 })
9737 .detach();
9738 cx.on_focus(&b, window, move |_, _, _| {
9739 b_focus_count.set(b_focus_count.get() + 1);
9740 })
9741 .detach();
9742 FocusForwarder { a, b }
9743 }
9744 });
9745
9746 window
9747 .update(cx, |_, window, _| window.activate_window())
9748 .unwrap();
9749 cx.executor().run_until_parked();
9750
9751 window
9752 .update(cx, |this, window, cx| {
9753 let a = this.a.clone();
9754 window.focus(&a, cx);
9755 })
9756 .unwrap();
9757 cx.executor().run_until_parked();
9758
9759 window
9760 .update(cx, |this, window, _| {
9761 assert!(this.b.is_focused(window));
9762 })
9763 .unwrap();
9764 assert_eq!(b_focus_count.get(), 1);
9765 }
9766
9767 #[gpui::test]
9768 fn claimed_touch_drag_receives_movement_and_release(cx: &mut TestAppContext) {
9769 let events = Rc::new(RefCell::new(Vec::new()));
9770 let window = cx.add_window({
9771 let events = events.clone();
9772 move |_, _| TouchDragListener { events }
9773 });
9774 let touch = TouchId(1);
9775
9776 dispatch_touch(window, cx, touch, TouchPhase::Started, 10.);
9777 dispatch_touch(window, cx, touch, TouchPhase::Moved, 30.);
9778 dispatch_touch(window, cx, touch, TouchPhase::Ended, 40.);
9779
9780 assert_eq!(
9781 events.borrow().as_slice(),
9782 [
9783 (TouchPhase::Started, px(10.)),
9784 (TouchPhase::Moved, px(30.)),
9785 (TouchPhase::Ended, px(40.)),
9786 ]
9787 );
9788 }
9789
9790 struct TouchDragListener {
9791 events: Rc<RefCell<Vec<(TouchPhase, Pixels)>>>,
9792 }
9793
9794 impl Render for TouchDragListener {
9795 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
9796 let events = self.events.clone();
9797 canvas(
9798 |_, _, _| {},
9799 move |_, _, window, _| {
9800 window.on_mouse_event(move |event: &TouchDragEvent, phase, window, _cx| {
9801 if phase != DispatchPhase::Bubble {
9802 return;
9803 }
9804 events.borrow_mut().push((event.phase, event.position.x));
9805 if event.phase == TouchPhase::Started {
9806 window.prevent_default();
9807 }
9808 });
9809 },
9810 )
9811 }
9812 }
9813
9814 #[gpui::test]
9815 fn long_press_is_claimed_only_when_started_prevents_default(cx: &mut TestAppContext) {
9816 for response in [
9817 LongPressResponse::PreventDefault,
9818 LongPressResponse::StopPropagation,
9819 LongPressResponse::None,
9820 ] {
9821 let phases = Rc::new(RefCell::new(Vec::new()));
9822 let window = cx.add_window({
9823 let phases = phases.clone();
9824 move |_, _| LongPressListener { phases, response }
9825 });
9826 dispatch_touch(window, cx, TouchId(1), TouchPhase::Started, 0.);
9827 cx.executor().advance_clock(Duration::from_millis(501));
9828 cx.executor().run_until_parked();
9829 window
9830 .update(cx, |_, window, _| {
9831 assert_eq!(
9832 window.core.long_press_capture.is_some(),
9833 response == LongPressResponse::PreventDefault
9834 );
9835 })
9836 .unwrap();
9837 dispatch_touch(window, cx, TouchId(1), TouchPhase::Moved, 2.);
9838 dispatch_touch(window, cx, TouchId(1), TouchPhase::Ended, 2.);
9839 window
9840 .update(cx, |_, window, _| {
9841 assert!(window.core.long_press_capture.is_none());
9842 })
9843 .unwrap();
9844
9845 let phases = phases.borrow();
9846 if response == LongPressResponse::PreventDefault {
9847 assert_eq!(
9848 phases.as_slice(),
9849 [TouchPhase::Started, TouchPhase::Moved, TouchPhase::Ended]
9850 );
9851 } else {
9852 assert_eq!(phases.as_slice(), [TouchPhase::Started]);
9853 }
9854 }
9855 }
9856
9857 #[gpui::test]
9858 fn stale_default_prevention_does_not_claim_long_press(cx: &mut TestAppContext) {
9859 let phases = Rc::new(RefCell::new(Vec::new()));
9860 let window = cx.add_window({
9861 let phases = phases.clone();
9862 move |_, _| LongPressListener {
9863 phases,
9864 response: LongPressResponse::None,
9865 }
9866 });
9867 window
9868 .update(cx, |_, window, _| {
9869 window.prevent_default();
9870 })
9871 .unwrap();
9872
9873 dispatch_touch(window, cx, TouchId(1), TouchPhase::Started, 0.);
9874 cx.executor().advance_clock(Duration::from_millis(501));
9875 cx.executor().run_until_parked();
9876 dispatch_touch(window, cx, TouchId(1), TouchPhase::Moved, 2.);
9877
9878 assert_eq!(phases.borrow().as_slice(), [TouchPhase::Started]);
9879 }
9880
9881 #[gpui::test]
9882 fn resolved_touch_cancels_scheduled_long_press(cx: &mut TestAppContext) {
9883 for (phase, position) in [
9884 (TouchPhase::Ended, 0.),
9885 (TouchPhase::Cancelled, 0.),
9886 (TouchPhase::Moved, 20.),
9887 ] {
9888 let phases = Rc::new(RefCell::new(Vec::new()));
9889 let window = cx.add_window({
9890 let phases = phases.clone();
9891 move |_, _| LongPressListener {
9892 phases,
9893 response: LongPressResponse::PreventDefault,
9894 }
9895 });
9896 dispatch_touch(window, cx, TouchId(1), TouchPhase::Started, 0.);
9897 dispatch_touch(window, cx, TouchId(1), phase, position);
9898 cx.executor().advance_clock(Duration::from_millis(501));
9899 cx.executor().run_until_parked();
9900
9901 assert!(phases.borrow().is_empty(), "{phase:?} allowed long press");
9902 }
9903 }
9904
9905 #[gpui::test]
9906 fn stale_long_press_timer_cannot_affect_replacement_touch(cx: &mut TestAppContext) {
9907 let phases = Rc::new(RefCell::new(Vec::new()));
9908 let window = cx.add_window({
9909 let phases = phases.clone();
9910 move |_, _| LongPressListener {
9911 phases,
9912 response: LongPressResponse::PreventDefault,
9913 }
9914 });
9915 let first_touch = TouchId(1);
9916 dispatch_touch(window, cx, first_touch, TouchPhase::Started, 0.);
9917 cx.executor().advance_clock(Duration::from_millis(250));
9918 dispatch_touch(window, cx, first_touch, TouchPhase::Cancelled, 0.);
9919 dispatch_touch(window, cx, TouchId(2), TouchPhase::Started, 10.);
9920
9921 cx.executor().advance_clock(Duration::from_millis(251));
9922 cx.executor().run_until_parked();
9923 assert!(phases.borrow().is_empty());
9924
9925 cx.executor().advance_clock(Duration::from_millis(250));
9926 cx.executor().run_until_parked();
9927 assert_eq!(phases.borrow().as_slice(), [TouchPhase::Started]);
9928 }
9929
9930 #[gpui::test]
9931 fn test_underline_exclusions_preserve_device_geometry(cx: &mut TestAppContext) {
9932 test_underline_paint_at_scales(cx, |window| {
9933 let (numerator, denominator) = match window.scale_factor() {
9934 1.0 => (1, 1),
9935 1.25 => (5, 4),
9936 1.5 => (3, 2),
9937 2.0 => (2, 1),
9938 3.0 => (3, 1),
9939 scale => panic!("unexpected scale {scale}"),
9940 };
9941 let snap = |quarters: i32| {
9942 let scaled = quarters * numerator;
9943 let divisor = 4 * denominator;
9944 let rounded =
9945 scaled.abs() / divisor + i32::from(2 * (scaled.abs() % divisor) > divisor);
9946 ScaledPixels((scaled.signum() * rounded) as f32)
9947 };
9948 let stroke = |quarters| {
9949 if quarters == 0 {
9950 ScaledPixels(0.)
9951 } else {
9952 snap(quarters).max(ScaledPixels(1.))
9953 }
9954 };
9955
9956 for origin in [-101, -3, -2, -1, 0, 1, 2, 3, 101] {
9957 for width in [0, 1, 3, 84] {
9958 for thickness in [0, 1, 4, 7] {
9959 for wavy in [false, true] {
9960 let style = UnderlineStyle {
9961 thickness: px(thickness as f32 / 4.),
9962 color: Some(hsla(0.25, 0.5, 0.75, 0.5)),
9963 wavy,
9964 };
9965 let bounds = Bounds::new(
9966 point(snap(origin), snap(-origin)),
9967 size(
9968 stroke(width),
9969 stroke(thickness) * if wavy { 3. } else { 1. },
9970 ),
9971 );
9972 let origin = point(px(origin as f32 / 4.), px(-origin as f32 / 4.));
9973 let width = px(width as f32 / 4.);
9974 assert_eq!(window.underline_bounds(origin, width, &style), bounds);
9975 let original = paint_test_underlines(window, |window| {
9976 window.paint_underline(origin, width, &style);
9977 })
9978 .to_vec();
9979 assert_eq!(original.len(), usize::from(!bounds.is_empty()));
9980 if let Some(underline) = original.first() {
9981 assert_eq!(underline.bounds, bounds);
9982 assert_eq!(underline.thickness, stroke(thickness));
9983 assert_eq!(underline.wavy, wavy.into());
9984 assert_eq!(underline.color, hsla(0.25, 0.5, 0.75, 0.5));
9985 }
9986
9987 let underlines = paint_test_underlines(window, |window| {
9988 window.paint_underline_with_exclusions(origin, width, &style, &[]);
9989 });
9990 assert_eq!(underlines.len(), original.len());
9991 for (actual, original) in underlines.iter().zip(&original) {
9992 assert_same_underline_geometry(actual, original);
9993 assert_eq!(actual.content_mask, original.content_mask);
9994 }
9995
9996 let left = bounds.left().0 as i32;
9997 let right = bounds.right().0 as i32;
9998 let exclusions = [
9999 (15, 25),
10000 (3, 7),
10001 (5, 10),
10002 (10, 12),
10003 (0, 0),
10004 (4, 2),
10005 (-50, -1),
10006 (70, 100),
10007 ]
10008 .map(|(start, end)| {
10009 ScaledPixels((left + start) as f32)
10010 ..ScaledPixels((left + end) as f32)
10011 });
10012 let underlines = paint_test_underlines(window, |window| {
10013 window.paint_underline_with_exclusions(
10014 origin,
10015 width,
10016 &style,
10017 &exclusions,
10018 );
10019 });
10020 let expected = (left..right)
10021 .filter(|column| {
10022 !bounds.is_empty()
10023 && !exclusions.iter().any(|span| {
10024 span.contains(&ScaledPixels(*column as f32))
10025 })
10026 })
10027 .collect::<Vec<_>>();
10028 assert_eq!(underline_device_columns(underlines), expected);
10029 for underline in underlines {
10030 assert_same_underline_geometry(underline, &original[0]);
10031 }
10032 }
10033 }
10034 }
10035 }
10036 });
10037 }
10038
10039 #[gpui::test]
10040 fn test_underline_exclusions_preserve_helvetica_warning_edge(cx: &mut TestAppContext) {
10041 test_underline_paint_at_scales(cx, |window| {
10042 if window.scale_factor() != 2.0 {
10043 return;
10044 }
10045 let style = UnderlineStyle {
10046 thickness: px(1.),
10047 color: None,
10048 wavy: true,
10049 };
10050 let origin = point(px(2.888_183_8), px(15.357_917));
10051 let width = px(23.848_145) - origin.x;
10052 let original = paint_test_underlines(window, |window| {
10053 window.paint_underline(origin, width, &style);
10054 })[0];
10055 assert_eq!(original.bounds.left(), ScaledPixels(6.));
10056 assert_eq!(original.bounds.right(), ScaledPixels(48.));
10057 let point_bounds = window.underline_bounds(origin, px(10.829_102), &style);
10058 assert_eq!(point_bounds.left(), ScaledPixels(6.));
10059 assert_eq!(point_bounds.right(), ScaledPixels(28.));
10060
10061 let underlines = paint_test_underlines(window, |window| {
10062 window.paint_underline_with_exclusions(
10063 origin,
10064 width,
10065 &style,
10066 &[point_bounds.left()..point_bounds.right()],
10067 );
10068 });
10069 assert_eq!(underlines.len(), 1);
10070 assert_same_underline_geometry(&underlines[0], &original);
10071 assert_eq!(
10072 underline_device_columns(underlines),
10073 (28..48).collect::<Vec<_>>()
10074 );
10075 });
10076 }
10077
10078 #[gpui::test]
10079 fn test_underline_exclusions_preserve_content_mask_and_opacity(cx: &mut TestAppContext) {
10080 test_underline_paint_at_scales(cx, |window| {
10081 let scale = window.scale_factor();
10082 let original_mask = window.content_mask();
10083 let original_opacity = window.element_opacity();
10084 let mask = ContentMask {
10085 bounds: Bounds::from_corners(point(px(4.), px(10.)), point(px(16.), px(12.))),
10086 };
10087 let style = UnderlineStyle {
10088 thickness: px(2.),
10089 color: Some(hsla(0.25, 0.5, 0.75, 0.5)),
10090 wavy: true,
10091 };
10092 let origin = point(px(-1.25), px(9.25));
10093 let width = px(24.);
10094 window.with_content_mask(Some(mask), |window| {
10095 window.with_element_opacity(Some(0.5), |window| {
10096 window.with_element_opacity(Some(0.5), |window| {
10097 let original = paint_test_underlines(window, |window| {
10098 window.paint_underline(origin, width, &style);
10099 })[0];
10100 assert_eq!(original.color, hsla(0.25, 0.5, 0.75, 0.125));
10101 let underlines = paint_test_underlines(window, |window| {
10102 window.paint_underline_with_exclusions(
10103 origin,
10104 width,
10105 &style,
10106 &[ScaledPixels(6. * scale)..ScaledPixels(8. * scale)],
10107 );
10108 });
10109 assert_eq!(underlines.len(), 2);
10110 let expected = [(4. * scale, 6. * scale), (8. * scale, 16. * scale)].map(
10111 |(left, right)| {
10112 Bounds::from_corners(
10113 point(ScaledPixels(left), ScaledPixels((10. * scale).floor())),
10114 point(ScaledPixels(right), ScaledPixels((12. * scale).ceil())),
10115 )
10116 },
10117 );
10118 assert_eq!(
10119 underlines
10120 .iter()
10121 .map(|underline| underline.content_mask.bounds)
10122 .collect::<Vec<_>>(),
10123 expected
10124 );
10125 for underline in underlines {
10126 assert_same_underline_geometry(underline, &original);
10127 }
10128 });
10129 });
10130 });
10131 assert_eq!(window.content_mask(), original_mask);
10132 assert_eq!(window.element_opacity(), original_opacity);
10133 });
10134 }
10135
10136 #[gpui::test]
10137 fn test_underline_exclusions_adversarial_permutations(cx: &mut TestAppContext) {
10138 test_underline_paint_at_scales(cx, |window| {
10139 let style = UnderlineStyle {
10140 thickness: px(1.),
10141 color: None,
10142 wavy: true,
10143 };
10144 let origin = point(px(-4.), px(-1.));
10145 let width = px(8.);
10146 let left = (-4. * window.scale_factor()) as i32;
10147 let right = (4. * window.scale_factor()) as i32;
10148 let endpoints = [-16, -8, -1, 0, 1, 8, 16];
10149 for first_start in endpoints {
10150 for first_end in endpoints {
10151 for second_start in endpoints {
10152 for second_end in endpoints {
10153 let exclusions = [first_start..first_end, second_start..second_end];
10154 let expected = (left..right)
10155 .filter(|column| {
10156 !exclusions.iter().any(|span| span.contains(column))
10157 })
10158 .collect::<Vec<_>>();
10159 let exclusions = exclusions.map(|span| {
10160 ScaledPixels(span.start as f32)..ScaledPixels(span.end as f32)
10161 });
10162 let underlines = paint_test_underlines(window, |window| {
10163 window.paint_underline_with_exclusions(
10164 origin,
10165 width,
10166 &style,
10167 &exclusions,
10168 );
10169 });
10170 assert_eq!(
10171 underline_device_columns(underlines),
10172 expected,
10173 "{exclusions:?}"
10174 );
10175 }
10176 }
10177 }
10178 }
10179 });
10180 }
10181
10182 #[derive(Clone, Copy, PartialEq)]
10183 enum LongPressResponse {
10184 PreventDefault,
10185 StopPropagation,
10186 None,
10187 }
10188
10189 struct LongPressListener {
10190 phases: Rc<RefCell<Vec<TouchPhase>>>,
10191 response: LongPressResponse,
10192 }
10193
10194 impl Render for LongPressListener {
10195 fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
10196 let entity = cx.entity();
10197 let phases = self.phases.clone();
10198 let response = self.response;
10199 canvas(
10200 |_, _, _| {},
10201 move |_, _, window, _| {
10202 window.on_mouse_event(move |event: &LongPressEvent, phase, window, cx| {
10203 if phase != DispatchPhase::Bubble {
10204 return;
10205 }
10206 phases.borrow_mut().push(event.phase);
10207 match response {
10208 LongPressResponse::PreventDefault => {
10209 window.capture_long_press(&entity);
10210 window.prevent_default();
10211 }
10212 LongPressResponse::StopPropagation => cx.stop_propagation(),
10213 LongPressResponse::None => {}
10214 }
10215 });
10216 },
10217 )
10218 }
10219 }
10220
10221 struct UnderlineTestView(Rc<dyn Fn(&mut Window)>);
10222
10223 impl Render for UnderlineTestView {
10224 fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
10225 let paint = self.0.clone();
10226 canvas(
10227 |_, _, _| {},
10228 move |_, _, window, _| {
10229 window.frame_state.content_mask_stack.push(ContentMask {
10230 bounds: Bounds::from_corners(
10231 point(px(-1000.), px(-1000.)),
10232 point(px(1000.), px(1000.)),
10233 ),
10234 });
10235 paint(window);
10236 window.frame_state.content_mask_stack.pop();
10237 },
10238 )
10239 .size_full()
10240 }
10241 }
10242
10243 fn test_underline_paint_at_scales(
10244 cx: &mut TestAppContext,
10245 paint: impl Fn(&mut Window) + 'static,
10246 ) {
10247 let window = cx.add_window(move |_, _| UnderlineTestView(Rc::new(paint)));
10248 for scale in [1., 1.25, 1.5, 2., 3.] {
10249 cx.simulate_window_scale_factor_change(window.into(), scale);
10250 cx.update_window(window.into(), |_, window, cx| window.draw(cx).clear(cx))
10251 .unwrap();
10252 }
10253 }
10254
10255 fn paint_test_underlines<'a>(
10256 window: &'a mut Window<'_>,
10257 paint: impl FnOnce(&mut Window),
10258 ) -> &'a [Underline] {
10259 window.frame_state.next_frame.scene.clear();
10260 paint(window);
10261 &window.frame_state.next_frame.scene.underlines
10262 }
10263
10264 fn assert_same_underline_geometry(actual: &Underline, expected: &Underline) {
10265 assert_eq!(actual.bounds, expected.bounds);
10266 assert_eq!(actual.thickness, expected.thickness);
10267 assert_eq!(actual.wavy, expected.wavy);
10268 assert_eq!(actual.color, expected.color);
10269 assert_eq!(actual.pad, expected.pad);
10270 }
10271
10272 fn underline_device_columns(underlines: &[Underline]) -> Vec<i32> {
10273 underlines
10274 .iter()
10275 .flat_map(|underline| {
10276 let bounds = underline.bounds.intersect(&underline.content_mask.bounds);
10277 bounds.left().0 as i32..bounds.right().0 as i32
10278 })
10279 .collect()
10280 }
10281
10282 fn dispatch_touch<T: 'static>(
10283 window: crate::WindowHandle<T>,
10284 cx: &mut TestAppContext,
10285 id: TouchId,
10286 phase: TouchPhase,
10287 x: f32,
10288 ) {
10289 window
10290 .update(cx, |_, window, cx| {
10291 window.dispatch_event(
10292 TouchEvent {
10293 id,
10294 phase,
10295 position: point(px(x), px(0.)),
10296 predicted_position: None,
10297 force: None,
10298 }
10299 .to_platform_input(),
10300 cx,
10301 );
10302 })
10303 .unwrap();
10304 }
10305
10306 #[gpui::test]
10311 fn a_painted_imported_texture_converts_its_radii_at_paint_time(cx: &mut TestAppContext) {
10312 struct PaintedTexture {
10313 handle: ImportedTextureHandle,
10314 bounds: Bounds<Pixels>,
10315 corner_radii: Corners<Pixels>,
10316 opacity: f32,
10317 flip_v: bool,
10318 }
10319
10320 impl Render for PaintedTexture {
10321 fn render(
10322 &mut self,
10323 _window: &mut Window,
10324 _cx: &mut Context<Self>,
10325 ) -> impl IntoElement {
10326 let handle = self.handle.clone();
10327 let bounds = self.bounds;
10328 let corner_radii = self.corner_radii;
10329 let opacity = self.opacity;
10330 let flip_v = self.flip_v;
10331 gpu_canvas(move |ctx| {
10332 ctx.paint_texture(handle.clone(), corner_radii, opacity, flip_v);
10333 })
10334 .w(bounds.size.width)
10335 .h(bounds.size.height)
10336 }
10337 }
10338
10339 let corner_radii = Corners {
10340 top_left: px(4.),
10341 top_right: px(0.),
10342 bottom_right: px(0.),
10343 bottom_left: px(0.),
10344 };
10345 let window = cx.add_window(|_, _| PaintedTexture {
10346 handle: ImportedTextureHandle::new(()),
10347 bounds: Bounds::new(point(px(10.), px(20.)), size(px(30.), px(40.))),
10348 corner_radii,
10349 opacity: 0.5,
10350 flip_v: true,
10351 });
10352 cx.update_window(window.into(), |_, window, cx| window.draw(cx).clear(cx))
10353 .unwrap();
10354
10355 cx.update_window(window.into(), |_, window, _| {
10356 let painted = window.painted_imported_textures();
10357 assert_eq!(
10358 painted.len(),
10359 1,
10360 "the window should have painted the texture"
10361 );
10362
10363 let CustomRenderPrimitive::Texture {
10364 radii,
10365 opacity,
10366 flip_v,
10367 bounds,
10368 ..
10369 } = &painted[0];
10370 assert_eq!(
10371 *radii,
10372 corner_radii.scale(window.scale_factor()),
10373 "the radii must be converted to scaled pixels at paint time"
10374 );
10375 assert_eq!(*opacity, 0.5);
10376 assert!(*flip_v);
10377 assert_eq!(bounds.size.width, ScaledPixels(30. * window.scale_factor()));
10378 assert_eq!(
10379 bounds.size.height,
10380 ScaledPixels(40. * window.scale_factor())
10381 );
10382 })
10383 .unwrap();
10384 }
10385}
10386
10387#[cfg(all(test, any(feature = "inspector", debug_assertions)))]
10388mod inspector_tests {
10389 use super::*;
10390 use crate::{
10391 DivInspectorState, InspectorElementId, MouseDownEvent, StyleRefinement, TestAppContext, div,
10392 };
10393
10394 #[gpui::test]
10395 fn inspector_only_tracks_its_open_window(cx: &mut TestAppContext) {
10396 let windows = [
10397 cx.add_window(|_, cx| InspectorTestRoot {
10398 child: cx.new(|_| InspectorTestView::default()),
10399 }),
10400 cx.add_window(|_, cx| InspectorTestRoot {
10401 child: cx.new(|_| InspectorTestView::default()),
10402 }),
10403 ];
10404 for window in windows {
10405 assert_closed_inspector(window.into(), cx);
10406 }
10407 for _ in 0..2 {
10408 cx.update_window(windows[0].into(), |root, window, cx| {
10409 let root = root.downcast::<InspectorTestRoot>().expect("test root");
10410 let child_widths = root.read(cx).child.read(cx).child_widths.clone();
10411 window.toggle_inspector(cx);
10412 window.draw(cx).clear(cx);
10413 assert_eq!(child_widths.borrow().as_slice(), &[px(10.); 3]);
10414 let path = window
10415 .frame_state
10416 .rendered_frame
10417 .next_inspector_instance_ids
10418 .iter()
10419 .find_map(|(path, count)| (*count == 3).then(|| path.clone()))
10420 .expect("anonymous siblings share an inspector path");
10421 let selected_id = InspectorElementId {
10422 path,
10423 instance_id: 1,
10424 };
10425 let position = window
10426 .frame_state
10427 .rendered_frame
10428 .hitboxes
10429 .iter()
10430 .find(|hitbox| {
10431 window
10432 .frame_state
10433 .rendered_frame
10434 .inspector_hitboxes
10435 .get(&hitbox.id)
10436 == Some(&selected_id)
10437 })
10438 .expect("middle sibling is pickable")
10439 .bounds
10440 .center();
10441 window.simulate_mouse_move(position, cx);
10442 window.dispatch_event(
10443 PlatformInput::MouseDown(MouseDownEvent {
10444 position,
10445 button: MouseButton::Left,
10446 modifiers: Modifiers::default(),
10447 click_count: 1,
10448 first_mouse: false,
10449 }),
10450 cx,
10451 );
10452 window.dispatch_event(
10453 PlatformInput::MouseUp(MouseUpEvent {
10454 position,
10455 button: MouseButton::Left,
10456 modifiers: Modifiers::default(),
10457 click_count: 1,
10458 }),
10459 cx,
10460 );
10461 assert!(!window.is_inspector_picking(cx));
10462 assert_eq!(
10463 window
10464 .core
10465 .inspector
10466 .as_ref()
10467 .expect("open inspector")
10468 .read(cx)
10469 .active_element_id(),
10470 Some(&selected_id)
10471 );
10472 window.draw(cx).clear(cx);
10473 window.with_inspector_state::<DivInspectorState, _>(
10474 Some(&selected_id),
10475 cx,
10476 |state, _| {
10477 let state = state.as_mut().expect("selected div has style state");
10478 assert_eq!(
10479 state.base_style.size.width,
10480 Some(crate::Length::from(px(10.)))
10481 );
10482 state.base_style.size.width = Some(crate::Length::from(px(25.)));
10483 },
10484 );
10485 window.refresh();
10486 window.draw(cx).clear(cx);
10487 assert_eq!(
10488 child_widths.borrow().as_slice(),
10489 &[px(10.), px(25.), px(10.)]
10490 );
10491 })
10492 .expect("pick and edit a cached child");
10493 assert_closed_inspector(windows[1].into(), cx);
10494 windows[0]
10495 .update(cx, |_, window, cx| window.toggle_inspector(cx))
10496 .expect("close inspector");
10497 assert_closed_inspector(windows[0].into(), cx);
10498 }
10499 }
10500
10501 struct InspectorTestRoot {
10502 child: Entity<InspectorTestView>,
10503 }
10504
10505 impl Render for InspectorTestRoot {
10506 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
10507 self.child
10508 .clone()
10509 .cached(StyleRefinement::default().size(px(100.)))
10510 }
10511 }
10512
10513 #[derive(Default)]
10514 struct InspectorTestView {
10515 child_widths: Rc<RefCell<Vec<Pixels>>>,
10516 }
10517
10518 impl Render for InspectorTestView {
10519 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
10520 let child_widths = self.child_widths.clone();
10521 div()
10522 .on_children_prepainted(move |bounds, _, _| {
10523 *child_widths.borrow_mut() =
10524 bounds.iter().map(|bounds| bounds.size.width).collect();
10525 })
10526 .with_dynamic_prepaint_order(|_, _| SmallVec::from_iter([2, 0, 1]))
10527 .id("inspector-root")
10528 .flex()
10529 .children((0..3).map(|_| div().size(px(10.)).flex_shrink_0()))
10530 }
10531 }
10532
10533 fn assert_closed_inspector(window: AnyWindowHandle, cx: &mut TestAppContext) {
10534 cx.update_window(window, |root, window, cx| {
10535 window.draw(cx).clear(cx);
10536 window.draw(cx).clear(cx);
10537 let root = root.downcast::<InspectorTestRoot>().expect("test root");
10538 assert_eq!(
10539 root.read(cx)
10540 .child
10541 .read(cx)
10542 .child_widths
10543 .borrow()
10544 .as_slice(),
10545 &[px(10.); 3]
10546 );
10547 for frame in [
10548 &window.frame_state.rendered_frame,
10549 &window.frame_state.next_frame,
10550 ] {
10551 assert_eq!(frame.next_inspector_instance_ids.capacity(), 0);
10552 assert_eq!(frame.inspector_hitboxes.capacity(), 0);
10553 }
10554 })
10555 .expect("closed inspector has no bookkeeping and no style overrides");
10556 }
10557}