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, DEFAULT_WINDOW_SIZE,
11 Decorations, DevicePixels, DispatchActionListener, DispatchEventResult, DispatchNodeId,
12 DispatchTree, DisplayId, Edges, Effect, Entity, EntityId, EventEmitter, FileDropEvent, FontId,
13 Global, GlobalElementId, GlyphId, GpuSpecs, Hsla, InputHandler, IsZero, KeyBinding, KeyContext,
14 KeyDownEvent, KeyEvent, Keystroke, KeystrokeEvent, LayoutId, LineLayoutIndex, MeasureContext,
15 MeasureHandles, Modifiers, ModifiersChangedEvent, MonochromeSprite, MouseButton, MouseEvent,
16 MouseMoveEvent, MouseUpEvent, Path, Pixels, PlatformAtlas, PlatformDisplay, PlatformInput,
17 PlatformInputHandler, PlatformWindow, Point, PolychromeSprite, Priority, PromptButton,
18 PromptLevel, Quad, Render, RenderGlyphParams, RenderImage, RenderImageParams, RenderSvgParams,
19 Replay, ResizeEdge, SMOOTH_SVG_SCALE_FACTOR, SUBPIXEL_VARIANTS_X, SUBPIXEL_VARIANTS_Y,
20 ScaledPixels, Scene, Shadow, SharedString, Size, StrikethroughStyle, Style, SubpixelSprite,
21 SubscriberSet, Subscription, SystemWindowTab, SystemWindowTabController, TabStopMap, Task, TextInputConfiguration, TextInputStateChange, TextRenderingMode,
22 TextStyle, TextStyleRefinement, ThermalState, TransformationMatrix, Underline, UnderlineStyle,
23 WindowAppearance, WindowBackgroundAppearance, WindowBounds, WindowControlArea, WindowControls,
24 WindowDecorations, WindowId, WindowMetrics, WindowOptions, WindowParams, WindowTextSystem,
25 WindowVisibility,
26 new_platform_input_handler, point, prelude::*, px, rems, size, transparent_black,
27};
28
29use crate::TouchEvent;
30use crate::gestures::{GestureTuning, RecognizedTouchGesture, TouchGestureRecognizer};
31use anyhow::{Context as _, Result, anyhow};
32use arc_swap::ArcSwap;
33use collections::{FxHashMap, FxHashSet};
34use derive_more::{Deref, DerefMut};
35use futures::channel::oneshot;
36use gpui_engine::FrameSession;
37use gpui_util::post_inc;
38use gpui_util::{ResultExt, measure};
39use itertools::FoldWhile::{Continue, Done};
40use itertools::Itertools;
41use parking_lot::RwLock;
42use raw_window_handle::{HandleError, HasDisplayHandle, HasWindowHandle};
43use refineable::Refineable;
44use scheduler::Instant;
45use slotmap::SlotMap;
46use smallvec::SmallVec;
47use std::{
48 any::{Any, TypeId},
49 borrow::Cow,
50 cell::{Cell, RefCell},
51 cmp,
52 fmt::{Debug, Display},
53 hash::{Hash, Hasher},
54 marker::PhantomData,
55 mem,
56 ops::{DerefMut, Range},
57 rc::Rc,
58 sync::{
59 Arc, Weak,
60 atomic::{AtomicBool, AtomicUsize, Ordering::SeqCst},
61 },
62 time::Duration,
63};
64use uuid::Uuid;
65
66pub(crate) mod a11y;
67mod frame_pipeline;
68#[cfg(target_os = "macos")]
69mod mac;
70mod prompts;
71
72pub use a11y::A11ySubtreeBuilder;
73pub use frame_pipeline::{FramePipeline, StandardImmediatePipeline};
74#[cfg(target_os = "macos")]
75pub use mac::*;
76
77use self::a11y::A11y;
78#[cfg(not(target_family = "wasm"))]
79use self::a11y::ROOT_NODE_ID;
80use crate::engine_layout::to_engine_layout_style;
81use crate::util::{
82 atomic_incr_if_not_zero, ceil_to_device_pixel, floor_to_device_pixel, round_half_toward_zero,
83 round_half_toward_zero_f64, round_stroke_to_device_pixel, round_to_device_pixel,
84};
85pub use prompts::*;
86
87pub const DEFAULT_ADDITIONAL_WINDOW_SIZE: Size<Pixels> = Size {
90 width: Pixels(900.),
91 height: Pixels(750.),
92};
93
94struct WindowMeasureContext<'a> {
101 core: &'a mut WindowHostCore,
102 frame_state: &'a mut WindowFrameState,
103 cx: &'a mut App,
104}
105
106impl MeasureContext for WindowMeasureContext<'_> {
107 fn handles(&mut self) -> MeasureHandles<'_> {
108 MeasureHandles {
109 window: (self.core, self.frame_state),
110 app: self.cx,
111 }
112 }
113}
114
115#[derive(Default, Copy, Clone, Debug, Eq, PartialEq)]
117pub enum DispatchPhase {
118 #[default]
123 Bubble,
124 Capture,
130}
131
132impl DispatchPhase {
133 #[inline]
135 pub fn bubble(self) -> bool {
136 self == DispatchPhase::Bubble
137 }
138
139 #[inline]
141 pub fn capture(self) -> bool {
142 self == DispatchPhase::Capture
143 }
144}
145
146struct WindowInvalidatorInner {
147 #[cfg(feature = "profiler")]
148 pub window_id: WindowId,
149 pub dirty: bool,
150 pub draw_phase: DrawPhase,
151 pub dirty_views: FxHashSet<EntityId>,
152 pub update_count: usize,
153 #[cfg(feature = "profiler")]
154 pub frame_dirty: FrameDirtyAccumulator,
155 pub platform_waker: Option<Rc<dyn Fn()>>,
156}
157
158#[cfg(feature = "profiler")]
164#[derive(Default)]
165struct FrameDirtyAccumulator {
166 dirty_at: Option<Instant>,
167 invalidations: u64,
168}
169
170#[derive(Clone)]
171pub(crate) struct WindowInvalidator {
172 inner: Rc<RefCell<WindowInvalidatorInner>>,
173}
174
175impl WindowInvalidator {
176 pub fn new(#[allow(unused_variables)] window_id: WindowId) -> Self {
177 WindowInvalidator {
178 inner: Rc::new(RefCell::new(WindowInvalidatorInner {
179 #[cfg(feature = "profiler")]
180 window_id,
181 dirty: true,
182 draw_phase: DrawPhase::None,
183 dirty_views: FxHashSet::default(),
184 update_count: 0,
185 #[cfg(feature = "profiler")]
186 frame_dirty: FrameDirtyAccumulator::default(),
187 platform_waker: None,
188 })),
189 }
190 }
191
192 pub fn invalidate_view(&self, entity: EntityId, cx: &mut App) -> bool {
193 let mut inner = self.inner.borrow_mut();
194 inner.update_count += 1;
195 inner.dirty_views.insert(entity);
196 if inner.draw_phase == DrawPhase::None {
197 #[cfg(feature = "profiler")]
198 let dirty_at = Self::record_frame_dirty(&mut inner);
199 let became_dirty = !inner.dirty;
200 inner.dirty = true;
201 let waker = became_dirty.then(|| inner.platform_waker.clone()).flatten();
202 #[cfg(feature = "profiler")]
203 let window_id = inner.window_id;
204 drop(inner);
205 #[cfg(feature = "profiler")]
206 if became_dirty {
207 profiler::journal::record_frame_pending(window_id, dirty_at);
208 }
209 cx.push_effect(Effect::Notify { emitter: entity });
210 if let Some(waker) = waker {
211 waker();
212 }
213 true
214 } else {
215 false
216 }
217 }
218
219 pub fn is_dirty(&self) -> bool {
220 self.inner.borrow().dirty
221 }
222
223 pub fn set_dirty(&self, dirty: bool) {
224 let mut inner = self.inner.borrow_mut();
225 let became_dirty = dirty && !inner.dirty;
226 inner.dirty = dirty;
227 if dirty {
228 inner.update_count += 1;
229 }
230 #[cfg(feature = "profiler")]
231 let dirty_at = dirty.then(|| Self::record_frame_dirty(&mut inner));
232 let waker = became_dirty.then(|| inner.platform_waker.clone()).flatten();
233 #[cfg(feature = "profiler")]
234 let window_id = inner.window_id;
235 drop(inner);
236 #[cfg(feature = "profiler")]
237 if became_dirty && let Some(dirty_at) = dirty_at {
238 profiler::journal::record_frame_pending(window_id, dirty_at);
239 }
240 if let Some(waker) = waker {
241 waker();
242 }
243 }
244
245 pub fn set_platform_waker(&self, waker: Option<Rc<dyn Fn()>>) {
246 let mut inner = self.inner.borrow_mut();
247 inner.platform_waker = waker;
248 let waker = inner.dirty.then(|| inner.platform_waker.clone()).flatten();
249 drop(inner);
250 if let Some(waker) = waker {
251 waker();
252 }
253 }
254
255 pub fn wake_platform(&self) {
259 let waker = self.inner.borrow().platform_waker.clone();
260 if let Some(waker) = waker {
261 waker();
262 }
263 }
264
265 pub fn set_phase(&self, phase: DrawPhase) {
266 self.inner.borrow_mut().draw_phase = phase
267 }
268
269 pub fn update_count(&self) -> usize {
270 self.inner.borrow().update_count
271 }
272
273 #[cfg(feature = "profiler")]
274 fn record_frame_dirty(inner: &mut WindowInvalidatorInner) -> Instant {
275 let dirty_at = *inner.frame_dirty.dirty_at.get_or_insert_with(Instant::now);
276 inner.frame_dirty.invalidations += 1;
277 dirty_at
278 }
279
280 #[cfg(feature = "profiler")]
281 fn take_frame_dirty(&self) -> FrameDirtyAccumulator {
282 mem::take(&mut self.inner.borrow_mut().frame_dirty)
283 }
284
285 pub fn take_views(&self) -> FxHashSet<EntityId> {
286 mem::take(&mut self.inner.borrow_mut().dirty_views)
287 }
288
289 pub fn replace_views(&self, views: FxHashSet<EntityId>) {
290 self.inner.borrow_mut().dirty_views = views;
291 }
292
293 pub fn not_drawing(&self) -> bool {
294 self.inner.borrow().draw_phase == DrawPhase::None
295 }
296
297 #[track_caller]
298 pub fn debug_assert_paint(&self) {
299 debug_assert!(
300 matches!(self.inner.borrow().draw_phase, DrawPhase::Paint),
301 "this method can only be called during paint"
302 );
303 }
304
305 #[track_caller]
306 pub fn debug_assert_prepaint(&self) {
307 debug_assert!(
308 matches!(self.inner.borrow().draw_phase, DrawPhase::Prepaint),
309 "this method can only be called during request_layout, or prepaint"
310 );
311 }
312
313 #[track_caller]
314 pub fn debug_assert_paint_or_prepaint(&self) {
315 debug_assert!(
316 matches!(
317 self.inner.borrow().draw_phase,
318 DrawPhase::Paint | DrawPhase::Prepaint
319 ),
320 "this method can only be called during request_layout, prepaint, or paint"
321 );
322 }
323}
324
325type AnyObserver = Box<dyn FnMut(&mut Window, &mut App) -> bool + 'static>;
326
327pub(crate) type AnyWindowFocusListener =
328 Box<dyn FnMut(&WindowFocusEvent, &mut Window, &mut App) -> bool + 'static>;
329
330pub(crate) struct WindowFocusEvent {
331 pub(crate) previous_focus_path: SmallVec<[FocusId; 8]>,
332 pub(crate) current_focus_path: SmallVec<[FocusId; 8]>,
333}
334
335impl WindowFocusEvent {
336 pub fn is_focus_in(&self, focus_id: FocusId) -> bool {
337 !self.previous_focus_path.contains(&focus_id) && self.current_focus_path.contains(&focus_id)
338 }
339
340 pub fn is_focus_out(&self, focus_id: FocusId) -> bool {
341 self.previous_focus_path.contains(&focus_id) && !self.current_focus_path.contains(&focus_id)
342 }
343}
344
345pub struct FocusOutEvent {
347 pub blurred: WeakFocusHandle,
349}
350
351slotmap::new_key_type! {
352 pub struct FocusId;
354}
355
356thread_local! {
357 pub(crate) static ELEMENT_ARENA: RefCell<Arena> = RefCell::new(Arena::new(1024 * 1024));
360
361 static CURRENT_ELEMENT_ARENA: Cell<Option<*const RefCell<Arena>>> = const { Cell::new(None) };
365}
366
367fn draw_in_progress() -> bool {
378 CURRENT_ELEMENT_ARENA.with(|current| current.get().is_some())
379}
380
381pub(crate) fn with_element_arena<R>(f: impl FnOnce(&mut Arena) -> R) -> R {
384 CURRENT_ELEMENT_ARENA.with(|current| {
385 if let Some(arena_ptr) = current.get() {
386 let arena_cell = unsafe { &*arena_ptr };
389 f(&mut arena_cell.borrow_mut())
390 } else {
391 ELEMENT_ARENA.with_borrow_mut(f)
392 }
393 })
394}
395
396pub(crate) struct ElementArenaScope {
411 entered: *const RefCell<Arena>,
414 previous: Option<*const RefCell<Arena>>,
415 exited: bool,
416}
417
418impl ElementArenaScope {
419 pub(crate) fn enter(arena: &RefCell<Arena>) -> Self {
421 arena.borrow_mut().begin_scope();
422 let previous = CURRENT_ELEMENT_ARENA.with(|current| {
423 let prev = current.get();
424 current.set(Some(arena as *const RefCell<Arena>));
425 prev
426 });
427 Self {
428 entered: arena as *const RefCell<Arena>,
429 previous,
430 exited: false,
431 }
432 }
433
434 pub(crate) fn exit(mut self, arena: &RefCell<Arena>) -> ArenaClearNeeded {
443 assert!(
444 std::ptr::eq(self.entered, arena),
445 "ElementArenaScope::exit called with a different arena than was entered"
446 );
447 self.exited = true;
448 ArenaClearNeeded::new(arena)
453 }
454}
455
456impl Drop for ElementArenaScope {
457 fn drop(&mut self) {
458 CURRENT_ELEMENT_ARENA.with(|current| {
465 current.set(self.previous);
466 });
467 unsafe { &*self.entered }.borrow_mut().end_scope();
471 if !self.exited && !std::thread::panicking() {
472 debug_assert!(false, "ElementArenaScope dropped without calling exit()");
473 log::error!(
474 "ElementArenaScope dropped without calling exit(); \
475 the arena clear for this draw was never requested"
476 );
477 }
478 }
479}
480
481#[must_use]
483pub struct ArenaClearNeeded {
484 arena: *const RefCell<Arena>,
487}
488
489impl ArenaClearNeeded {
490 fn new(arena: &RefCell<Arena>) -> Self {
493 Self {
494 arena: arena as *const RefCell<Arena>,
495 }
496 }
497
498 pub fn clear(self, cx: &mut App) {
507 assert!(
508 std::ptr::eq(self.arena, &cx.element_arena),
509 "ArenaClearNeeded::clear called with a different App than the draw ran against"
510 );
511 cx.element_arena.borrow_mut().clear();
512 }
513}
514
515pub(crate) type FocusMap = RwLock<SlotMap<FocusId, FocusRef>>;
516pub(crate) struct FocusRef {
517 pub(crate) ref_count: AtomicUsize,
518 pub(crate) tab_index: isize,
519 pub(crate) tab_stop: bool,
520}
521
522impl FocusId {
523 pub fn is_focused(&self, window: &Window) -> bool {
525 window.core.focus == Some(*self)
526 }
527
528 pub fn contains_focused(&self, window: &Window, cx: &App) -> bool {
531 window
532 .focused(cx)
533 .is_some_and(|focused| self.contains(focused.id, window))
534 }
535
536 pub fn within_focused(&self, window: &Window, cx: &App) -> bool {
539 let focused = window.focused(cx);
540 focused.is_some_and(|focused| focused.id.contains(*self, window))
541 }
542
543 pub(crate) fn contains(&self, other: Self, window: &Window) -> bool {
545 window
546 .frame_state
547 .rendered_frame
548 .dispatch_tree
549 .focus_contains(*self, other)
550 }
551}
552
553pub struct FocusHandle {
555 pub(crate) id: FocusId,
556 handles: Arc<FocusMap>,
557 pub tab_index: isize,
559 pub tab_stop: bool,
561}
562
563impl std::fmt::Debug for FocusHandle {
564 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
565 f.write_fmt(format_args!("FocusHandle({:?})", self.id))
566 }
567}
568
569impl FocusHandle {
570 pub(crate) fn new(handles: &Arc<FocusMap>) -> Self {
571 let id = handles.write().insert(FocusRef {
572 ref_count: AtomicUsize::new(1),
573 tab_index: 0,
574 tab_stop: false,
575 });
576
577 Self {
578 id,
579 tab_index: 0,
580 tab_stop: false,
581 handles: handles.clone(),
582 }
583 }
584
585 pub(crate) fn for_id(id: FocusId, handles: &Arc<FocusMap>) -> Option<Self> {
586 let lock = handles.read();
587 let focus = lock.get(id)?;
588 if atomic_incr_if_not_zero(&focus.ref_count) == 0 {
589 return None;
590 }
591 Some(Self {
592 id,
593 tab_index: focus.tab_index,
594 tab_stop: focus.tab_stop,
595 handles: handles.clone(),
596 })
597 }
598
599 pub fn tab_index(mut self, index: isize) -> Self {
601 self.tab_index = index;
602 if let Some(focus) = self.handles.write().get_mut(self.id) {
603 focus.tab_index = index;
604 }
605 self
606 }
607
608 pub fn tab_stop(mut self, tab_stop: bool) -> Self {
612 self.tab_stop = tab_stop;
613 if let Some(focus) = self.handles.write().get_mut(self.id) {
614 focus.tab_stop = tab_stop;
615 }
616 self
617 }
618
619 pub fn downgrade(&self) -> WeakFocusHandle {
621 WeakFocusHandle {
622 id: self.id,
623 handles: Arc::downgrade(&self.handles),
624 }
625 }
626
627 pub fn focus(&self, window: &mut Window, cx: &mut App) {
629 window.focus(self, cx)
630 }
631
632 pub fn is_focused(&self, window: &Window) -> bool {
634 self.id.is_focused(window)
635 }
636
637 pub fn contains_focused(&self, window: &Window, cx: &App) -> bool {
640 self.id.contains_focused(window, cx)
641 }
642
643 pub fn within_focused(&self, window: &Window, cx: &mut App) -> bool {
646 self.id.within_focused(window, cx)
647 }
648
649 pub fn contains(&self, other: &Self, window: &Window) -> bool {
651 self.id.contains(other.id, window)
652 }
653
654 pub fn dispatch_action(&self, action: &dyn Action, window: &mut Window, cx: &mut App) {
656 if let Some(node_id) = window
657 .frame_state
658 .rendered_frame
659 .dispatch_tree
660 .focusable_node_id(self.id)
661 {
662 window.dispatch_action_on_node(node_id, action, cx)
663 }
664 }
665}
666
667impl Clone for FocusHandle {
668 fn clone(&self) -> Self {
669 Self::for_id(self.id, &self.handles).unwrap()
670 }
671}
672
673impl PartialEq for FocusHandle {
674 fn eq(&self, other: &Self) -> bool {
675 self.id == other.id
676 }
677}
678
679impl Eq for FocusHandle {}
680
681impl Drop for FocusHandle {
682 fn drop(&mut self) {
683 self.handles
684 .read()
685 .get(self.id)
686 .unwrap()
687 .ref_count
688 .fetch_sub(1, SeqCst);
689 }
690}
691
692#[derive(Clone, Debug)]
694pub struct WeakFocusHandle {
695 pub(crate) id: FocusId,
696 pub(crate) handles: Weak<FocusMap>,
697}
698
699impl WeakFocusHandle {
700 pub fn upgrade(&self) -> Option<FocusHandle> {
702 let handles = self.handles.upgrade()?;
703 FocusHandle::for_id(self.id, &handles)
704 }
705}
706
707impl PartialEq for WeakFocusHandle {
708 fn eq(&self, other: &WeakFocusHandle) -> bool {
709 self.id == other.id
710 }
711}
712
713impl Eq for WeakFocusHandle {}
714
715impl PartialEq<FocusHandle> for WeakFocusHandle {
716 fn eq(&self, other: &FocusHandle) -> bool {
717 self.id == other.id
718 }
719}
720
721impl PartialEq<WeakFocusHandle> for FocusHandle {
722 fn eq(&self, other: &WeakFocusHandle) -> bool {
723 self.id == other.id
724 }
725}
726
727pub trait Focusable: 'static {
730 fn focus_handle(&self, cx: &App) -> FocusHandle;
732}
733
734impl<V: Focusable> Focusable for Entity<V> {
735 fn focus_handle(&self, cx: &App) -> FocusHandle {
736 self.read(cx).focus_handle(cx)
737 }
738}
739
740pub trait ManagedView: Focusable + EventEmitter<DismissEvent> + Render {}
743
744impl<M: Focusable + EventEmitter<DismissEvent> + Render> ManagedView for M {}
745
746pub struct DismissEvent;
748
749type FrameCallback = Box<dyn FnOnce(&mut Window, &mut App)>;
750
751pub(crate) type AnyMouseListener =
752 Box<dyn FnMut(&dyn Any, DispatchPhase, &mut Window, &mut App) + 'static>;
753
754#[derive(Clone)]
755pub(crate) struct CursorStyleRequest {
756 pub(crate) hitbox_id: Option<HitboxId>,
757 pub(crate) style: CursorStyle,
758}
759
760#[derive(Default, Eq, PartialEq)]
761pub(crate) struct HitTest {
762 pub(crate) ids: SmallVec<[HitboxId; 8]>,
763 pub(crate) hover_hitbox_count: usize,
764}
765
766#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
768pub struct HitboxId(u64);
769
770#[cfg(feature = "test-support")]
771impl HitboxId {
772 pub const fn placeholder() -> Self {
777 Self(0)
778 }
779}
780
781impl HitboxId {
782 pub fn is_hovered(self, window: &Window) -> bool {
789 if window.core.captured_hitbox == Some(self) {
791 return true;
792 }
793 if window.last_input_was_keyboard() {
794 return false;
795 }
796 self.hit_test(window)
797 }
798
799 pub(crate) fn is_hovered_ignoring_last_input(self, window: &Window) -> bool {
804 if window.core.captured_hitbox == Some(self) {
806 return true;
807 }
808 self.hit_test(window)
809 }
810
811 fn hit_test(self, window: &Window) -> bool {
812 let hit_test = &window.core.mouse_hit_test;
813 for id in hit_test.ids.iter().take(hit_test.hover_hitbox_count) {
814 if self == *id {
815 return true;
816 }
817 }
818 false
819 }
820
821 pub fn should_handle_scroll(self, window: &Window) -> bool {
826 window.core.mouse_hit_test.ids.contains(&self)
827 }
828
829 fn next(mut self) -> HitboxId {
830 HitboxId(self.0.wrapping_add(1))
831 }
832}
833
834#[derive(Clone, Debug, Deref)]
837pub struct Hitbox {
838 pub id: HitboxId,
840 #[deref]
842 pub bounds: Bounds<Pixels>,
843 pub content_mask: ContentMask<Pixels>,
845 pub behavior: HitboxBehavior,
847}
848
849impl Hitbox {
850 pub fn is_hovered(&self, window: &Window) -> bool {
867 self.id.is_hovered(window)
868 }
869
870 pub fn is_hovered_at(&self, position: Point<Pixels>, window: &Window) -> bool {
873 let hit_test = window.frame_state.rendered_frame.hit_test(position);
874 hit_test
875 .ids
876 .iter()
877 .take(hit_test.hover_hitbox_count)
878 .any(|id| self.id == *id)
879 }
880
881 pub fn should_handle_scroll(&self, window: &Window) -> bool {
888 self.id.should_handle_scroll(window)
889 }
890}
891
892#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
894pub enum HitboxBehavior {
895 #[default]
897 Normal,
898
899 BlockMouse,
921
922 BlockMouseExceptScroll,
949}
950
951#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
953pub struct TooltipId(usize);
954
955impl TooltipId {
956 pub fn is_hovered(&self, window: &Window) -> bool {
958 window
959 .frame_state
960 .tooltip_bounds
961 .as_ref()
962 .is_some_and(|tooltip_bounds| {
963 tooltip_bounds.id == *self
964 && tooltip_bounds.bounds.contains(&window.mouse_position())
965 })
966 }
967}
968
969pub(crate) struct TooltipBounds {
970 id: TooltipId,
971 bounds: Bounds<Pixels>,
972}
973
974#[derive(Clone)]
975pub(crate) struct TooltipRequest {
976 id: TooltipId,
977 tooltip: AnyTooltip,
978}
979
980pub(crate) struct DeferredDraw {
981 current_view: EntityId,
982 priority: usize,
983 parent_node: DispatchNodeId,
984 element_id_stack: SmallVec<[ElementId; 32]>,
985 text_style_stack: Vec<TextStyleRefinement>,
986 content_mask: Option<ContentMask<Pixels>>,
987 rem_size: Pixels,
988 element: Option<AnyElement>,
989 absolute_offset: Point<Pixels>,
990 prepaint_range: Range<PrepaintStateIndex>,
991 paint_range: Range<PaintIndex>,
992}
993
994pub(crate) struct Frame {
995 pub(crate) focus: Option<FocusId>,
996 pub(crate) window_active: bool,
997 pub(crate) element_states: FxHashMap<(GlobalElementId, TypeId), ElementStateBox>,
998 accessed_element_states: Vec<(GlobalElementId, TypeId)>,
999 pub(crate) mouse_listeners: Vec<Option<AnyMouseListener>>,
1000 pub(crate) dispatch_tree: DispatchTree,
1001 pub(crate) scene: Scene,
1002 pub(crate) hitboxes: Vec<Hitbox>,
1003 pub(crate) window_control_hitboxes: Vec<(WindowControlArea, Hitbox)>,
1004 pub(crate) deferred_draws: Vec<DeferredDraw>,
1005 pub(crate) input_handlers: Vec<Option<PlatformInputHandler>>,
1006 pub(crate) tooltip_requests: Vec<Option<TooltipRequest>>,
1007 pub(crate) cursor_styles: Vec<CursorStyleRequest>,
1008 #[cfg(any(test, feature = "test-support"))]
1009 pub(crate) debug_bounds: FxHashMap<String, Bounds<Pixels>>,
1010 #[cfg(any(feature = "inspector", debug_assertions))]
1011 pub(crate) next_inspector_instance_ids: FxHashMap<Rc<crate::InspectorElementPath>, usize>,
1012 #[cfg(any(feature = "inspector", debug_assertions))]
1013 pub(crate) inspector_hitboxes: FxHashMap<HitboxId, crate::InspectorElementId>,
1014 pub(crate) tab_stops: TabStopMap,
1015}
1016
1017#[derive(Clone, Default)]
1018pub(crate) struct PrepaintStateIndex {
1019 hitboxes_index: usize,
1020 tooltips_index: usize,
1021 deferred_draws_index: usize,
1022 dispatch_tree_index: usize,
1023 accessed_element_states_index: usize,
1024 line_layout_index: LineLayoutIndex,
1025}
1026
1027#[derive(Clone, Default)]
1028pub(crate) struct PaintIndex {
1029 scene_index: usize,
1030 mouse_listeners_index: usize,
1031 input_handlers_index: usize,
1032 cursor_styles_index: usize,
1033 accessed_element_states_index: usize,
1034 tab_handle_index: usize,
1035 line_layout_index: LineLayoutIndex,
1036}
1037
1038impl Frame {
1039 pub(crate) fn new(dispatch_tree: DispatchTree) -> Self {
1040 Frame {
1041 focus: None,
1042 window_active: false,
1043 element_states: FxHashMap::default(),
1044 accessed_element_states: Vec::new(),
1045 mouse_listeners: Vec::new(),
1046 dispatch_tree,
1047 scene: Scene::default(),
1048 hitboxes: Vec::new(),
1049 window_control_hitboxes: Vec::new(),
1050 deferred_draws: Vec::new(),
1051 input_handlers: Vec::new(),
1052 tooltip_requests: Vec::new(),
1053 cursor_styles: Vec::new(),
1054
1055 #[cfg(any(test, feature = "test-support"))]
1056 debug_bounds: FxHashMap::default(),
1057
1058 #[cfg(any(feature = "inspector", debug_assertions))]
1059 next_inspector_instance_ids: FxHashMap::default(),
1060
1061 #[cfg(any(feature = "inspector", debug_assertions))]
1062 inspector_hitboxes: FxHashMap::default(),
1063 tab_stops: TabStopMap::default(),
1064 }
1065 }
1066
1067 pub(crate) fn clear(&mut self) {
1068 self.element_states.clear();
1069 self.accessed_element_states.clear();
1070 self.mouse_listeners.clear();
1071 self.dispatch_tree.clear();
1072 self.scene.clear();
1073 self.input_handlers.clear();
1074 self.tooltip_requests.clear();
1075 self.cursor_styles.clear();
1076 self.hitboxes.clear();
1077 self.window_control_hitboxes.clear();
1078 self.deferred_draws.clear();
1079 self.tab_stops.clear();
1080 self.focus = None;
1081
1082 #[cfg(any(test, feature = "test-support"))]
1083 {
1084 self.debug_bounds.clear();
1085 }
1086
1087 #[cfg(any(feature = "inspector", debug_assertions))]
1088 {
1089 self.next_inspector_instance_ids.clear();
1090 self.inspector_hitboxes.clear();
1091 }
1092 }
1093
1094 pub(crate) fn cursor_style(&self, window: &Window) -> Option<CursorStyle> {
1095 self.cursor_styles
1096 .iter()
1097 .rev()
1098 .fold_while(None, |style, request| match request.hitbox_id {
1099 None => Done(Some(request.style)),
1100 Some(hitbox_id) => Continue(style.or_else(|| {
1101 hitbox_id
1102 .is_hovered_ignoring_last_input(window)
1103 .then_some(request.style)
1104 })),
1105 })
1106 .into_inner()
1107 }
1108
1109 pub(crate) fn hit_test(&self, position: Point<Pixels>) -> HitTest {
1110 let mut set_hover_hitbox_count = false;
1111 let mut hit_test = HitTest::default();
1112 for hitbox in self.hitboxes.iter().rev() {
1113 let bounds = hitbox.bounds.intersect(&hitbox.content_mask.bounds);
1114 if bounds.contains(&position) {
1115 hit_test.ids.push(hitbox.id);
1116 if !set_hover_hitbox_count
1117 && hitbox.behavior == HitboxBehavior::BlockMouseExceptScroll
1118 {
1119 hit_test.hover_hitbox_count = hit_test.ids.len();
1120 set_hover_hitbox_count = true;
1121 }
1122 if hitbox.behavior == HitboxBehavior::BlockMouse {
1123 break;
1124 }
1125 }
1126 }
1127 if !set_hover_hitbox_count {
1128 hit_test.hover_hitbox_count = hit_test.ids.len();
1129 }
1130 hit_test
1131 }
1132
1133 pub(crate) fn focus_path(&self) -> SmallVec<[FocusId; 8]> {
1134 self.focus
1135 .map(|focus_id| self.dispatch_tree.focus_path(focus_id))
1136 .unwrap_or_default()
1137 }
1138
1139 pub(crate) fn finish(&mut self, prev_frame: &mut Self) {
1140 for element_state_key in &self.accessed_element_states {
1141 if let Some((element_state_key, element_state)) =
1142 prev_frame.element_states.remove_entry(element_state_key)
1143 {
1144 self.element_states.insert(element_state_key, element_state);
1145 }
1146 }
1147
1148 self.scene.finish();
1149 }
1150}
1151
1152#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
1153enum InputModality {
1154 Mouse,
1155 Keyboard,
1156 Touch,
1157}
1158
1159#[cfg(debug_assertions)]
1169#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1170pub(crate) enum FramePhase {
1171 Idle,
1173 Begun,
1175 Evaluated,
1177 LaidOut,
1179 Painted,
1181 Finished,
1183 Completed,
1185}
1186
1187#[cfg(debug_assertions)]
1188impl FramePhase {
1189 #[track_caller]
1191 fn enter(&mut self, from: &[FramePhase], next: FramePhase, method: &'static str) {
1192 debug_assert!(
1193 from.contains(self),
1194 "{method} ran while the frame was {self:?}, but it must follow one of {from:?}"
1195 );
1196 *self = next;
1197 }
1198}
1199
1200pub(crate) struct WindowFrameState {
1201 rem_size_override_stack: SmallVec<[Pixels; 8]>,
1206 layout_session: Rc<FrameSession>,
1207 pub(crate) inspector_element_id: Option<crate::InspectorElementId>,
1212 pub(crate) dirty_views: FxHashSet<EntityId>,
1214 focus_lost_path: SmallVec<[FocusId; 8]>,
1217 pub(crate) element_id_stack: SmallVec<[ElementId; 32]>,
1218 pub(crate) text_style_stack: Vec<TextStyleRefinement>,
1219 pub(crate) rendered_entity_stack: Vec<EntityId>,
1220 pub(crate) element_offset_stack: Vec<Point<Pixels>>,
1221 pub(crate) element_opacity: f32,
1222 pub(crate) content_mask_stack: Vec<ContentMask<Pixels>>,
1223 pub(crate) requested_autoscroll: Option<Bounds<Pixels>>,
1224 pub(crate) image_cache_stack: Vec<AnyImageCache>,
1225 pub(crate) rendered_frame: Frame,
1226 pub(crate) next_frame: Frame,
1227 next_hitbox_id: HitboxId,
1228 pub(crate) next_tooltip_id: TooltipId,
1229 pub(crate) tooltip_bounds: Option<TooltipBounds>,
1230 #[cfg(debug_assertions)]
1232 frame_phase: FramePhase,
1233}
1234
1235pub(crate) struct WindowHostCore {
1241 pub(crate) handle: AnyWindowHandle,
1242 pub(crate) invalidator: WindowInvalidator,
1243 frame_pipeline: Rc<RefCell<Box<dyn FramePipeline>>>,
1248 pub(crate) removed: bool,
1249 metrics: Arc<ArcSwap<WindowMetrics>>,
1251 pub(crate) platform_window: Box<dyn PlatformWindow>,
1252 display_id: Option<DisplayId>,
1253 is_resizable: bool,
1254 is_minimizable: bool,
1255 sprite_atlas: Arc<dyn PlatformAtlas>,
1256 text_system: Arc<WindowTextSystem>,
1257 text_rendering_mode: Rc<Cell<TextRenderingMode>>,
1258 rem_size: Pixels,
1259 pub(crate) viewport_size: Size<Pixels>,
1260 pub(crate) root: Option<AnyView>,
1261 last_text_input_configuration: Option<TextInputConfiguration>,
1265 focused_text_input_active: bool,
1266 pub(crate) next_frame_callbacks: Rc<RefCell<Vec<FrameCallback>>>,
1267 focus_listeners: SubscriberSet<(), AnyWindowFocusListener>,
1268 pub(crate) focus_lost_listeners: SubscriberSet<(), AnyObserver>,
1269 default_prevented: bool,
1270 mouse_position: Point<Pixels>,
1271 mouse_hit_test: HitTest,
1272 modifiers: Modifiers,
1273 capslock: Capslock,
1274 scale_factor: f32,
1275 pub(crate) bounds_observers: SubscriberSet<(), AnyObserver>,
1276 appearance: WindowAppearance,
1277 pub(crate) appearance_observers: SubscriberSet<(), AnyObserver>,
1278 pub(crate) button_layout_observers: SubscriberSet<(), AnyObserver>,
1279 active: Rc<Cell<bool>>,
1280 visibility: WindowVisibility,
1281 pub(crate) visibility_observers:
1282 SubscriberSet<(), Box<dyn FnMut(WindowVisibility, &mut Window, &mut App) -> bool>>,
1283 hovered: Rc<Cell<bool>>,
1284 pub(crate) needs_present: Rc<Cell<bool>>,
1285 pub(crate) input_rate_tracker: Rc<RefCell<InputRateTracker>>,
1288 #[cfg(feature = "profiler")]
1289 window_profiler: profiler::WindowProfiler,
1290 last_input_modality: InputModality,
1291 touch_gestures: TouchGestureRecognizer,
1292 touch_prediction_enabled: bool,
1293 long_press_timer: Option<Task<()>>,
1294 long_press_capture: Option<EntityId>,
1295 pub(crate) refreshing: bool,
1296 pub(crate) activation_observers: SubscriberSet<(), AnyObserver>,
1297 pub(crate) focus: Option<FocusId>,
1298 focus_enabled: bool,
1299 pub(crate) focus_generation: u64,
1302 pending_input: Option<PendingInput>,
1303 pending_modifier: ModifierState,
1304 pub(crate) pending_input_observers: SubscriberSet<(), AnyObserver>,
1305 prompt: Option<RenderablePromptHandle>,
1306 pub(crate) client_inset: Option<Pixels>,
1307 captured_hitbox: Option<HitboxId>,
1310 #[cfg(any(feature = "inspector", debug_assertions))]
1311 inspector: Option<Entity<Inspector>>,
1312 #[cfg(feature = "profiler")]
1313 debug_frame_overlay: crate::debug_overlay::DebugFrameOverlay,
1314 pub(crate) a11y: A11y,
1315}
1316
1317impl WindowHostCore {
1318 fn metrics_handle(&self) -> WindowMetricsHandle {
1319 WindowMetricsHandle {
1320 id: self.handle.window_id(),
1321 metrics: self.metrics.clone(),
1322 }
1323 }
1324
1325 pub(crate) fn should_render_frame(&self) -> bool {
1328 let is_dirty = self.invalidator.is_dirty();
1329 let metrics = self.metrics.load();
1330 self.frame_pipeline
1331 .borrow_mut()
1332 .should_render(is_dirty, &metrics)
1333 }
1334}
1335
1336pub struct WindowMetricsHandle {
1342 id: WindowId,
1343 metrics: Arc<ArcSwap<WindowMetrics>>,
1344}
1345
1346impl WindowMetricsHandle {
1347 pub fn id(&self) -> WindowId {
1349 self.id
1350 }
1351
1352 pub fn snapshot(&self) -> Arc<WindowMetrics> {
1357 self.metrics.load_full()
1358 }
1359
1360 pub fn bounds(&self) -> Bounds<Pixels> {
1362 self.metrics.load().bounds
1363 }
1364
1365 pub fn viewport(&self) -> Bounds<Pixels> {
1370 self.metrics.load().viewport
1371 }
1372
1373 pub fn content_size(&self) -> Size<Pixels> {
1375 self.metrics.load().content_size
1376 }
1377
1378 pub fn scale_factor(&self) -> f32 {
1380 self.metrics.load().scale_factor
1381 }
1382
1383 pub fn display_id(&self) -> Option<DisplayId> {
1385 self.metrics.load().display_id
1386 }
1387
1388 pub fn is_active(&self) -> bool {
1390 self.metrics.load().is_active
1391 }
1392
1393 pub fn is_fullscreen(&self) -> bool {
1395 self.metrics.load().is_fullscreen
1396 }
1397}
1398
1399pub struct Window<'frame> {
1415 pub(crate) core: &'frame mut WindowHostCore,
1418 pub(crate) frame_state: &'frame mut WindowFrameState,
1420}
1421
1422pub(crate) struct WindowHost {
1428 pub(crate) core: WindowHostCore,
1429 pub(crate) frame_state: WindowFrameState,
1430}
1431
1432impl WindowHost {
1433 pub(crate) fn with_window<R>(&mut self, f: impl FnOnce(&mut Window<'_>) -> R) -> R {
1435 let core = &mut self.core;
1436 let frame_state = &mut self.frame_state;
1437 f(&mut Window { core, frame_state })
1438 }
1439}
1440
1441#[derive(Clone, Debug, Default)]
1442struct ModifierState {
1443 modifiers: Modifiers,
1444 saw_other_input: bool,
1445}
1446
1447#[derive(Clone, Debug)]
1450pub(crate) struct InputRateTracker {
1451 timestamps: Vec<Instant>,
1452 window: Duration,
1453 inputs_per_second: u32,
1454 sustain_until: Instant,
1455 sustain_duration: Duration,
1456}
1457
1458impl Default for InputRateTracker {
1459 fn default() -> Self {
1460 Self {
1461 timestamps: Vec::new(),
1462 window: Duration::from_millis(100),
1463 inputs_per_second: 60,
1464 sustain_until: Instant::now(),
1465 sustain_duration: Duration::from_secs(1),
1466 }
1467 }
1468}
1469
1470impl InputRateTracker {
1471 pub fn record_input(&mut self) {
1472 let now = Instant::now();
1473 self.timestamps.push(now);
1474 self.prune_old_timestamps(now);
1475
1476 let min_events = self.inputs_per_second as u128 * self.window.as_millis() / 1000;
1477 if self.timestamps.len() as u128 >= min_events {
1478 self.sustain_until = now + self.sustain_duration;
1479 }
1480 }
1481
1482 pub fn is_high_rate(&self) -> bool {
1483 Instant::now() < self.sustain_until
1484 }
1485
1486 fn prune_old_timestamps(&mut self, now: Instant) {
1487 self.timestamps
1488 .retain(|&t| now.duration_since(t) <= self.window);
1489 }
1490}
1491
1492#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1493pub(crate) enum DrawPhase {
1494 None,
1495 Prepaint,
1496 Paint,
1497 Focus,
1498}
1499
1500pub(crate) const PENDING_INPUT_TIMEOUT: Duration = Duration::from_secs(1);
1501
1502pub struct PendingInputStatus<'a> {
1504 keystrokes: &'a [Keystroke],
1505 timeout: Option<PendingInputTimeoutStatus>,
1506}
1507
1508impl<'a> PendingInputStatus<'a> {
1509 pub fn keystrokes(&self) -> &'a [Keystroke] {
1511 self.keystrokes
1512 }
1513
1514 pub fn timeout(&self) -> Option<PendingInputTimeoutStatus> {
1516 self.timeout
1517 }
1518}
1519
1520#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1522pub struct PendingInputTimeoutStatus {
1523 duration: Duration,
1524 remaining: Duration,
1525 started_at: Option<Instant>,
1526 paused: bool,
1527}
1528
1529impl PendingInputTimeoutStatus {
1530 pub fn duration(&self) -> Duration {
1532 self.duration
1533 }
1534
1535 pub fn remaining(&self, cx: &App) -> Duration {
1537 self.started_at
1538 .map(|started_at| {
1539 self.remaining
1540 .saturating_sub(cx.background_executor().now() - started_at)
1541 })
1542 .unwrap_or(self.remaining)
1543 }
1544
1545 pub fn is_paused(&self) -> bool {
1547 self.paused
1548 }
1549}
1550
1551#[derive(Debug)]
1552struct PendingInputTimeout {
1553 duration: Duration,
1554 remaining: Duration,
1555 state: PendingInputTimeoutState,
1556}
1557
1558#[derive(Debug)]
1559enum PendingInputTimeoutState {
1560 Running { started_at: Instant, task: Task<()> },
1561 Paused { pause: PendingInputTimeoutPause },
1562}
1563
1564#[derive(Debug)]
1565struct PendingInputTimeoutPause {
1566 owner_id: EntityId,
1567 _release_subscription: Subscription,
1568}
1569
1570impl PendingInputTimeout {
1571 fn is_paused(&self) -> bool {
1572 matches!(&self.state, PendingInputTimeoutState::Paused { .. })
1573 }
1574
1575 fn pause(&mut self, pause: PendingInputTimeoutPause, now: Instant) -> bool {
1576 match std::mem::replace(&mut self.state, PendingInputTimeoutState::Paused { pause }) {
1577 PendingInputTimeoutState::Running { started_at, task } => {
1578 self.remaining = self.remaining.saturating_sub(now - started_at);
1579 drop(task);
1580 true
1581 }
1582 previous_state @ PendingInputTimeoutState::Paused { .. } => {
1583 self.state = previous_state;
1584 false
1585 }
1586 }
1587 }
1588
1589 fn pause_owner_id(&self) -> Option<EntityId> {
1590 match &self.state {
1591 PendingInputTimeoutState::Running { .. } => None,
1592 PendingInputTimeoutState::Paused { pause } => Some(pause.owner_id),
1593 }
1594 }
1595
1596 fn resume(&mut self, owner_id: EntityId, started_at: Instant, task: Task<()>) -> bool {
1597 match std::mem::replace(
1598 &mut self.state,
1599 PendingInputTimeoutState::Running { started_at, task },
1600 ) {
1601 PendingInputTimeoutState::Paused { pause } if pause.owner_id == owner_id => true,
1602 previous_state => {
1603 self.state = previous_state;
1604 false
1605 }
1606 }
1607 }
1608
1609 fn reset_duration(&mut self, duration: Duration) {
1610 self.duration = duration;
1611 self.remaining = duration;
1612 }
1613
1614 fn status(&self) -> PendingInputTimeoutStatus {
1615 let (started_at, paused) = match &self.state {
1616 PendingInputTimeoutState::Running { started_at, .. } => (Some(*started_at), false),
1617 PendingInputTimeoutState::Paused { .. } => (None, true),
1618 };
1619 PendingInputTimeoutStatus {
1620 duration: self.duration,
1621 remaining: self.remaining,
1622 started_at,
1623 paused,
1624 }
1625 }
1626}
1627
1628#[derive(Default, Debug)]
1629struct PendingInput {
1630 keystrokes: SmallVec<[Keystroke; 1]>,
1631 focus: Option<FocusId>,
1632 timeout: Option<PendingInputTimeout>,
1633}
1634
1635pub(crate) struct ElementStateBox {
1636 pub(crate) inner: Box<dyn Any>,
1637 #[cfg(debug_assertions)]
1638 pub(crate) type_name: &'static str,
1639}
1640
1641fn default_bounds(display_id: Option<DisplayId>, cx: &mut App) -> WindowBounds {
1642 let active_window_bounds = cx
1647 .active_window()
1648 .and_then(|w| w.update(cx, |_, window, _| window.window_bounds()).ok());
1649
1650 const CASCADE_OFFSET: f32 = 25.0;
1651
1652 let display = display_id
1653 .map(|id| cx.find_display(id))
1654 .unwrap_or_else(|| cx.primary_display());
1655
1656 let default_placement = || Bounds::new(point(px(0.), px(0.)), DEFAULT_WINDOW_SIZE);
1657
1658 let display_bounds = display
1660 .as_ref()
1661 .map(|d| d.visible_bounds())
1662 .unwrap_or_else(default_placement);
1663
1664 let (
1665 Bounds {
1666 origin: base_origin,
1667 size: base_size,
1668 },
1669 window_bounds_ctor,
1670 ): (_, fn(Bounds<Pixels>) -> WindowBounds) = match active_window_bounds {
1671 Some(bounds) => match bounds {
1672 WindowBounds::Windowed(bounds) => (bounds, WindowBounds::Windowed),
1673 WindowBounds::Maximized(bounds) => (bounds, WindowBounds::Maximized),
1674 WindowBounds::Fullscreen(bounds) => (bounds, WindowBounds::Fullscreen),
1675 },
1676 None => (
1677 display
1678 .as_ref()
1679 .map(|d| d.default_bounds())
1680 .unwrap_or_else(default_placement),
1681 WindowBounds::Windowed,
1682 ),
1683 };
1684
1685 let cascade_offset = point(px(CASCADE_OFFSET), px(CASCADE_OFFSET));
1686 let proposed_origin = base_origin + cascade_offset;
1687 let proposed_bounds = Bounds::new(proposed_origin, base_size);
1688
1689 let display_right = display_bounds.origin.x + display_bounds.size.width;
1690 let display_bottom = display_bounds.origin.y + display_bounds.size.height;
1691 let window_right = proposed_bounds.origin.x + proposed_bounds.size.width;
1692 let window_bottom = proposed_bounds.origin.y + proposed_bounds.size.height;
1693
1694 let fits_horizontally = window_right <= display_right;
1695 let fits_vertically = window_bottom <= display_bottom;
1696
1697 let final_origin = match (fits_horizontally, fits_vertically) {
1698 (true, true) => proposed_origin,
1699 (false, true) => point(display_bounds.origin.x, base_origin.y),
1700 (true, false) => point(base_origin.x, display_bounds.origin.y),
1701 (false, false) => display_bounds.origin,
1702 };
1703 window_bounds_ctor(Bounds::new(final_origin, base_size))
1704}
1705
1706impl WindowHost {
1707 pub(crate) fn new(
1708 handle: AnyWindowHandle,
1709 options: WindowOptions,
1710 cx: &mut App,
1711 ) -> Result<Self> {
1712 let WindowOptions {
1713 window_bounds,
1714 titlebar,
1715 focus,
1716 show,
1717 kind,
1718 is_movable,
1719 app_owns_titlebar_drag,
1720 inactive_frame_interval,
1721 is_resizable,
1722 is_minimizable,
1723 display_id,
1724 window_background,
1725 app_id,
1726 window_min_size,
1727 window_decorations,
1728 #[cfg_attr(
1729 not(any(target_os = "linux", target_os = "freebsd")),
1730 allow(unused_variables)
1731 )]
1732 icon,
1733 #[cfg_attr(not(target_os = "macos"), allow(unused_variables))]
1734 tabbing_identifier,
1735 } = options;
1736
1737 let initial_window_title = titlebar
1738 .as_ref()
1739 .and_then(|titlebar| titlebar.title.clone());
1740
1741 let window_bounds = window_bounds.unwrap_or_else(|| default_bounds(display_id, cx));
1742 let mut platform_window = cx.platform.open_window(
1743 handle.window_id(),
1744 WindowParams {
1745 bounds: window_bounds.get_bounds(),
1746 titlebar,
1747 kind,
1748 is_movable,
1749 app_owns_titlebar_drag,
1750 is_resizable,
1751 is_minimizable,
1752 focus,
1753 show,
1754 display_id,
1755 window_min_size,
1756 app_id: app_id.clone(),
1757 icon,
1758 #[cfg(target_os = "macos")]
1759 tabbing_identifier,
1760 },
1761 )?;
1762
1763 let tab_bar_visible = platform_window.tab_bar_visible();
1764 SystemWindowTabController::init_visible(cx, tab_bar_visible);
1765 if let Some(tabs) = platform_window.tabbed_windows() {
1766 SystemWindowTabController::add_tab(cx, handle.window_id(), tabs);
1767 }
1768
1769 let display_id = platform_window.display().map(|display| display.id());
1770 let mut sprite_atlas = None;
1771 platform_window.with_renderer(&mut |renderer| {
1772 sprite_atlas = Some(renderer.sprite_atlas());
1773 });
1774 let sprite_atlas = sprite_atlas
1775 .ok_or_else(|| anyhow!("platform window did not provide a scene renderer"))?;
1776 let mouse_position = platform_window.mouse_position();
1777 let modifiers = platform_window.modifiers();
1778 let capslock = platform_window.capslock();
1779 let content_size = platform_window.content_size();
1780 let scale_factor = platform_window.scale_factor();
1781 let appearance = platform_window.appearance();
1782 let text_system = Arc::new(WindowTextSystem::new(cx.text_system().clone()));
1783 let invalidator = WindowInvalidator::new(handle.window_id());
1784 let active = Rc::new(Cell::new(platform_window.is_active()));
1785 let visibility = platform_window.visibility();
1786 let metrics = Arc::new(ArcSwap::from_pointee(WindowMetrics {
1787 bounds: platform_window.bounds(),
1788 viewport: platform_window.visual_viewport_bounds(),
1789 content_size,
1790 scale_factor,
1791 display_id,
1792 is_active: active.get(),
1793 is_fullscreen: platform_window.is_fullscreen(),
1794 }));
1795 let hovered = Rc::new(Cell::new(platform_window.is_hovered()));
1796 let needs_present = Rc::new(Cell::new(false));
1797 let next_frame_callbacks: Rc<RefCell<Vec<FrameCallback>>> = Default::default();
1798 let input_rate_tracker = Rc::new(RefCell::new(InputRateTracker::default()));
1799 let last_frame_time = Rc::new(Cell::new(None));
1800
1801 platform_window
1802 .request_decorations(window_decorations.unwrap_or(WindowDecorations::Server));
1803 platform_window.set_background_appearance(window_background);
1804
1805 match window_bounds {
1806 WindowBounds::Fullscreen(_) => platform_window.toggle_fullscreen(),
1807 WindowBounds::Maximized(_) => platform_window.zoom(),
1808 WindowBounds::Windowed(_) => {}
1809 }
1810
1811 let accessibility_force_disabled = cx.accessibility_force_disabled;
1812 let a11y_active_flag = Arc::new(AtomicBool::new(false));
1813
1814 #[cfg(not(target_family = "wasm"))]
1815 if !accessibility_force_disabled {
1816 let mut initial_root_node = accesskit::Node::new(accesskit::Role::Window);
1817 if let Some(title) = &initial_window_title {
1818 initial_root_node.set_label(title.to_string());
1819 }
1820 let initial_tree = accesskit::TreeUpdate {
1821 nodes: vec![(ROOT_NODE_ID, initial_root_node)],
1822 tree: Some(accesskit::Tree::new(ROOT_NODE_ID)),
1823 tree_id: accesskit::TreeId::ROOT,
1824 focus: ROOT_NODE_ID,
1825 };
1826 let (activation_sender, activation_receiver) = async_channel::unbounded::<()>();
1827 let (deactivation_sender, deactivation_receiver) = async_channel::unbounded::<()>();
1828 let (action_sender, action_receiver) =
1829 async_channel::unbounded::<accesskit::ActionRequest>();
1830
1831 platform_window.a11y_init(crate::A11yCallbacks {
1832 activation: {
1833 let active_flag = a11y_active_flag.clone();
1834 Box::new(move || {
1835 log::info!("Accessibility activated");
1836 active_flag.store(true, SeqCst);
1837 activation_sender.send_blocking(()).log_err();
1838 Some(initial_tree.clone())
1839 })
1840 },
1841 action: Box::new(move |request| {
1842 action_sender.send_blocking(request).log_err();
1843 }),
1844 deactivation: {
1845 let active_flag = a11y_active_flag.clone();
1846 Box::new(move || {
1847 log::info!("Accessibility deactivated");
1848 active_flag.store(false, SeqCst);
1849 deactivation_sender.send_blocking(()).log_err();
1850 })
1851 },
1852 });
1853
1854 let mut async_cx = cx.to_async();
1860 cx.foreground_executor()
1861 .spawn(async move {
1862 while activation_receiver.recv().await.is_ok() {
1863 handle
1864 .update(&mut async_cx, |_, window, _| window.refresh())
1865 .log_err();
1866 }
1867 })
1868 .detach();
1869
1870 let mut async_cx = cx.to_async();
1871 cx.foreground_executor()
1872 .spawn(async move {
1873 while deactivation_receiver.recv().await.is_ok() {
1874 handle
1875 .update(&mut async_cx, |_, window, _| window.refresh())
1876 .log_err();
1877 }
1878 })
1879 .detach();
1880
1881 let mut async_cx = cx.to_async();
1882 cx.foreground_executor()
1883 .spawn(async move {
1884 while let Ok(request) = action_receiver.recv().await {
1885 handle
1886 .update(&mut async_cx, |_, window, cx| {
1887 window.handle_a11y_action(request, cx);
1888 })
1889 .log_err();
1890 }
1891 })
1892 .detach();
1893 }
1894
1895 platform_window.on_close(Box::new({
1896 let window_id = handle.window_id();
1897 let mut cx = cx.to_async();
1898 move || {
1899 let _ = handle.update(&mut cx, |_, window, _| window.remove_window());
1900 let _ = cx.update(|cx| {
1901 SystemWindowTabController::remove_tab(cx, window_id);
1902 });
1903 }
1904 }));
1905 platform_window.on_request_frame(Box::new({
1906 let mut cx = cx.to_async();
1907 let invalidator = invalidator.clone();
1908 let active = active.clone();
1909 let needs_present = needs_present.clone();
1910 let next_frame_callbacks = next_frame_callbacks.clone();
1911 let input_rate_tracker = input_rate_tracker.clone();
1912 let mut deferred_force_render = false;
1913 move |request_frame_options| {
1914 #[cfg(feature = "profiler")]
1915 let _foreground_turn = profiler::journal::foreground_turn();
1916 if draw_in_progress() {
1932 log::debug!("deferring re-entrant window draw request");
1933 deferred_force_render |= request_frame_options.force_render;
1934 return;
1935 }
1936 let force_render =
1940 mem::take(&mut deferred_force_render) || request_frame_options.force_render;
1941
1942 let thermal_state = handle
1943 .update(&mut cx, |_, _, cx| cx.thermal_state())
1944 .log_err();
1945
1946 let min_frame_interval = if request_frame_options.require_presentation
1950 || (!request_frame_options.force_render
1951 && next_frame_callbacks.borrow().is_empty())
1952 {
1953 None
1954 } else if !active.get() && !input_rate_tracker.borrow_mut().is_high_rate() {
1955 inactive_frame_interval
1956 } else if let Some(ThermalState::Critical | ThermalState::Serious) = thermal_state {
1957 Some(Duration::from_micros(16667))
1958 } else {
1959 None
1960 };
1961
1962 let now = Instant::now();
1963 if let Some(min_interval) = min_frame_interval {
1964 if let Some(last_frame) = last_frame_time.get()
1965 && now.duration_since(last_frame) < min_interval
1966 {
1967 deferred_force_render |= force_render;
1969 handle
1971 .update(&mut cx, |_, window, _| {
1972 window.core.platform_window.schedule_frame();
1973 })
1974 .log_err();
1975 invalidator.wake_platform();
1980 return;
1981 }
1982 }
1983 last_frame_time.set(Some(now));
1984
1985 let pending_next_frame_callbacks = next_frame_callbacks.take();
1986 if !pending_next_frame_callbacks.is_empty() {
1987 handle
1988 .update(&mut cx, |_, window, cx| {
1989 for callback in pending_next_frame_callbacks {
1990 callback(window, cx);
1991 }
1992 })
1993 .log_err();
1994 }
1995
1996 let needs_present = request_frame_options.require_presentation
2000 || needs_present.get()
2001 || input_rate_tracker.borrow_mut().is_high_rate();
2002
2003 if invalidator.is_dirty() || force_render {
2004 measure("frame duration", || {
2005 handle
2006 .update(&mut cx, |_, window, cx| {
2007 if force_render {
2008 window.refresh();
2011 }
2012 if force_render || window.core.should_render_frame() {
2015 let arena_clear_needed = window.draw(cx);
2016 window.present();
2017 arena_clear_needed.clear(cx);
2018 }
2019 })
2020 .log_err();
2021 })
2022 } else if needs_present {
2023 handle
2024 .update(&mut cx, |_, window, _| window.present())
2025 .log_err();
2026 }
2027
2028 handle
2029 .update(&mut cx, |_, window, _| {
2030 if window.core.invalidator.is_dirty()
2031 || !window.core.next_frame_callbacks.borrow().is_empty()
2032 {
2033 window.core.platform_window.schedule_frame();
2034 }
2035 })
2036 .log_err();
2037
2038 if invalidator.is_dirty() || !next_frame_callbacks.borrow().is_empty() {
2044 invalidator.wake_platform();
2045 }
2046 }
2047 }));
2048 invalidator.set_platform_waker(platform_window.frame_waker());
2049 platform_window.on_visual_viewport_changed(Box::new({
2050 let mut cx = cx.to_async();
2051 move || {
2052 handle
2053 .update(&mut cx, |_, window, _| window.refresh())
2054 .log_err();
2055 }
2056 }));
2057 platform_window.on_insets_changed(Box::new({
2058 let mut cx = cx.to_async();
2059 move |_| {
2060 handle
2061 .update(&mut cx, |_, window, _| window.refresh())
2062 .log_err();
2063 }
2064 }));
2065 platform_window.on_resize(Box::new({
2066 let mut cx = cx.to_async();
2067 move |_, _| {
2068 handle
2069 .update(&mut cx, |_, window, cx| window.bounds_changed(cx))
2070 .log_err();
2071 }
2072 }));
2073 platform_window.on_moved(Box::new({
2074 let mut cx = cx.to_async();
2075 move || {
2076 handle
2077 .update(&mut cx, |_, window, cx| window.bounds_changed(cx))
2078 .log_err();
2079 }
2080 }));
2081 platform_window.on_appearance_changed(Box::new({
2082 let cx = cx.to_async();
2083 let foreground_executor = cx.foreground_executor().clone();
2084 move || {
2085 let mut cx = cx.clone();
2086 foreground_executor
2089 .spawn(async move {
2090 handle
2091 .update(&mut cx, |_, window, cx| window.appearance_changed(cx))
2092 .log_err();
2093 })
2094 .detach();
2095 }
2096 }));
2097 platform_window.on_button_layout_changed(Box::new({
2098 let mut cx = cx.to_async();
2099 move || {
2100 handle
2101 .update(&mut cx, |_, window, cx| window.button_layout_changed(cx))
2102 .log_err();
2103 }
2104 }));
2105 platform_window.on_active_status_change(Box::new({
2106 let mut cx = cx.to_async();
2107 move |active| {
2108 handle
2109 .update(&mut cx, |_, window, cx| {
2110 window.core.active.set(active);
2111 window.core.modifiers = window.core.platform_window.modifiers();
2112 window.core.capslock = window.core.platform_window.capslock();
2113 window
2114 .core
2115 .activation_observers
2116 .clone()
2117 .retain(&(), |callback| callback(window, cx));
2118
2119 window.bounds_changed(cx);
2120 window.refresh();
2121
2122 SystemWindowTabController::update_last_active(cx, window.core.handle.id);
2123 })
2124 .log_err();
2125 }
2126 }));
2127 platform_window.on_visibility_change(Box::new({
2128 let mut cx = cx.to_async();
2129 move |visibility| {
2130 handle
2131 .update(&mut cx, |_, window, cx| {
2132 if window.core.visibility == visibility {
2133 return;
2134 }
2135 window.core.visibility = visibility;
2136 window
2137 .core
2138 .visibility_observers
2139 .clone()
2140 .retain(&(), |callback| callback(visibility, window, cx));
2141 })
2142 .log_err();
2143 }
2144 }));
2145 platform_window.on_hover_status_change(Box::new({
2146 let mut cx = cx.to_async();
2147 move |active| {
2148 handle
2149 .update(&mut cx, |_, window, _| {
2150 window.core.hovered.set(active);
2151 window.refresh();
2152 })
2153 .log_err();
2154 }
2155 }));
2156 platform_window.on_input({
2157 let mut cx = cx.to_async();
2158 Box::new(move |event| {
2159 handle
2160 .update(&mut cx, |_, window, cx| window.dispatch_event(event, cx))
2161 .log_err()
2162 .unwrap_or(DispatchEventResult::default())
2163 })
2164 });
2165 platform_window.on_hit_test_window_control({
2166 let mut cx = cx.to_async();
2167 Box::new(move || {
2168 handle
2169 .update(&mut cx, |_, window, _cx| {
2170 for (area, hitbox) in
2171 &window.frame_state.rendered_frame.window_control_hitboxes
2172 {
2173 if window.core.mouse_hit_test.ids.contains(&hitbox.id) {
2174 return Some(*area);
2175 }
2176 }
2177 None
2178 })
2179 .log_err()
2180 .unwrap_or(None)
2181 })
2182 });
2183 platform_window.on_move_tab_to_new_window({
2184 let mut cx = cx.to_async();
2185 Box::new(move || {
2186 handle
2187 .update(&mut cx, |_, _window, cx| {
2188 SystemWindowTabController::move_tab_to_new_window(cx, handle.window_id());
2189 })
2190 .log_err();
2191 })
2192 });
2193 platform_window.on_merge_all_windows({
2194 let mut cx = cx.to_async();
2195 Box::new(move || {
2196 handle
2197 .update(&mut cx, |_, _window, cx| {
2198 SystemWindowTabController::merge_all_windows(cx, handle.window_id());
2199 })
2200 .log_err();
2201 })
2202 });
2203 platform_window.on_select_next_tab({
2204 let mut cx = cx.to_async();
2205 Box::new(move || {
2206 handle
2207 .update(&mut cx, |_, _window, cx| {
2208 SystemWindowTabController::select_next_tab(cx, handle.window_id());
2209 })
2210 .log_err();
2211 })
2212 });
2213 platform_window.on_select_previous_tab({
2214 let mut cx = cx.to_async();
2215 Box::new(move || {
2216 handle
2217 .update(&mut cx, |_, _window, cx| {
2218 SystemWindowTabController::select_previous_tab(cx, handle.window_id())
2219 })
2220 .log_err();
2221 })
2222 });
2223 platform_window.on_toggle_tab_bar({
2224 let mut cx = cx.to_async();
2225 Box::new(move || {
2226 handle
2227 .update(&mut cx, |_, window, cx| {
2228 let tab_bar_visible = window.core.platform_window.tab_bar_visible();
2229 SystemWindowTabController::set_visible(cx, tab_bar_visible);
2230 })
2231 .log_err();
2232 })
2233 });
2234
2235 if let Some(app_id) = app_id {
2236 platform_window.set_app_id(&app_id);
2237 }
2238
2239 platform_window.map_window().unwrap();
2240
2241 Ok(WindowHost {
2242 core: WindowHostCore {
2243 handle,
2244 invalidator,
2245 frame_pipeline: Rc::new(RefCell::new(cx.new_frame_pipeline(handle.window_id()))),
2246 removed: false,
2247 metrics,
2248 platform_window,
2249 display_id,
2250 is_resizable,
2251 is_minimizable,
2252 sprite_atlas,
2253 text_system,
2254 text_rendering_mode: cx.text_rendering_mode.clone(),
2255 rem_size: px(16.),
2256 viewport_size: content_size,
2257 root: None,
2258 last_text_input_configuration: None,
2259 focused_text_input_active: false,
2260 next_frame_callbacks,
2261 focus_listeners: SubscriberSet::new(),
2262 focus_lost_listeners: SubscriberSet::new(),
2263 default_prevented: true,
2264 mouse_position,
2265 mouse_hit_test: HitTest::default(),
2266 modifiers,
2267 capslock,
2268 scale_factor,
2269 bounds_observers: SubscriberSet::new(),
2270 appearance,
2271 appearance_observers: SubscriberSet::new(),
2272 button_layout_observers: SubscriberSet::new(),
2273 active,
2274 visibility,
2275 visibility_observers: SubscriberSet::new(),
2276 hovered,
2277 needs_present,
2278 input_rate_tracker,
2279 #[cfg(feature = "profiler")]
2280 window_profiler: profiler::WindowProfiler::new(handle.window_id())?,
2281 last_input_modality: InputModality::Mouse,
2282 touch_gestures: TouchGestureRecognizer::new(
2283 cx.platform
2284 .gestures()
2285 .map_or_else(GestureTuning::default, |gestures| gestures.tuning()),
2286 ),
2287 touch_prediction_enabled: true,
2288 long_press_timer: None,
2289 long_press_capture: None,
2290 refreshing: false,
2291 activation_observers: SubscriberSet::new(),
2292 focus: None,
2293 focus_enabled: true,
2294 focus_generation: 0,
2295 pending_input: None,
2296 pending_modifier: ModifierState::default(),
2297 pending_input_observers: SubscriberSet::new(),
2298 prompt: None,
2299 client_inset: None,
2300 captured_hitbox: None,
2301 #[cfg(any(feature = "inspector", debug_assertions))]
2302 inspector: None,
2303 #[cfg(feature = "profiler")]
2304 debug_frame_overlay: crate::debug_overlay::DebugFrameOverlay::new(),
2305 a11y: A11y::new(
2306 a11y_active_flag,
2307 accessibility_force_disabled,
2308 initial_window_title,
2309 ),
2310 },
2311 frame_state: WindowFrameState {
2312 rem_size_override_stack: SmallVec::new(),
2313 layout_session: Rc::new(FrameSession::new(cx.new_layout_engine())),
2314 inspector_element_id: None,
2315 dirty_views: FxHashSet::default(),
2316 focus_lost_path: SmallVec::new(),
2317 element_id_stack: SmallVec::default(),
2318 text_style_stack: Vec::new(),
2319 rendered_entity_stack: Vec::new(),
2320 element_offset_stack: Vec::new(),
2321 element_opacity: 1.0,
2322 content_mask_stack: Vec::new(),
2323 requested_autoscroll: None,
2324 image_cache_stack: Vec::new(),
2325 rendered_frame: Frame::new(DispatchTree::new(
2326 cx.keymap.clone(),
2327 cx.actions.clone(),
2328 )),
2329 next_frame: Frame::new(DispatchTree::new(cx.keymap.clone(), cx.actions.clone())),
2330 next_hitbox_id: HitboxId(0),
2331 next_tooltip_id: TooltipId::default(),
2332 tooltip_bounds: None,
2333 #[cfg(debug_assertions)]
2334 frame_phase: FramePhase::Idle,
2335 },
2336 })
2337 }
2338}
2339
2340pub struct PreparedRoots {
2352 pub root: AnyElement,
2354 pub prompt: Option<AnyElement>,
2356 pub tooltip: Option<AnyElement>,
2358 pub drag: Option<(AnyElement, Point<Pixels>)>,
2361 pub inspector: Option<AnyElement>,
2363}
2364
2365impl Window<'_> {
2366 pub(crate) fn new_focus_listener(
2367 &self,
2368 value: AnyWindowFocusListener,
2369 ) -> (Subscription, impl FnOnce() + use<>) {
2370 self.core.focus_listeners.insert((), value)
2371 }
2372
2373 fn mark_view_dirty(&mut self, view_id: EntityId) {
2374 for view_id in self
2377 .frame_state
2378 .rendered_frame
2379 .dispatch_tree
2380 .view_path_reversed(view_id)
2381 {
2382 if !self.frame_state.dirty_views.insert(view_id) {
2383 break;
2384 }
2385 }
2386 }
2387
2388 pub fn visibility(&self) -> WindowVisibility {
2391 self.core.visibility
2392 }
2393
2394 pub fn is_visible(&self) -> bool {
2400 self.core.visibility.is_visible()
2401 }
2402
2403 pub fn observe_window_visibility(
2405 &self,
2406 mut callback: impl FnMut(WindowVisibility, &mut Window, &mut App) + 'static,
2407 ) -> Subscription {
2408 let (subscription, activate) = self.core.visibility_observers.insert(
2409 (),
2410 Box::new(move |visibility, window, cx| {
2411 callback(visibility, window, cx);
2412 true
2413 }),
2414 );
2415 activate();
2416 subscription
2417 }
2418
2419 pub fn observe_window_appearance(
2421 &self,
2422 mut callback: impl FnMut(&mut Window, &mut App) + 'static,
2423 ) -> Subscription {
2424 let (subscription, activate) = self.core.appearance_observers.insert(
2425 (),
2426 Box::new(move |window, cx| {
2427 callback(window, cx);
2428 true
2429 }),
2430 );
2431 activate();
2432 subscription
2433 }
2434
2435 pub fn observe_button_layout_changed(
2437 &self,
2438 mut callback: impl FnMut(&mut Window, &mut App) + 'static,
2439 ) -> Subscription {
2440 let (subscription, activate) = self.core.button_layout_observers.insert(
2441 (),
2442 Box::new(move |window, cx| {
2443 callback(window, cx);
2444 true
2445 }),
2446 );
2447 activate();
2448 subscription
2449 }
2450
2451 pub fn replace_root<E>(
2453 &mut self,
2454 cx: &mut App,
2455 build_view: impl FnOnce(&mut Window, &mut Context<E>) -> E,
2456 ) -> Entity<E>
2457 where
2458 E: 'static + Render,
2459 {
2460 let view = cx.new(|cx| build_view(self, cx));
2461 self.core.root = Some(view.clone().into());
2462 self.refresh();
2463 view
2464 }
2465
2466 pub fn root<E>(&self) -> Option<Option<Entity<E>>>
2468 where
2469 E: 'static + Render,
2470 {
2471 self.core
2472 .root
2473 .as_ref()
2474 .map(|view| view.clone().downcast::<E>().ok())
2475 }
2476
2477 pub fn window_handle(&self) -> AnyWindowHandle {
2479 self.core.handle
2480 }
2481
2482 pub fn metrics_handle(&self) -> WindowMetricsHandle {
2488 self.core.metrics_handle()
2489 }
2490
2491 pub fn refresh(&mut self) {
2493 if self.core.invalidator.not_drawing() {
2494 self.core.refreshing = true;
2495 self.core.invalidator.set_dirty(true);
2496 }
2497 }
2498
2499 pub fn remove_window(&mut self) {
2501 self.core.removed = true;
2502 }
2503
2504 pub fn focused(&self, cx: &App) -> Option<FocusHandle> {
2506 self.core
2507 .focus
2508 .and_then(|id| FocusHandle::for_id(id, &cx.focus_handles))
2509 }
2510
2511 pub fn focus_lost_restore_target(&self, cx: &App) -> Option<FocusHandle> {
2515 let (_leaf, ancestors) = self.frame_state.focus_lost_path.split_last()?;
2516 ancestors.iter().rev().find_map(|id| {
2517 self.frame_state
2518 .rendered_frame
2519 .dispatch_tree
2520 .focusable_node_id(*id)?;
2521 FocusHandle::for_id(*id, &cx.focus_handles)
2522 })
2523 }
2524
2525 pub fn focus(&mut self, handle: &FocusHandle, cx: &mut App) {
2527 if !self.core.focus_enabled || self.core.focus == Some(handle.id) {
2528 return;
2529 }
2530
2531 self.core.focus = Some(handle.id);
2532 self.core.focus_generation = self.core.focus_generation.wrapping_add(1);
2533 self.clear_pending_keystrokes(cx);
2534
2535 self.refresh();
2536 }
2537
2538 pub fn blur(&mut self, cx: &mut App) {
2540 self.clear_pending_keystrokes(cx);
2541
2542 if !self.core.focus_enabled {
2543 return;
2544 }
2545
2546 if self.core.focus.is_some() {
2547 self.core.focus_generation = self.core.focus_generation.wrapping_add(1);
2548 }
2549 self.core.focus = None;
2550 self.refresh();
2551 }
2552
2553 pub fn disable_focus(&mut self, cx: &mut App) {
2555 self.blur(cx);
2556 self.core.focus_enabled = false;
2557 }
2558
2559 pub fn focus_next(&mut self, cx: &mut App) {
2561 if !self.core.focus_enabled {
2562 return;
2563 }
2564
2565 if let Some(handle) = self
2566 .frame_state
2567 .rendered_frame
2568 .tab_stops
2569 .next(self.core.focus.as_ref())
2570 {
2571 self.focus(&handle, cx)
2572 }
2573 }
2574
2575 pub fn focus_prev(&mut self, cx: &mut App) {
2577 if !self.core.focus_enabled {
2578 return;
2579 }
2580
2581 if let Some(handle) = self
2582 .frame_state
2583 .rendered_frame
2584 .tab_stops
2585 .prev(self.core.focus.as_ref())
2586 {
2587 self.focus(&handle, cx)
2588 }
2589 }
2590
2591 pub fn text_system(&self) -> &Arc<WindowTextSystem> {
2593 &self.core.text_system
2594 }
2595
2596 pub fn text_style(&self) -> TextStyle {
2598 let mut style = TextStyle::default();
2599 for refinement in &self.frame_state.text_style_stack {
2600 style.refine(refinement);
2601 }
2602 style
2603 }
2604
2605 pub fn is_maximized(&self) -> bool {
2609 self.core.platform_window.is_maximized()
2610 }
2611
2612 pub fn request_decorations(&self, decorations: WindowDecorations) {
2614 self.core.platform_window.request_decorations(decorations);
2615 }
2616
2617 pub fn set_exclusive_zone(&self, zone: Pixels) {
2623 self.core.platform_window.set_exclusive_zone(zone);
2624 }
2625
2626 #[cfg(all(target_os = "linux", feature = "wayland"))]
2631 pub fn set_exclusive_edge(&self, edge: crate::layer_shell::Anchor) {
2632 self.core.platform_window.set_exclusive_edge(edge);
2633 }
2634
2635 pub fn start_window_resize(&self, edge: ResizeEdge) {
2637 if self.core.is_resizable {
2638 self.core.platform_window.start_window_resize(edge);
2639 }
2640 }
2641
2642 pub fn set_input_region(&self, region: Option<&[Bounds<Pixels>]>) {
2649 self.core.platform_window.set_input_region(region);
2650 }
2651
2652 pub fn window_bounds(&self) -> WindowBounds {
2655 self.core.platform_window.window_bounds()
2656 }
2657
2658 pub fn inner_window_bounds(&self) -> WindowBounds {
2660 self.core.platform_window.inner_window_bounds()
2661 }
2662
2663 pub fn native_window_state(&self) -> Option<Vec<u8>> {
2666 self.core.platform_window.native_window_state()
2667 }
2668
2669 pub fn restore_native_window_state(&self, state: &[u8]) {
2672 self.core.platform_window.restore_native_window_state(state);
2673 }
2674
2675 pub fn dispatch_action(&mut self, action: Box<dyn Action>, cx: &mut App) {
2677 let focus_id = self.focused(cx).map(|handle| handle.id);
2678
2679 let window = self.core.handle;
2680 cx.defer(move |cx| {
2681 window
2682 .update(cx, |_, window, cx| {
2683 let node_id = window.focus_node_id_in_rendered_frame(focus_id);
2684 window.dispatch_action_on_node(node_id, action.as_ref(), cx);
2685 })
2686 .log_err();
2687 })
2688 }
2689
2690 pub(crate) fn dispatch_keystroke_observers(
2691 &mut self,
2692 event: &dyn Any,
2693 action: Option<Box<dyn Action>>,
2694 context_stack: Vec<KeyContext>,
2695 cx: &mut App,
2696 ) {
2697 let Some(key_down_event) = event.downcast_ref::<KeyDownEvent>() else {
2698 return;
2699 };
2700
2701 cx.keystroke_observers.clone().retain(&(), move |callback| {
2702 (callback)(
2703 &KeystrokeEvent {
2704 keystroke: key_down_event.keystroke.clone(),
2705 action: action.as_ref().map(|action| action.boxed_clone()),
2706 context_stack: context_stack.clone(),
2707 },
2708 self,
2709 cx,
2710 )
2711 });
2712 }
2713
2714 pub(crate) fn dispatch_keystroke_interceptors(
2715 &mut self,
2716 event: &dyn Any,
2717 context_stack: Vec<KeyContext>,
2718 cx: &mut App,
2719 ) {
2720 let Some(key_down_event) = event.downcast_ref::<KeyDownEvent>() else {
2721 return;
2722 };
2723
2724 cx.keystroke_interceptors
2725 .clone()
2726 .retain(&(), move |callback| {
2727 (callback)(
2728 &KeystrokeEvent {
2729 keystroke: key_down_event.keystroke.clone(),
2730 action: None,
2731 context_stack: context_stack.clone(),
2732 },
2733 self,
2734 cx,
2735 )
2736 });
2737 }
2738
2739 pub fn defer(&self, cx: &mut App, f: impl FnOnce(&mut Window, &mut App) + 'static) {
2742 let handle = self.core.handle;
2743 cx.defer(move |cx| {
2744 handle.update(cx, |_, window, cx| f(window, cx)).ok();
2745 });
2746 }
2747
2748 pub fn observe<T: 'static>(
2752 &mut self,
2753 observed: &Entity<T>,
2754 cx: &mut App,
2755 mut on_notify: impl FnMut(Entity<T>, &mut Window, &mut App) + 'static,
2756 ) -> Subscription {
2757 let entity_id = observed.entity_id();
2758 let observed = observed.downgrade();
2759 let window_handle = self.core.handle;
2760 cx.new_observer(
2761 entity_id,
2762 Box::new(move |cx| {
2763 window_handle
2764 .update(cx, |_, window, cx| {
2765 if let Some(handle) = observed.upgrade() {
2766 on_notify(handle, window, cx);
2767 true
2768 } else {
2769 false
2770 }
2771 })
2772 .unwrap_or(false)
2773 }),
2774 )
2775 }
2776
2777 pub fn subscribe<Emitter, Evt>(
2781 &mut self,
2782 entity: &Entity<Emitter>,
2783 cx: &mut App,
2784 mut on_event: impl FnMut(Entity<Emitter>, &Evt, &mut Window, &mut App) + 'static,
2785 ) -> Subscription
2786 where
2787 Emitter: EventEmitter<Evt>,
2788 Evt: 'static,
2789 {
2790 let entity_id = entity.entity_id();
2791 let handle = entity.downgrade();
2792 let window_handle = self.core.handle;
2793 cx.new_subscription(
2794 entity_id,
2795 (
2796 TypeId::of::<Evt>(),
2797 Box::new(move |event, cx| {
2798 window_handle
2799 .update(cx, |_, window, cx| {
2800 if let Some(entity) = handle.upgrade() {
2801 let event = event.downcast_ref().expect("invalid event type");
2802 on_event(entity, event, window, cx);
2803 true
2804 } else {
2805 false
2806 }
2807 })
2808 .unwrap_or(false)
2809 }),
2810 ),
2811 )
2812 }
2813
2814 pub fn observe_release<T>(
2816 &self,
2817 entity: &Entity<T>,
2818 cx: &mut App,
2819 mut on_release: impl FnOnce(&mut T, &mut Window, &mut App) + 'static,
2820 ) -> Subscription
2821 where
2822 T: 'static,
2823 {
2824 let entity_id = entity.entity_id();
2825 let window_handle = self.core.handle;
2826 let (subscription, activate) = cx.release_listeners.insert(
2827 entity_id,
2828 Box::new(move |entity, cx| {
2829 let entity = entity.downcast_mut().expect("invalid entity type");
2830 let _ = window_handle.update(cx, |_, window, cx| on_release(entity, window, cx));
2831 }),
2832 );
2833 activate();
2834 subscription
2835 }
2836
2837 pub fn to_async(&self, cx: &App) -> AsyncWindowContext {
2840 AsyncWindowContext::new_context(cx.to_async(), self.core.handle)
2841 }
2842
2843 pub fn on_next_frame(&self, callback: impl FnOnce(&mut Window, &mut App) + 'static) {
2845 RefCell::borrow_mut(&self.core.next_frame_callbacks).push(Box::new(callback));
2846 self.core.platform_window.schedule_frame();
2847 self.core.invalidator.wake_platform();
2850 }
2851
2852 pub fn request_animation_frame(&self) {
2865 let entity = self.current_view();
2866 self.on_next_frame(move |_, cx| cx.notify(entity));
2867 }
2868
2869 #[cfg(any(test, feature = "test-support"))]
2874 pub fn simulate_next_frame(&mut self, cx: &mut App) -> usize {
2875 let callbacks = self.core.next_frame_callbacks.take();
2876 let count = callbacks.len();
2877 for callback in callbacks {
2878 callback(self, cx);
2879 }
2880 count
2881 }
2882
2883 #[track_caller]
2887 pub fn spawn<AsyncFn, R>(&self, cx: &App, f: AsyncFn) -> Task<R>
2888 where
2889 R: 'static,
2890 AsyncFn: AsyncFnOnce(&mut AsyncWindowContext) -> R + 'static,
2891 {
2892 let handle = self.core.handle;
2893 cx.spawn(async move |app| {
2894 let mut async_window_cx = AsyncWindowContext::new_context(app.clone(), handle);
2895 f(&mut async_window_cx).await
2896 })
2897 }
2898
2899 #[track_caller]
2903 pub fn spawn_with_priority<AsyncFn, R>(
2904 &self,
2905 priority: Priority,
2906 cx: &App,
2907 f: AsyncFn,
2908 ) -> Task<R>
2909 where
2910 R: 'static,
2911 AsyncFn: AsyncFnOnce(&mut AsyncWindowContext) -> R + 'static,
2912 {
2913 let handle = self.core.handle;
2914 cx.spawn_with_priority(priority, async move |app| {
2915 let mut async_window_cx = AsyncWindowContext::new_context(app.clone(), handle);
2916 f(&mut async_window_cx).await
2917 })
2918 }
2919
2920 fn sync_metrics(&self) {
2926 self.core.metrics.store(Arc::new(WindowMetrics {
2927 bounds: self.core.platform_window.bounds(),
2928 viewport: self.core.platform_window.visual_viewport_bounds(),
2929 content_size: self.core.viewport_size,
2930 scale_factor: self.core.scale_factor,
2931 display_id: self.core.display_id,
2932 is_active: self.core.active.get(),
2933 is_fullscreen: self.core.platform_window.is_fullscreen(),
2934 }));
2935 }
2936
2937 pub fn bounds_changed(&mut self, cx: &mut App) {
2943 self.core.scale_factor = self.core.platform_window.scale_factor();
2944 self.core.viewport_size = self.core.platform_window.content_size();
2945 self.core.display_id = self
2946 .core
2947 .platform_window
2948 .display()
2949 .map(|display| display.id());
2950 self.core.mouse_position = self.core.platform_window.mouse_position();
2951
2952 self.sync_metrics();
2953 self.refresh();
2954
2955 self.core
2956 .bounds_observers
2957 .clone()
2958 .retain(&(), |callback| callback(self, cx));
2959 }
2960
2961 pub fn bounds(&self) -> Bounds<Pixels> {
2963 self.core.platform_window.bounds()
2964 }
2965
2966 #[cfg(any(test, feature = "test-support"))]
2970 pub fn render_to_image(&mut self) -> anyhow::Result<image::RgbaImage> {
2971 let size = self.bounds().size.to_device_pixels(self.scale_factor());
2972 let scene = &self.frame_state.rendered_frame.scene;
2973 let mut result = None;
2974 self.core.platform_window.with_renderer(&mut |renderer| {
2975 result = Some(renderer.render_scene_to_image(scene, size));
2976 });
2977 result.unwrap_or_else(|| anyhow::bail!("platform window does not support image capture"))
2978 }
2979
2980 #[cfg(any(test, feature = "test-support"))]
2985 pub fn painted_quads(&self) -> Vec<Quad> {
2986 self.frame_state.rendered_frame.scene.quads.clone()
2987 }
2988
2989 pub fn resize(&mut self, size: Size<Pixels>) {
2991 self.core.platform_window.resize(size);
2992 }
2993
2994 pub fn is_fullscreen(&self) -> bool {
2996 self.core.platform_window.is_fullscreen()
2997 }
2998
2999 pub fn is_simple_fullscreen(&self) -> bool {
3003 self.core.platform_window.is_simple_fullscreen()
3004 }
3005
3006 pub(crate) fn appearance_changed(&mut self, cx: &mut App) {
3007 self.core.appearance = self.core.platform_window.appearance();
3008
3009 self.core
3010 .appearance_observers
3011 .clone()
3012 .retain(&(), |callback| callback(self, cx));
3013 }
3014
3015 pub(crate) fn button_layout_changed(&mut self, cx: &mut App) {
3016 self.core
3017 .button_layout_observers
3018 .clone()
3019 .retain(&(), |callback| callback(self, cx));
3020 }
3021
3022 pub fn appearance(&self) -> WindowAppearance {
3024 self.core.appearance
3025 }
3026
3027 pub fn viewport_size(&self) -> Size<Pixels> {
3029 self.core.viewport_size
3030 }
3031
3032 pub fn visual_viewport_bounds(&self) -> Bounds<Pixels> {
3038 self.core.platform_window.visual_viewport_bounds()
3039 }
3040
3041 pub fn fully_visible_bounds(&self) -> Bounds<Pixels> {
3046 let insets = self.core.platform_window.insets().effective();
3047 let viewport = self.viewport_size();
3048 let left = insets.left.max(Pixels::ZERO).min(viewport.width);
3049 let top = insets.top.max(Pixels::ZERO).min(viewport.height);
3050 let right = (viewport.width - insets.right.max(Pixels::ZERO)).max(left);
3051 let bottom = (viewport.height - insets.bottom.max(Pixels::ZERO)).max(top);
3052 let safe_bounds = Bounds::from_corners(point(left, top), point(right, bottom));
3053 let mut visible = safe_bounds.intersect(&self.visual_viewport_bounds());
3054 visible.size.width = visible.size.width.max(Pixels::ZERO);
3055 visible.size.height = visible.size.height.max(Pixels::ZERO);
3056 visible
3057 }
3058
3059 pub fn request_virtual_keyboard(&self) {
3064 self.core.platform_window.show_soft_keyboard();
3065 }
3066
3067 pub fn dismiss_virtual_keyboard(&self) {
3069 self.core.platform_window.hide_soft_keyboard();
3070 }
3071
3072 pub fn is_window_active(&self) -> bool {
3074 self.core.active.get()
3075 }
3076
3077 pub fn is_window_hovered(&self) -> bool {
3081 if cfg!(any(
3082 target_os = "windows",
3083 target_os = "linux",
3084 target_os = "freebsd"
3085 )) {
3086 self.core.hovered.get()
3087 } else {
3088 self.is_window_active()
3089 }
3090 }
3091
3092 pub fn zoom_window(&self) {
3094 self.core.platform_window.zoom();
3095 }
3096
3097 pub fn show_window_menu(&self, position: Point<Pixels>) {
3099 self.core.platform_window.show_window_menu(position)
3100 }
3101
3102 pub fn start_window_move(&self) {
3107 self.core.platform_window.start_window_move()
3108 }
3109
3110 pub fn set_client_inset(&mut self, inset: Pixels) {
3112 self.core.client_inset = Some(inset);
3113 self.core.platform_window.set_client_inset(inset);
3114 }
3115
3116 pub fn client_inset(&self) -> Option<Pixels> {
3118 self.core.client_inset
3119 }
3120
3121 pub fn window_decorations(&self) -> Decorations {
3123 self.core.platform_window.window_decorations()
3124 }
3125
3126 pub fn is_resizable(&self) -> bool {
3128 self.core.is_resizable
3129 }
3130
3131 pub fn is_minimizable(&self) -> bool {
3133 self.core.is_minimizable
3134 }
3135
3136 pub fn window_controls(&self) -> WindowControls {
3138 self.core.platform_window.window_controls()
3139 }
3140
3141 pub fn set_window_title(&mut self, title: &str) {
3143 self.core.platform_window.set_title(title);
3144 self.core.a11y.set_window_title(title.to_string());
3145 }
3146
3147 #[cfg(target_os = "macos")]
3149 pub fn set_traffic_light_position(&self, position: Point<Pixels>) {
3150 self.core
3151 .platform_window
3152 .set_traffic_light_position(position);
3153 }
3154
3155 pub fn set_app_id(&mut self, app_id: &str) {
3157 self.core.platform_window.set_app_id(app_id);
3158 }
3159
3160 pub fn set_background_appearance(&self, background_appearance: WindowBackgroundAppearance) {
3162 self.core
3163 .platform_window
3164 .set_background_appearance(background_appearance);
3165 }
3166
3167 pub fn set_window_edited(&mut self, edited: bool) {
3169 self.core.platform_window.set_edited(edited);
3170 }
3171
3172 pub fn set_document_path(&self, path: Option<&std::path::Path>) {
3175 self.core.platform_window.set_document_path(path);
3176 }
3177
3178 pub fn display(&self, cx: &App) -> Option<Rc<dyn PlatformDisplay>> {
3180 cx.platform
3181 .displays()
3182 .into_iter()
3183 .find(|display| Some(display.id()) == self.core.display_id)
3184 }
3185
3186 pub fn show_character_palette(&self) {
3188 self.core.platform_window.show_character_palette();
3189 }
3190
3191 pub fn scale_factor(&self) -> f32 {
3195 self.core.scale_factor
3196 }
3197
3198 #[cfg(any(test, feature = "test-support"))]
3200 pub fn set_scale_factor(&mut self, scale_factor: f32) {
3201 self.core.scale_factor = scale_factor;
3202 self.sync_metrics();
3203 self.refresh();
3204 }
3205
3206 pub fn rem_size(&self) -> Pixels {
3209 self.frame_state
3210 .rem_size_override_stack
3211 .last()
3212 .copied()
3213 .unwrap_or(self.core.rem_size)
3214 }
3215
3216 pub fn set_rem_size(&mut self, rem_size: impl Into<Pixels>) {
3219 self.core.rem_size = rem_size.into();
3220 }
3221
3222 pub fn with_global_id<R>(
3225 &mut self,
3226 element_id: ElementId,
3227 f: impl FnOnce(&GlobalElementId, &mut Self) -> R,
3228 ) -> R {
3229 self.with_id(element_id, |this| {
3230 let global_id = GlobalElementId(Arc::from(&*this.frame_state.element_id_stack));
3231
3232 f(&global_id, this)
3233 })
3234 }
3235
3236 #[inline]
3238 pub fn with_id<R>(
3239 &mut self,
3240 element_id: impl Into<ElementId>,
3241 f: impl FnOnce(&mut Self) -> R,
3242 ) -> R {
3243 self.frame_state.element_id_stack.push(element_id.into());
3244 let result = f(self);
3245 self.frame_state.element_id_stack.pop();
3246 result
3247 }
3248
3249 #[inline]
3255 pub fn with_rem_size<F, R>(&mut self, rem_size: Option<impl Into<Pixels>>, f: F) -> R
3256 where
3257 F: FnOnce(&mut Self) -> R,
3258 {
3259 self.core.invalidator.debug_assert_paint_or_prepaint();
3260
3261 if let Some(rem_size) = rem_size {
3262 self.frame_state
3263 .rem_size_override_stack
3264 .push(rem_size.into());
3265 let result = f(self);
3266 self.frame_state.rem_size_override_stack.pop();
3267 result
3268 } else {
3269 f(self)
3270 }
3271 }
3272
3273 pub fn line_height(&self) -> Pixels {
3275 self.text_style().line_height_in_pixels(self.rem_size())
3276 }
3277
3278 #[inline]
3280 pub fn pixel_snap(&self, value: Pixels) -> Pixels {
3281 px(round_to_device_pixel(value.0, self.scale_factor()) / self.scale_factor())
3282 }
3283
3284 #[inline]
3286 pub fn pixel_snap_f64(&self, value: f64) -> f64 {
3287 let scale_factor = f64::from(self.scale_factor());
3288 round_half_toward_zero_f64(value * scale_factor) / scale_factor
3289 }
3290
3291 #[inline]
3293 pub fn pixel_snap_bounds(&self, bounds: Bounds<Pixels>) -> Bounds<Pixels> {
3294 bounds.map(|c| self.pixel_snap(c))
3295 }
3296
3297 #[inline]
3299 pub fn pixel_snap_point(&self, position: Point<Pixels>) -> Point<Pixels> {
3300 position.map(|c| self.pixel_snap(c))
3301 }
3302
3303 #[inline]
3304 fn snap_bounds(&self, bounds: Bounds<Pixels>) -> Bounds<ScaledPixels> {
3305 let scale_factor = self.scale_factor();
3306 let left = round_to_device_pixel(bounds.left().0, scale_factor);
3307 let top = round_to_device_pixel(bounds.top().0, scale_factor);
3308 let right = round_to_device_pixel(bounds.right().0, scale_factor).max(left);
3309 let bottom = round_to_device_pixel(bounds.bottom().0, scale_factor).max(top);
3310 Bounds::from_corners(
3311 point(ScaledPixels(left), ScaledPixels(top)),
3312 point(ScaledPixels(right), ScaledPixels(bottom)),
3313 )
3314 }
3315
3316 #[inline]
3318 fn snap_stroke(&self, value: Pixels) -> ScaledPixels {
3319 ScaledPixels(round_stroke_to_device_pixel(value.0, self.scale_factor()))
3320 }
3321
3322 #[inline]
3323 fn snap_border_widths(&self, edges: Edges<Pixels>) -> Edges<ScaledPixels> {
3324 edges.map(|e| self.snap_stroke(*e))
3325 }
3326
3327 #[inline]
3329 fn cover_bounds(&self, bounds: Bounds<Pixels>) -> Bounds<ScaledPixels> {
3330 let scale_factor = self.scale_factor();
3331 let left = floor_to_device_pixel(bounds.left().0, scale_factor);
3332 let top = floor_to_device_pixel(bounds.top().0, scale_factor);
3333 let right = ceil_to_device_pixel(bounds.right().0, scale_factor).max(left);
3334 let bottom = ceil_to_device_pixel(bounds.bottom().0, scale_factor).max(top);
3335 Bounds::from_corners(
3336 point(ScaledPixels(left), ScaledPixels(top)),
3337 point(ScaledPixels(right), ScaledPixels(bottom)),
3338 )
3339 }
3340
3341 #[inline]
3342 fn snapped_content_mask(&self) -> ContentMask<ScaledPixels> {
3343 ContentMask {
3344 bounds: self.cover_bounds(self.content_mask().bounds),
3345 }
3346 }
3347
3348 pub fn prevent_default(&mut self) {
3351 self.core.default_prevented = true;
3352 }
3353
3354 pub fn default_prevented(&self) -> bool {
3356 self.core.default_prevented
3357 }
3358
3359 pub fn is_action_available(&self, action: &dyn Action, cx: &App) -> bool {
3361 let node_id =
3362 self.focus_node_id_in_rendered_frame(self.focused(cx).map(|handle| handle.id));
3363 self.frame_state
3364 .rendered_frame
3365 .dispatch_tree
3366 .is_action_available(action, node_id)
3367 }
3368
3369 pub fn is_action_available_in(&self, action: &dyn Action, focus_handle: &FocusHandle) -> bool {
3371 let node_id = self.focus_node_id_in_rendered_frame(Some(focus_handle.id));
3372 self.frame_state
3373 .rendered_frame
3374 .dispatch_tree
3375 .is_action_available(action, node_id)
3376 }
3377
3378 pub fn mouse_position(&self) -> Point<Pixels> {
3380 self.core.mouse_position
3381 }
3382
3383 pub fn capture_pointer(&mut self, hitbox_id: HitboxId) {
3390 self.core.captured_hitbox = Some(hitbox_id);
3391 }
3392
3393 pub fn release_pointer(&mut self) {
3395 self.core.captured_hitbox = None;
3396 }
3397
3398 pub fn captured_hitbox(&self) -> Option<HitboxId> {
3400 self.core.captured_hitbox
3401 }
3402
3403 pub fn capture_long_press<T: 'static>(&mut self, entity: &Entity<T>) {
3409 self.core.long_press_capture = Some(entity.entity_id());
3410 }
3411
3412 pub fn has_long_press_capture<T: 'static>(&self, entity: &Entity<T>) -> bool {
3414 self.core.long_press_capture == Some(entity.entity_id())
3415 }
3416
3417 pub fn modifiers(&self) -> Modifiers {
3419 self.core.modifiers
3420 }
3421
3422 pub fn last_input_was_keyboard(&self) -> bool {
3425 self.core.last_input_modality == InputModality::Keyboard
3426 }
3427
3428 pub(crate) fn last_input_was_touch(&self) -> bool {
3429 self.core.last_input_modality == InputModality::Touch
3430 }
3431
3432 pub fn capslock(&self) -> Capslock {
3434 self.core.capslock
3435 }
3436
3437 #[doc(hidden)]
3444 #[profiling::function]
3445 pub fn draw(&mut self, cx: &mut App) -> ArenaClearNeeded {
3446 let pipeline = self.core.frame_pipeline.clone();
3447 pipeline.borrow_mut().draw(self, cx)
3448 }
3449
3450 pub fn begin_frame(&mut self, cx: &mut App) {
3455 #[cfg(debug_assertions)]
3456 self.frame_state.frame_phase.enter(
3457 &[FramePhase::Idle, FramePhase::Completed],
3458 FramePhase::Begun,
3459 "begin_frame",
3460 );
3461 if self.core.platform_window.prepare_frame() {
3462 self.refresh();
3463 }
3464 self.sync_metrics();
3465 self.invalidate_entities();
3466 cx.entities.clear_accessed();
3467 debug_assert!(self.frame_state.rendered_entity_stack.is_empty());
3468 self.core.invalidator.set_dirty(false);
3469 self.frame_state.requested_autoscroll = None;
3470 }
3471
3472 fn restore_input_handler(&mut self) {
3477 if let Some(input_handler) = self.core.platform_window.take_input_handler() {
3478 if let Some(slot) = self
3479 .frame_state
3480 .rendered_frame
3481 .input_handlers
3482 .iter_mut()
3483 .rev()
3484 .find(|h| h.is_none())
3485 {
3486 *slot = Some(input_handler);
3487 } else {
3488 self.frame_state
3489 .rendered_frame
3490 .input_handlers
3491 .push(Some(input_handler));
3492 }
3493 }
3494 }
3495
3496 pub fn finish_frame(&mut self, cx: &mut App) {
3506 #[cfg(debug_assertions)]
3507 self.frame_state.frame_phase.enter(
3508 &[FramePhase::Begun, FramePhase::Painted],
3509 FramePhase::Finished,
3510 "finish_frame",
3511 );
3512 self.frame_state.dirty_views.clear();
3513 self.frame_state.next_frame.window_active = self.core.active.get();
3514
3515 let focused_text_input_active = if let Some(mut input_handler) = self
3520 .frame_state
3521 .next_frame
3522 .input_handlers
3523 .iter_mut()
3524 .rev()
3525 .find_map(|h| h.take())
3526 {
3527 let accepts_text_input = input_handler.accepts_text_input(self, cx);
3528 self.core.platform_window.set_input_handler(input_handler);
3529 accepts_text_input
3530 } else {
3531 false
3532 };
3533 self.apply_text_input_configuration(cx);
3534 if focused_text_input_active != self.core.focused_text_input_active {
3535 self.core.focused_text_input_active = focused_text_input_active;
3536 self.core
3537 .platform_window
3538 .text_input_state_changed(if focused_text_input_active {
3539 TextInputStateChange::FocusGained
3540 } else {
3541 TextInputStateChange::FocusLost
3542 });
3543 }
3544
3545 self.frame_state.layout_session.clear();
3546 self.text_system().finish_frame();
3547 self.frame_state
3548 .next_frame
3549 .finish(&mut self.frame_state.rendered_frame);
3550 }
3551
3552 pub fn complete_frame(&mut self, cx: &mut App) -> Option<FocusId> {
3560 #[cfg(debug_assertions)]
3561 self.frame_state.frame_phase.enter(
3562 &[FramePhase::Finished],
3563 FramePhase::Completed,
3564 "complete_frame",
3565 );
3566 self.core.invalidator.set_phase(DrawPhase::Focus);
3567 let previous_focus_path = self.frame_state.rendered_frame.focus_path();
3568 let previous_window_active = self.frame_state.rendered_frame.window_active;
3569 mem::swap(
3570 &mut self.frame_state.rendered_frame,
3571 &mut self.frame_state.next_frame,
3572 );
3573 self.frame_state.next_frame.clear();
3574 let current_focus_path = self.frame_state.rendered_frame.focus_path();
3575 let current_window_active = self.frame_state.rendered_frame.window_active;
3576 let mut focus_before_listeners = self.core.focus;
3577
3578 if previous_focus_path != current_focus_path
3579 || previous_window_active != current_window_active
3580 {
3581 if !previous_focus_path.is_empty() && current_focus_path.is_empty() {
3582 self.frame_state.focus_lost_path = previous_focus_path.clone();
3583 self.core
3584 .focus_lost_listeners
3585 .clone()
3586 .retain(&(), |listener| listener(self, cx));
3587 self.frame_state.focus_lost_path = SmallVec::new();
3588 focus_before_listeners = self.core.focus;
3593 }
3594
3595 let event = WindowFocusEvent {
3596 previous_focus_path: if previous_window_active {
3597 previous_focus_path
3598 } else {
3599 Default::default()
3600 },
3601 current_focus_path: if current_window_active {
3602 current_focus_path
3603 } else {
3604 Default::default()
3605 },
3606 };
3607 self.core
3608 .focus_listeners
3609 .clone()
3610 .retain(&(), |listener| listener(&event, self, cx));
3611 }
3612
3613 focus_before_listeners
3614 }
3615
3616 pub fn end_frame(&mut self, cx: &mut App, focus_before_listeners: Option<FocusId>) {
3620 #[cfg(debug_assertions)]
3621 self.frame_state
3622 .frame_phase
3623 .enter(&[FramePhase::Completed], FramePhase::Idle, "end_frame");
3624 debug_assert!(self.frame_state.rendered_entity_stack.is_empty());
3625 self.record_entities_accessed(cx);
3626 self.reset_cursor_style(cx);
3627 self.core.refreshing = false;
3628 self.core.invalidator.set_phase(DrawPhase::None);
3629 if self.core.focus != focus_before_listeners {
3634 self.refresh();
3635 }
3636 self.core.needs_present.set(true);
3637 }
3638 fn record_entities_accessed(&mut self, cx: &mut App) {
3639 let mut entities_ref = cx.entities.accessed_entities.get_mut();
3640 let mut entities = mem::take(entities_ref.deref_mut());
3641 let handle = self.core.handle;
3642 cx.record_entities_accessed(
3643 handle,
3644 self.core.invalidator.clone(),
3646 &entities,
3647 );
3648 let mut entities_ref = cx.entities.accessed_entities.get_mut();
3649 mem::swap(&mut entities, entities_ref.deref_mut());
3650 }
3651
3652 fn invalidate_entities(&mut self) {
3653 let mut views = self.core.invalidator.take_views();
3654 for entity in views.drain() {
3655 self.mark_view_dirty(entity);
3656 }
3657 self.core.invalidator.replace_views(views);
3658 }
3659
3660 #[profiling::function]
3661 fn present(&mut self) {
3662 #[cfg(feature = "profiler")]
3663 let _foreground_turn = profiler::journal::foreground_turn();
3664 #[cfg(feature = "profiler")]
3665 let present_start = Instant::now();
3666 self.core
3667 .platform_window
3668 .present(&mut |renderer| renderer.draw(&self.frame_state.rendered_frame.scene));
3669 #[cfg(feature = "profiler")]
3670 self.core.window_profiler.record_present(
3671 present_start,
3672 Instant::now(),
3673 self.core.active.get(),
3674 !self.core.next_frame_callbacks.borrow().is_empty(),
3675 );
3676 self.core.needs_present.set(false);
3677 profiling::finish_frame!();
3678 }
3679
3680 #[cfg(any(test, feature = "bench-support"))]
3682 pub(crate) fn present_if_needed(&mut self) {
3683 if self.core.needs_present.get() {
3684 self.present();
3685 }
3686 }
3687
3688 #[cfg(feature = "profiler")]
3690 pub fn input_latency_snapshot(&self) -> profiler::InputLatencySnapshot {
3691 self.core.window_profiler.input_latency_snapshot()
3692 }
3693
3694 #[cfg(feature = "profiler")]
3696 pub fn frame_duration_snapshot(&self) -> profiler::FrameDurationSnapshot {
3697 self.core.window_profiler.frame_duration_snapshot()
3698 }
3699
3700 #[cfg(feature = "profiler")]
3702 pub fn debug_frame_overlay_mode(&self) -> DebugFrameOverlayMode {
3703 self.core.debug_frame_overlay.mode()
3704 }
3705
3706 #[cfg(feature = "profiler")]
3708 pub fn set_debug_frame_overlay_mode(&mut self, mode: DebugFrameOverlayMode) {
3709 self.core.debug_frame_overlay.set_mode(mode);
3710 self.refresh();
3711 }
3712
3713 #[cfg(feature = "profiler")]
3716 pub fn cycle_debug_frame_overlay_mode(&mut self) {
3717 self.set_debug_frame_overlay_mode(self.core.debug_frame_overlay.mode().next());
3718 }
3719
3720 #[cfg(feature = "profiler")]
3723 pub fn reset_debug_frame_overlay_stats(&mut self) {
3724 self.core.debug_frame_overlay.reset_stats();
3725 self.refresh();
3726 }
3727
3728 pub fn evaluate_roots(&mut self, cx: &mut App) -> PreparedRoots {
3734 #[cfg(debug_assertions)]
3735 self.frame_state.frame_phase.enter(
3736 &[FramePhase::Begun],
3737 FramePhase::Evaluated,
3738 "evaluate_roots",
3739 );
3740 let root = self.core.root.as_ref().unwrap().clone().into_any_element();
3741
3742 let mut prompt = None;
3745 let mut drag = None;
3746 if let Some(handle) = self.core.prompt.take() {
3747 prompt = Some(handle.view.any_view().into_any_element());
3748 self.core.prompt = Some(handle);
3749 } else if let Some(active_drag) = cx.active_drag.take() {
3750 let origin = self.mouse_position() - active_drag.cursor_offset;
3751 drag = Some((active_drag.view.clone().into_any_element(), origin));
3752 cx.active_drag = Some(active_drag);
3753 }
3754
3755 PreparedRoots {
3756 root,
3757 prompt,
3758 tooltip: None,
3759 drag,
3760 inspector: None,
3761 }
3762 }
3763
3764 pub fn layout_roots(&mut self, roots: &mut PreparedRoots, cx: &mut App) {
3767 #[cfg(debug_assertions)]
3768 self.frame_state.frame_phase.enter(
3769 &[FramePhase::Evaluated],
3770 FramePhase::LaidOut,
3771 "layout_roots",
3772 );
3773 self.core.invalidator.set_phase(DrawPhase::Prepaint);
3774 self.frame_state.tooltip_bounds.take();
3775
3776 self.core.a11y.sync_active_flag();
3777 if self.core.a11y.is_active() {
3778 self.core.a11y.begin_frame();
3779 }
3780
3781 #[cfg(any(feature = "inspector", debug_assertions))]
3782 let inspector_width: Pixels = rems(30.0).to_pixels(self.rem_size());
3783 let root_size = {
3784 #[cfg(any(feature = "inspector", debug_assertions))]
3785 {
3786 if self.core.inspector.is_some() {
3787 let mut size = self.core.viewport_size;
3788 size.width = (size.width - inspector_width).max(px(0.0));
3789 size
3790 } else {
3791 self.core.viewport_size
3792 }
3793 }
3794 #[cfg(not(any(feature = "inspector", debug_assertions)))]
3795 {
3796 self.core.viewport_size
3797 }
3798 };
3799
3800 let scale_factor = self.scale_factor();
3804 let root_layout_id = roots.root.request_layout(self, cx);
3805 self.frame_state.layout_session.stretch_auto_size_to_fill(
3806 root_layout_id,
3807 root_size,
3808 scale_factor,
3809 );
3810 roots
3811 .root
3812 .prepaint_as_root(Point::default(), root_size.into(), self, cx);
3813
3814 #[cfg(any(feature = "inspector", debug_assertions))]
3815 {
3816 roots.inspector = self.prepaint_inspector(inspector_width, cx);
3817 }
3818
3819 self.prepaint_deferred_draws(cx);
3820
3821 if let Some(prompt) = roots.prompt.as_mut() {
3822 let prompt_layout_id = prompt.request_layout(self, cx);
3823 self.frame_state.layout_session.stretch_auto_size_to_fill(
3824 prompt_layout_id,
3825 root_size,
3826 scale_factor,
3827 );
3828 prompt.prepaint_as_root(Point::default(), root_size.into(), self, cx);
3829 } else if let Some((drag, origin)) = roots.drag.as_mut() {
3830 drag.prepaint_as_root(*origin, AvailableSpace::min_size(), self, cx);
3831 } else {
3832 roots.tooltip = self.prepaint_tooltip(cx);
3833 }
3834
3835 self.core.mouse_hit_test = self
3836 .frame_state
3837 .next_frame
3838 .hit_test(self.core.mouse_position);
3839 }
3840
3841 pub fn paint_roots(&mut self, mut roots: PreparedRoots, cx: &mut App) {
3843 #[cfg(debug_assertions)]
3844 self.frame_state.frame_phase.enter(
3845 &[FramePhase::LaidOut],
3846 FramePhase::Painted,
3847 "paint_roots",
3848 );
3849 self.core.invalidator.set_phase(DrawPhase::Paint);
3850 roots.root.paint(self, cx);
3851
3852 #[cfg(any(feature = "inspector", debug_assertions))]
3853 self.paint_inspector(roots.inspector.take(), cx);
3854
3855 self.paint_deferred_draws(cx);
3856
3857 if let Some(mut prompt) = roots.prompt.take() {
3858 prompt.paint(self, cx);
3859 } else if let Some((mut drag, _)) = roots.drag.take() {
3860 drag.paint(self, cx);
3861 } else if let Some(mut tooltip) = roots.tooltip.take() {
3862 tooltip.paint(self, cx);
3863 }
3864
3865 #[cfg(any(feature = "inspector", debug_assertions))]
3866 self.paint_inspector_hitbox(cx);
3867
3868 let a11y_active_start_of_frame = self.core.a11y.is_active();
3870 self.core.a11y.sync_active_flag();
3871 let a11y_active_end_of_frame = self.core.a11y.is_active();
3872
3873 let should_send_a11y_update = a11y_active_start_of_frame && a11y_active_end_of_frame;
3874
3875 if a11y_active_start_of_frame {
3876 let frame_info = crate::window::a11y::debug::FrameDebugInfo {
3879 viewport_size: self.core.viewport_size,
3880 scale_factor: self.core.scale_factor,
3881 tab_stop_count: self.frame_state.next_frame.tab_stops.tab_stop_count(),
3882 };
3883 let tree_update = self.core.a11y.end_frame(frame_info);
3885
3886 if should_send_a11y_update {
3887 log::debug!(
3888 "Sending a11y tree update: {} nodes",
3889 tree_update.nodes.len()
3890 );
3891 self.core.platform_window.a11y_tree_update(tree_update);
3892 }
3893 }
3894 }
3895
3896 pub fn draw_roots(&mut self, cx: &mut App) {
3902 let mut roots = self.evaluate_roots(cx);
3903 self.layout_roots(&mut roots, cx);
3904 self.paint_roots(roots, cx);
3905 }
3906
3907 fn prepaint_tooltip(&mut self, cx: &mut App) -> Option<AnyElement> {
3908 for tooltip_request_index in (0..self.frame_state.next_frame.tooltip_requests.len()).rev() {
3910 let Some(Some(tooltip_request)) = self
3911 .frame_state
3912 .next_frame
3913 .tooltip_requests
3914 .get(tooltip_request_index)
3915 .cloned()
3916 else {
3917 log::error!("Unexpectedly absent TooltipRequest");
3918 continue;
3919 };
3920 let mut element = tooltip_request.tooltip.view.clone().into_any_element();
3921 let mouse_position = tooltip_request.tooltip.mouse_position;
3922 let tooltip_size = element.layout_as_root(AvailableSpace::min_size(), self, cx);
3923
3924 let mut tooltip_bounds =
3925 Bounds::new(mouse_position + point(px(1.), px(1.)), tooltip_size);
3926 let window_bounds = Bounds {
3927 origin: Point::default(),
3928 size: self.viewport_size(),
3929 };
3930
3931 if tooltip_bounds.right() > window_bounds.right() {
3932 let new_x = mouse_position.x - tooltip_bounds.size.width - px(1.);
3933 if new_x >= Pixels::ZERO {
3934 tooltip_bounds.origin.x = new_x;
3935 } else {
3936 tooltip_bounds.origin.x = cmp::max(
3937 Pixels::ZERO,
3938 tooltip_bounds.origin.x - tooltip_bounds.right() - window_bounds.right(),
3939 );
3940 }
3941 }
3942
3943 if tooltip_bounds.bottom() > window_bounds.bottom() {
3944 let new_y = mouse_position.y - tooltip_bounds.size.height - px(1.);
3945 if new_y >= Pixels::ZERO {
3946 tooltip_bounds.origin.y = new_y;
3947 } else {
3948 tooltip_bounds.origin.y = cmp::max(
3949 Pixels::ZERO,
3950 tooltip_bounds.origin.y - tooltip_bounds.bottom() - window_bounds.bottom(),
3951 );
3952 }
3953 }
3954
3955 let is_visible =
3959 (tooltip_request.tooltip.check_visible_and_update)(tooltip_bounds, self, cx);
3960 if !is_visible {
3961 continue;
3962 }
3963
3964 self.with_absolute_element_offset(tooltip_bounds.origin, |window| {
3965 element.prepaint(window, cx)
3966 });
3967
3968 self.frame_state.tooltip_bounds = Some(TooltipBounds {
3969 id: tooltip_request.id,
3970 bounds: tooltip_bounds,
3971 });
3972 return Some(element);
3973 }
3974 None
3975 }
3976
3977 fn prepaint_deferred_draws(&mut self, cx: &mut App) {
3978 assert_eq!(self.frame_state.element_id_stack.len(), 0);
3979
3980 let mut round_start = 0;
3991 let mut depth = 0;
3992 loop {
3993 let round_end = self.frame_state.next_frame.deferred_draws.len();
3994 if round_start == round_end {
3995 break;
3996 }
3997 assert!(depth < 10, "Exceeded maximum (10) deferred depth");
3999 depth += 1;
4000
4001 let mut traversal_order = (round_start..round_end).collect::<SmallVec<[usize; 8]>>();
4003 traversal_order
4004 .sort_by_key(|ix| self.frame_state.next_frame.deferred_draws[*ix].priority);
4005
4006 for deferred_draw_ix in traversal_order {
4007 let (element, parent_node, current_view, rem_size, absolute_offset, prepaint_range) = {
4008 let deferred_draw =
4009 &mut self.frame_state.next_frame.deferred_draws[deferred_draw_ix];
4010 self.frame_state
4011 .element_id_stack
4012 .clone_from(&deferred_draw.element_id_stack);
4013 self.frame_state
4014 .text_style_stack
4015 .clone_from(&deferred_draw.text_style_stack);
4016 (
4017 deferred_draw.element.take(),
4018 deferred_draw.parent_node,
4019 deferred_draw.current_view,
4020 deferred_draw.rem_size,
4021 deferred_draw.absolute_offset,
4022 deferred_draw.prepaint_range.clone(),
4023 )
4024 };
4025 self.frame_state
4026 .next_frame
4027 .dispatch_tree
4028 .set_active_node(parent_node);
4029
4030 let prepaint_start = self.prepaint_index();
4031 if let Some(mut element) = element {
4032 self.with_rendered_view(current_view, |window| {
4033 window.with_rem_size(Some(rem_size), |window| {
4034 window.with_absolute_element_offset(absolute_offset, |window| {
4035 element.prepaint(window, cx);
4036 });
4037 });
4038 });
4039 self.frame_state.next_frame.deferred_draws[deferred_draw_ix].element =
4040 Some(element);
4041 } else {
4042 self.reuse_prepaint(prepaint_range);
4043 }
4044 let prepaint_end = self.prepaint_index();
4045 self.frame_state.next_frame.deferred_draws[deferred_draw_ix].prepaint_range =
4046 prepaint_start..prepaint_end;
4047 }
4048
4049 self.frame_state.element_id_stack.clear();
4050 self.frame_state.text_style_stack.clear();
4051 round_start = round_end;
4052 }
4053 }
4054
4055 fn paint_deferred_draws(&mut self, cx: &mut App) {
4056 assert_eq!(self.frame_state.element_id_stack.len(), 0);
4057
4058 if self.frame_state.next_frame.deferred_draws.len() == 0 {
4061 return;
4062 }
4063
4064 let traversal_order = self.deferred_draw_traversal_order();
4065 let mut deferred_draws = mem::take(&mut self.frame_state.next_frame.deferred_draws);
4066 for deferred_draw_ix in traversal_order {
4067 let mut deferred_draw = &mut deferred_draws[deferred_draw_ix];
4068 self.frame_state
4069 .element_id_stack
4070 .clone_from(&deferred_draw.element_id_stack);
4071 self.frame_state
4072 .next_frame
4073 .dispatch_tree
4074 .set_active_node(deferred_draw.parent_node);
4075
4076 let paint_start = self.paint_index();
4077 let content_mask = deferred_draw.content_mask;
4078 if let Some(element) = deferred_draw.element.as_mut() {
4079 self.with_rendered_view(deferred_draw.current_view, |window| {
4080 window.with_content_mask(content_mask, |window| {
4081 window.with_rem_size(Some(deferred_draw.rem_size), |window| {
4082 element.paint(window, cx);
4083 });
4084 })
4085 })
4086 } else {
4087 self.reuse_paint(deferred_draw.paint_range.clone());
4088 }
4089 let paint_end = self.paint_index();
4090 deferred_draw.paint_range = paint_start..paint_end;
4091 }
4092 self.frame_state.next_frame.deferred_draws = deferred_draws;
4093 self.frame_state.element_id_stack.clear();
4094 }
4095
4096 fn deferred_draw_traversal_order(&mut self) -> SmallVec<[usize; 8]> {
4097 let deferred_count = self.frame_state.next_frame.deferred_draws.len();
4098 let mut sorted_indices = (0..deferred_count).collect::<SmallVec<[_; 8]>>();
4099 sorted_indices.sort_by_key(|ix| self.frame_state.next_frame.deferred_draws[*ix].priority);
4100 sorted_indices
4101 }
4102
4103 pub(crate) fn prepaint_index(&self) -> PrepaintStateIndex {
4104 PrepaintStateIndex {
4105 hitboxes_index: self.frame_state.next_frame.hitboxes.len(),
4106 tooltips_index: self.frame_state.next_frame.tooltip_requests.len(),
4107 deferred_draws_index: self.frame_state.next_frame.deferred_draws.len(),
4108 dispatch_tree_index: self.frame_state.next_frame.dispatch_tree.len(),
4109 accessed_element_states_index: self
4110 .frame_state
4111 .next_frame
4112 .accessed_element_states
4113 .len(),
4114 line_layout_index: self.core.text_system.layout_index(),
4115 }
4116 }
4117
4118 pub(crate) fn reuse_prepaint(&mut self, range: Range<PrepaintStateIndex>) {
4119 self.frame_state.next_frame.hitboxes.extend(
4120 self.frame_state.rendered_frame.hitboxes
4121 [range.start.hitboxes_index..range.end.hitboxes_index]
4122 .iter()
4123 .cloned(),
4124 );
4125 self.frame_state.next_frame.tooltip_requests.extend(
4126 self.frame_state.rendered_frame.tooltip_requests
4127 [range.start.tooltips_index..range.end.tooltips_index]
4128 .iter_mut()
4129 .map(|request| request.take()),
4130 );
4131 self.frame_state.next_frame.accessed_element_states.extend(
4132 self.frame_state.rendered_frame.accessed_element_states[range
4133 .start
4134 .accessed_element_states_index
4135 ..range.end.accessed_element_states_index]
4136 .iter()
4137 .map(|(id, type_id)| (id.clone(), *type_id)),
4138 );
4139 self.core
4140 .text_system
4141 .reuse_layouts(range.start.line_layout_index..range.end.line_layout_index);
4142
4143 let reused_subtree = self.frame_state.next_frame.dispatch_tree.reuse_subtree(
4144 range.start.dispatch_tree_index..range.end.dispatch_tree_index,
4145 &mut self.frame_state.rendered_frame.dispatch_tree,
4146 self.core.focus,
4147 );
4148
4149 if reused_subtree.contains_focus() {
4150 self.frame_state.next_frame.focus = self.core.focus;
4151 }
4152
4153 self.frame_state.next_frame.deferred_draws.extend(
4154 self.frame_state.rendered_frame.deferred_draws
4155 [range.start.deferred_draws_index..range.end.deferred_draws_index]
4156 .iter()
4157 .map(|deferred_draw| DeferredDraw {
4158 current_view: deferred_draw.current_view,
4159 parent_node: reused_subtree.refresh_node_id(deferred_draw.parent_node),
4160 element_id_stack: deferred_draw.element_id_stack.clone(),
4161 text_style_stack: deferred_draw.text_style_stack.clone(),
4162 content_mask: deferred_draw.content_mask,
4163 rem_size: deferred_draw.rem_size,
4164 priority: deferred_draw.priority,
4165 element: None,
4166 absolute_offset: deferred_draw.absolute_offset,
4167 prepaint_range: deferred_draw.prepaint_range.clone(),
4168 paint_range: deferred_draw.paint_range.clone(),
4169 }),
4170 );
4171 }
4172
4173 pub(crate) fn paint_index(&self) -> PaintIndex {
4174 PaintIndex {
4175 scene_index: self.frame_state.next_frame.scene.len(),
4176 mouse_listeners_index: self.frame_state.next_frame.mouse_listeners.len(),
4177 input_handlers_index: self.frame_state.next_frame.input_handlers.len(),
4178 cursor_styles_index: self.frame_state.next_frame.cursor_styles.len(),
4179 accessed_element_states_index: self
4180 .frame_state
4181 .next_frame
4182 .accessed_element_states
4183 .len(),
4184 tab_handle_index: self.frame_state.next_frame.tab_stops.paint_index(),
4185 line_layout_index: self.core.text_system.layout_index(),
4186 }
4187 }
4188
4189 pub(crate) fn reuse_paint(&mut self, range: Range<PaintIndex>) {
4190 self.frame_state.next_frame.cursor_styles.extend(
4191 self.frame_state.rendered_frame.cursor_styles
4192 [range.start.cursor_styles_index..range.end.cursor_styles_index]
4193 .iter()
4194 .cloned(),
4195 );
4196 self.frame_state.next_frame.input_handlers.extend(
4197 self.frame_state.rendered_frame.input_handlers
4198 [range.start.input_handlers_index..range.end.input_handlers_index]
4199 .iter_mut()
4200 .map(|handler| handler.take()),
4201 );
4202 self.frame_state.next_frame.mouse_listeners.extend(
4203 self.frame_state.rendered_frame.mouse_listeners
4204 [range.start.mouse_listeners_index..range.end.mouse_listeners_index]
4205 .iter_mut()
4206 .map(|listener| listener.take()),
4207 );
4208 self.frame_state.next_frame.accessed_element_states.extend(
4209 self.frame_state.rendered_frame.accessed_element_states[range
4210 .start
4211 .accessed_element_states_index
4212 ..range.end.accessed_element_states_index]
4213 .iter()
4214 .map(|(id, type_id)| (id.clone(), *type_id)),
4215 );
4216 self.frame_state.next_frame.tab_stops.replay(
4217 &self.frame_state.rendered_frame.tab_stops.insertion_history
4218 [range.start.tab_handle_index..range.end.tab_handle_index],
4219 );
4220
4221 self.core
4222 .text_system
4223 .reuse_layouts(range.start.line_layout_index..range.end.line_layout_index);
4224 self.frame_state.next_frame.scene.replay(
4225 range.start.scene_index..range.end.scene_index,
4226 &self.frame_state.rendered_frame.scene,
4227 );
4228 }
4229
4230 pub fn with_text_style<F, R>(&mut self, style: Option<TextStyleRefinement>, f: F) -> R
4234 where
4235 F: FnOnce(&mut Self) -> R,
4236 {
4237 self.core.invalidator.debug_assert_paint_or_prepaint();
4238 if let Some(style) = style {
4239 self.frame_state.text_style_stack.push(style);
4240 let result = f(self);
4241 self.frame_state.text_style_stack.pop();
4242 result
4243 } else {
4244 f(self)
4245 }
4246 }
4247
4248 pub fn set_cursor_style(&mut self, style: CursorStyle, hitbox: &Hitbox) {
4251 self.core.invalidator.debug_assert_paint();
4252 self.frame_state
4253 .next_frame
4254 .cursor_styles
4255 .push(CursorStyleRequest {
4256 hitbox_id: Some(hitbox.id),
4257 style,
4258 });
4259 }
4260
4261 pub fn set_window_cursor_style(&mut self, style: CursorStyle) {
4266 self.core.invalidator.debug_assert_paint();
4267 self.frame_state
4268 .next_frame
4269 .cursor_styles
4270 .push(CursorStyleRequest {
4271 hitbox_id: None,
4272 style,
4273 })
4274 }
4275
4276 pub fn set_tooltip(&mut self, tooltip: AnyTooltip) -> TooltipId {
4279 self.core.invalidator.debug_assert_prepaint();
4280 let id = TooltipId(post_inc(&mut self.frame_state.next_tooltip_id.0));
4281 self.frame_state
4282 .next_frame
4283 .tooltip_requests
4284 .push(Some(TooltipRequest { id, tooltip }));
4285 id
4286 }
4287
4288 #[inline]
4293 pub fn with_content_mask<R>(
4294 &mut self,
4295 mask: Option<ContentMask<Pixels>>,
4296 f: impl FnOnce(&mut Self) -> R,
4297 ) -> R {
4298 self.core.invalidator.debug_assert_paint_or_prepaint();
4299 if let Some(mask) = mask {
4300 let mask = mask.intersect(&self.content_mask());
4301 self.frame_state.content_mask_stack.push(mask);
4302 let result = f(self);
4303 self.frame_state.content_mask_stack.pop();
4304 result
4305 } else {
4306 f(self)
4307 }
4308 }
4309
4310 pub fn with_element_offset<R>(
4313 &mut self,
4314 offset: Point<Pixels>,
4315 f: impl FnOnce(&mut Self) -> R,
4316 ) -> R {
4317 self.core.invalidator.debug_assert_prepaint();
4318
4319 if offset.is_zero() {
4320 return f(self);
4321 };
4322
4323 let abs_offset = self.element_offset() + offset;
4324 self.with_absolute_element_offset(abs_offset, f)
4325 }
4326
4327 pub fn with_absolute_element_offset<R>(
4331 &mut self,
4332 offset: Point<Pixels>,
4333 f: impl FnOnce(&mut Self) -> R,
4334 ) -> R {
4335 self.core.invalidator.debug_assert_prepaint();
4336 self.frame_state.element_offset_stack.push(offset);
4337 let result = f(self);
4338 self.frame_state.element_offset_stack.pop();
4339 result
4340 }
4341
4342 pub(crate) fn with_element_opacity<R>(
4343 &mut self,
4344 opacity: Option<f32>,
4345 f: impl FnOnce(&mut Self) -> R,
4346 ) -> R {
4347 self.core.invalidator.debug_assert_paint_or_prepaint();
4348
4349 let Some(opacity) = opacity else {
4350 return f(self);
4351 };
4352
4353 let previous_opacity = self.frame_state.element_opacity;
4354 self.frame_state.element_opacity = previous_opacity * opacity;
4355 let result = f(self);
4356 self.frame_state.element_opacity = previous_opacity;
4357 result
4358 }
4359
4360 pub fn transact<T, U>(&mut self, f: impl FnOnce(&mut Self) -> Result<T, U>) -> Result<T, U> {
4366 self.core.invalidator.debug_assert_prepaint();
4367 let index = self.prepaint_index();
4368 let result = f(self);
4369 if result.is_err() {
4370 self.frame_state
4371 .next_frame
4372 .hitboxes
4373 .truncate(index.hitboxes_index);
4374 self.frame_state
4375 .next_frame
4376 .tooltip_requests
4377 .truncate(index.tooltips_index);
4378 self.frame_state
4379 .next_frame
4380 .deferred_draws
4381 .truncate(index.deferred_draws_index);
4382 self.frame_state
4383 .next_frame
4384 .dispatch_tree
4385 .truncate(index.dispatch_tree_index);
4386 self.frame_state
4387 .next_frame
4388 .accessed_element_states
4389 .truncate(index.accessed_element_states_index);
4390 self.core
4391 .text_system
4392 .truncate_layouts(index.line_layout_index);
4393 }
4394 result
4395 }
4396
4397 pub fn request_autoscroll(&mut self, bounds: Bounds<Pixels>) {
4403 self.core.invalidator.debug_assert_prepaint();
4404 self.frame_state.requested_autoscroll = Some(bounds);
4405 }
4406
4407 pub fn take_autoscroll(&mut self) -> Option<Bounds<Pixels>> {
4410 self.core.invalidator.debug_assert_prepaint();
4411 self.frame_state.requested_autoscroll.take()
4412 }
4413
4414 pub fn use_asset<A: Asset>(&mut self, source: &A::Source, cx: &mut App) -> Option<A::Output> {
4420 cx.asset_entry::<A>(source).use_by(self.current_view())
4421 }
4422
4423 pub fn get_asset<A: Asset>(&mut self, source: &A::Source, cx: &mut App) -> Option<A::Output> {
4429 cx.fetch_asset::<A>(source)
4430 }
4431 pub fn element_offset(&self) -> Point<Pixels> {
4434 self.core.invalidator.debug_assert_prepaint();
4435 self.frame_state
4436 .element_offset_stack
4437 .last()
4438 .copied()
4439 .unwrap_or_default()
4440 }
4441
4442 #[inline]
4445 pub(crate) fn element_opacity(&self) -> f32 {
4446 self.core.invalidator.debug_assert_paint_or_prepaint();
4447 self.frame_state.element_opacity
4448 }
4449
4450 pub fn content_mask(&self) -> ContentMask<Pixels> {
4452 self.core.invalidator.debug_assert_paint_or_prepaint();
4453 self.frame_state
4454 .content_mask_stack
4455 .last()
4456 .cloned()
4457 .unwrap_or_else(|| ContentMask {
4458 bounds: Bounds {
4459 origin: Point::default(),
4460 size: self.core.viewport_size,
4461 },
4462 })
4463 }
4464
4465 pub fn with_element_namespace<R>(
4468 &mut self,
4469 element_id: impl Into<ElementId>,
4470 f: impl FnOnce(&mut Self) -> R,
4471 ) -> R {
4472 self.frame_state.element_id_stack.push(element_id.into());
4473 let result = f(self);
4474 self.frame_state.element_id_stack.pop();
4475 result
4476 }
4477
4478 pub fn use_keyed_state<S: 'static>(
4480 &mut self,
4481 key: impl Into<ElementId>,
4482 cx: &mut App,
4483 init: impl FnOnce(&mut Self, &mut Context<S>) -> S,
4484 ) -> Entity<S> {
4485 let current_view = self.current_view();
4486 self.with_global_id(key.into(), |global_id, window| {
4487 window.with_element_state(global_id, |state: Option<Entity<S>>, window| {
4488 if let Some(state) = state {
4489 (state.clone(), state)
4490 } else {
4491 let new_state = cx.new(|cx| init(window, cx));
4492 cx.observe(&new_state, move |_, cx| {
4493 cx.notify(current_view);
4494 })
4495 .detach();
4496 (new_state.clone(), new_state)
4497 }
4498 })
4499 })
4500 }
4501
4502 #[track_caller]
4508 pub fn use_state<S: 'static>(
4509 &mut self,
4510 cx: &mut App,
4511 init: impl FnOnce(&mut Self, &mut Context<S>) -> S,
4512 ) -> Entity<S> {
4513 self.use_keyed_state(
4514 ElementId::CodeLocation(*core::panic::Location::caller()),
4515 cx,
4516 init,
4517 )
4518 }
4519
4520 pub fn with_element_state<S, R>(
4525 &mut self,
4526 global_id: &GlobalElementId,
4527 f: impl FnOnce(Option<S>, &mut Self) -> (R, S),
4528 ) -> R
4529 where
4530 S: 'static,
4531 {
4532 self.core.invalidator.debug_assert_paint_or_prepaint();
4533
4534 let key = (global_id.clone(), TypeId::of::<S>());
4535 self.frame_state
4536 .next_frame
4537 .accessed_element_states
4538 .push(key.clone());
4539
4540 if let Some(any) = self
4541 .frame_state
4542 .next_frame
4543 .element_states
4544 .remove(&key)
4545 .or_else(|| self.frame_state.rendered_frame.element_states.remove(&key))
4546 {
4547 let ElementStateBox {
4548 inner,
4549 #[cfg(debug_assertions)]
4550 type_name,
4551 } = any;
4552 let mut state_box = inner
4554 .downcast::<Option<S>>()
4555 .map_err(|_| {
4556 #[cfg(debug_assertions)]
4557 {
4558 anyhow::anyhow!(
4559 "invalid element state type for id, requested {:?}, actual: {:?}",
4560 std::any::type_name::<S>(),
4561 type_name
4562 )
4563 }
4564
4565 #[cfg(not(debug_assertions))]
4566 {
4567 anyhow::anyhow!(
4568 "invalid element state type for id, requested {:?}",
4569 std::any::type_name::<S>(),
4570 )
4571 }
4572 })
4573 .unwrap();
4574
4575 let state = state_box.take().expect(
4576 "reentrant call to with_element_state for the same state type and element id",
4577 );
4578 let (result, state) = f(Some(state), self);
4579 state_box.replace(state);
4580 self.frame_state.next_frame.element_states.insert(
4581 key,
4582 ElementStateBox {
4583 inner: state_box,
4584 #[cfg(debug_assertions)]
4585 type_name,
4586 },
4587 );
4588 result
4589 } else {
4590 let (result, state) = f(None, self);
4591 self.frame_state.next_frame.element_states.insert(
4592 key,
4593 ElementStateBox {
4594 inner: Box::new(Some(state)),
4595 #[cfg(debug_assertions)]
4596 type_name: std::any::type_name::<S>(),
4597 },
4598 );
4599 result
4600 }
4601 }
4602
4603 pub fn with_optional_element_state<S, R>(
4610 &mut self,
4611 global_id: Option<&GlobalElementId>,
4612 f: impl FnOnce(Option<Option<S>>, &mut Self) -> (R, Option<S>),
4613 ) -> R
4614 where
4615 S: 'static,
4616 {
4617 self.core.invalidator.debug_assert_paint_or_prepaint();
4618
4619 if let Some(global_id) = global_id {
4620 self.with_element_state(global_id, |state, cx| {
4621 let (result, state) = f(Some(state), cx);
4622 let state =
4623 state.expect("you must return some state when you pass some element id");
4624 (result, state)
4625 })
4626 } else {
4627 let (result, state) = f(None, self);
4628 debug_assert!(
4629 state.is_none(),
4630 "you must not return an element state when passing None for the global id"
4631 );
4632 result
4633 }
4634 }
4635
4636 #[inline]
4638 pub fn with_tab_group<R>(&mut self, index: Option<isize>, f: impl FnOnce(&mut Self) -> R) -> R {
4639 if let Some(index) = index {
4640 self.frame_state.next_frame.tab_stops.begin_group(index);
4641 let result = f(self);
4642 self.frame_state.next_frame.tab_stops.end_group();
4643 result
4644 } else {
4645 f(self)
4646 }
4647 }
4648
4649 pub fn defer_draw(
4658 &mut self,
4659 element: AnyElement,
4660 absolute_offset: Point<Pixels>,
4661 priority: usize,
4662 content_mask: Option<ContentMask<Pixels>>,
4663 ) {
4664 self.core.invalidator.debug_assert_prepaint();
4665 let parent_node = self
4666 .frame_state
4667 .next_frame
4668 .dispatch_tree
4669 .active_node_id()
4670 .unwrap();
4671 self.frame_state
4672 .next_frame
4673 .deferred_draws
4674 .push(DeferredDraw {
4675 current_view: self.current_view(),
4676 parent_node,
4677 element_id_stack: self.frame_state.element_id_stack.clone(),
4678 text_style_stack: self.frame_state.text_style_stack.clone(),
4679 content_mask,
4680 rem_size: self.rem_size(),
4681 priority,
4682 element: Some(element),
4683 absolute_offset,
4684 prepaint_range: PrepaintStateIndex::default()..PrepaintStateIndex::default(),
4685 paint_range: PaintIndex::default()..PaintIndex::default(),
4686 });
4687 }
4688
4689 pub fn paint_layer<R>(&mut self, bounds: Bounds<Pixels>, f: impl FnOnce(&mut Self) -> R) -> R {
4695 self.core.invalidator.debug_assert_paint();
4696
4697 let content_mask = self.content_mask();
4698 let clipped_bounds = bounds.intersect(&content_mask.bounds);
4699 if !clipped_bounds.is_empty() {
4700 self.frame_state
4701 .next_frame
4702 .scene
4703 .push_layer(self.cover_bounds(clipped_bounds));
4704 }
4705
4706 let result = f(self);
4707
4708 if !clipped_bounds.is_empty() {
4709 self.frame_state.next_frame.scene.pop_layer();
4710 }
4711
4712 result
4713 }
4714
4715 pub fn paint_drop_shadows(
4722 &mut self,
4723 bounds: Bounds<Pixels>,
4724 corner_radii: Corners<Pixels>,
4725 shadows: &[BoxShadow],
4726 ) {
4727 self.core.invalidator.debug_assert_paint();
4728
4729 let scale_factor = self.scale_factor();
4730 let content_mask = self.snapped_content_mask();
4731 let opacity = self.element_opacity();
4732 let element_bounds = self.cover_bounds(bounds);
4733 let element_corner_radii = corner_radii.scale(scale_factor);
4734 for shadow in shadows {
4735 if shadow.inset {
4736 continue;
4737 }
4738 let shadow_bounds = (bounds + shadow.offset).dilate(shadow.spread_radius);
4739 self.frame_state.next_frame.scene.insert_primitive(Shadow {
4740 order: 0,
4741 blur_radius: shadow.blur_radius.scale(scale_factor),
4742 bounds: self.cover_bounds(shadow_bounds),
4743 content_mask,
4744 corner_radii: corner_radii.scale(scale_factor),
4745 color: shadow.color.opacity(opacity),
4746 element_bounds,
4747 element_corner_radii,
4748 inset: 0,
4749 pad: 0,
4750 });
4751 }
4752 }
4753
4754 pub fn paint_inset_shadows(
4759 &mut self,
4760 bounds: Bounds<Pixels>,
4761 corner_radii: Corners<Pixels>,
4762 shadows: &[BoxShadow],
4763 ) {
4764 self.core.invalidator.debug_assert_paint();
4765
4766 let scale_factor = self.scale_factor();
4767 let content_mask = self.snapped_content_mask();
4768 let opacity = self.element_opacity();
4769 let element_bounds = self.cover_bounds(bounds);
4770 let element_corner_radii = corner_radii.scale(scale_factor);
4771 for shadow in shadows {
4772 if !shadow.inset {
4773 continue;
4774 }
4775 let hole = (bounds + shadow.offset).dilate(-shadow.spread_radius);
4776 let zero = Pixels::ZERO;
4779 let hole_corner_radii = Corners {
4780 top_left: (corner_radii.top_left - shadow.spread_radius).max(zero),
4781 top_right: (corner_radii.top_right - shadow.spread_radius).max(zero),
4782 bottom_right: (corner_radii.bottom_right - shadow.spread_radius).max(zero),
4783 bottom_left: (corner_radii.bottom_left - shadow.spread_radius).max(zero),
4784 };
4785 self.frame_state.next_frame.scene.insert_primitive(Shadow {
4786 order: 0,
4787 blur_radius: shadow.blur_radius.scale(scale_factor),
4788 bounds: self.cover_bounds(hole),
4789 content_mask,
4790 corner_radii: hole_corner_radii.scale(scale_factor),
4791 color: shadow.color.opacity(opacity),
4792 element_bounds,
4793 element_corner_radii,
4794 inset: 1,
4795 pad: 0,
4796 });
4797 }
4798 }
4799
4800 fn largest_border_interior(quad: &Quad) -> Bounds<ScaledPixels> {
4801 let radii = &quad.corner_radii;
4802 let widths = &quad.border_widths;
4803 let edge_radii = Edges {
4804 top: radii.top_left.max(radii.top_right),
4805 right: radii.top_right.max(radii.bottom_right),
4806 bottom: radii.bottom_left.max(radii.bottom_right),
4807 left: radii.top_left.max(radii.bottom_left),
4808 };
4809
4810 let antialias_inset = point(ScaledPixels(1.0), ScaledPixels(1.0));
4811 let inset_bounds = |top_left_inset, bottom_right_inset| {
4812 Bounds::from_corners(
4813 quad.bounds.origin + top_left_inset + antialias_inset,
4814 quad.bounds.bottom_right() - bottom_right_inset - antialias_inset,
4815 )
4816 };
4817
4818 let horizontal_band = inset_bounds(
4821 point(widths.left, widths.top.max(edge_radii.top)),
4822 point(widths.right, widths.bottom.max(edge_radii.bottom)),
4823 );
4824 let vertical_band = inset_bounds(
4825 point(widths.left.max(edge_radii.left), widths.top),
4826 point(widths.right.max(edge_radii.right), widths.bottom),
4827 );
4828
4829 let area = |bounds: &Bounds<ScaledPixels>| {
4830 bounds.size.width.0.max(0.) * bounds.size.height.0.max(0.)
4831 };
4832 if area(&horizontal_band) >= area(&vertical_band) {
4833 horizontal_band
4834 } else {
4835 vertical_band
4836 }
4837 }
4838
4839 pub fn paint_quad(&mut self, quad: PaintQuad) {
4850 self.core.invalidator.debug_assert_paint();
4851
4852 let opacity = self.element_opacity();
4853 let snapped_bounds = self.snap_bounds(quad.bounds);
4854 let snapped_border_widths = self.snap_border_widths(quad.border_widths);
4855 let quad = Quad {
4856 order: 0,
4857 bounds: snapped_bounds,
4858 content_mask: self.snapped_content_mask(),
4859 background: quad.background.opacity(opacity),
4860 border_color: quad.border_color.opacity(opacity),
4861 corner_radii: quad.corner_radii.scale(self.scale_factor()),
4862 border_widths: snapped_border_widths,
4863 border_style: quad.border_style,
4864 };
4865
4866 if !quad.background.is_transparent() {
4867 self.frame_state.next_frame.scene.insert_primitive(quad);
4868 return;
4869 }
4870
4871 let outer_bounds = quad.bounds;
4874 let inner_bounds = Self::largest_border_interior(&quad);
4875
4876 if inner_bounds.is_empty() {
4877 self.frame_state.next_frame.scene.insert_primitive(quad);
4878 return;
4879 }
4880
4881 let strips = [
4882 Bounds::from_corners(
4884 outer_bounds.origin,
4885 point(outer_bounds.right(), inner_bounds.top()),
4886 ),
4887 Bounds::from_corners(
4889 point(outer_bounds.left(), inner_bounds.bottom()),
4890 outer_bounds.bottom_right(),
4891 ),
4892 Bounds::from_corners(
4894 point(outer_bounds.left(), inner_bounds.top()),
4895 inner_bounds.bottom_left(),
4896 ),
4897 Bounds::from_corners(
4899 inner_bounds.top_right(),
4900 point(outer_bounds.right(), inner_bounds.bottom()),
4901 ),
4902 ];
4903
4904 for strip in strips {
4905 let content_mask_bounds = quad.content_mask.bounds.intersect(&strip);
4906 if !content_mask_bounds.is_empty() {
4907 self.frame_state.next_frame.scene.insert_primitive(Quad {
4908 content_mask: ContentMask {
4909 bounds: content_mask_bounds,
4910 },
4911 ..quad
4912 });
4913 }
4914 }
4915 }
4916
4917 pub fn paint_path(&mut self, mut path: Path<Pixels>, color: impl Into<Background>) {
4922 self.core.invalidator.debug_assert_paint();
4923
4924 let scale_factor = self.scale_factor();
4925 let content_mask = self.content_mask();
4926 let opacity = self.element_opacity();
4927 path.content_mask = content_mask;
4928 let color: Background = color.into();
4929 path.color = color.opacity(opacity);
4930 self.frame_state
4931 .next_frame
4932 .scene
4933 .insert_primitive(path.scale(scale_factor));
4934 }
4935
4936 pub fn paint_underline(
4940 &mut self,
4941 origin: Point<Pixels>,
4942 width: Pixels,
4943 style: &UnderlineStyle,
4944 ) {
4945 self.core.invalidator.debug_assert_paint();
4946
4947 let scale_factor = self.scale_factor();
4948 let thickness = self.snap_stroke(style.thickness);
4949 let height = if style.wavy {
4950 ScaledPixels(thickness.0 * 3.)
4951 } else {
4952 thickness
4953 };
4954 let bounds = Bounds {
4955 origin: origin.map(|c| ScaledPixels(round_to_device_pixel(c.0, scale_factor))),
4956 size: size(self.snap_stroke(width), height),
4957 };
4958 let element_opacity = self.element_opacity();
4959
4960 self.frame_state
4961 .next_frame
4962 .scene
4963 .insert_primitive(Underline {
4964 order: 0,
4965 pad: 0,
4966 bounds,
4967 content_mask: self.snapped_content_mask(),
4968 color: style.color.unwrap_or_default().opacity(element_opacity),
4969 thickness,
4970 wavy: style.wavy.into(),
4971 });
4972 }
4973
4974 pub fn paint_strikethrough(
4978 &mut self,
4979 origin: Point<Pixels>,
4980 width: Pixels,
4981 style: &StrikethroughStyle,
4982 ) {
4983 self.core.invalidator.debug_assert_paint();
4984
4985 let scale_factor = self.scale_factor();
4986 let height = style.thickness;
4987 let bounds = Bounds {
4988 origin: origin.map(|c| ScaledPixels(round_to_device_pixel(c.0, scale_factor))),
4989 size: size(self.snap_stroke(width), self.snap_stroke(height)),
4990 };
4991 let opacity = self.element_opacity();
4992
4993 self.frame_state
4994 .next_frame
4995 .scene
4996 .insert_primitive(Underline {
4997 order: 0,
4998 pad: 0,
4999 bounds,
5000 content_mask: self.snapped_content_mask(),
5001 thickness: self.snap_stroke(style.thickness),
5002 color: style.color.unwrap_or_default().opacity(opacity),
5003 wavy: false.into(),
5004 });
5005 }
5006
5007 pub fn paint_glyph(
5016 &mut self,
5017 origin: Point<Pixels>,
5018 font_id: FontId,
5019 glyph_id: GlyphId,
5020 font_size: Pixels,
5021 color: Hsla,
5022 ) -> Result<()> {
5023 self.core.invalidator.debug_assert_paint();
5024
5025 let element_opacity = self.element_opacity();
5026 let scale_factor = self.scale_factor();
5027 let glyph_origin = origin.scale(scale_factor);
5028
5029 let quantized_origin = Point::new(
5030 round_half_toward_zero(glyph_origin.x.0 * SUBPIXEL_VARIANTS_X as f32)
5031 / SUBPIXEL_VARIANTS_X as f32,
5032 round_half_toward_zero(glyph_origin.y.0 * SUBPIXEL_VARIANTS_Y as f32)
5033 / SUBPIXEL_VARIANTS_Y as f32,
5034 );
5035 let subpixel_variant = Point::new(
5036 (quantized_origin.x.fract() * SUBPIXEL_VARIANTS_X as f32) as u8,
5037 (quantized_origin.y.fract() * SUBPIXEL_VARIANTS_Y as f32) as u8,
5038 );
5039 let integer_origin = quantized_origin.map(|c| ScaledPixels(c.trunc()));
5040 let subpixel_rendering = self.should_use_subpixel_rendering(font_id, font_size);
5041 let dilation = self.text_system().glyph_dilation_for_color(color);
5042 let params = RenderGlyphParams {
5043 font_id,
5044 glyph_id,
5045 font_size,
5046 subpixel_variant,
5047 scale_factor,
5048 is_emoji: false,
5049 subpixel_rendering,
5050 dilation,
5051 };
5052
5053 let raster_bounds = self.text_system().raster_bounds(¶ms)?;
5054 if !raster_bounds.is_zero() {
5055 let tile = self
5056 .core
5057 .sprite_atlas
5058 .get_or_insert_with(¶ms.clone().into(), &mut || {
5059 let (size, bytes) = self.text_system().rasterize_glyph(¶ms)?;
5060 Ok(Some((size, Cow::Owned(bytes))))
5061 })?
5062 .expect("Callback above only errors or returns Some");
5063 let bounds = Bounds {
5064 origin: integer_origin + raster_bounds.origin.map(Into::into),
5065 size: tile.bounds.size.map(Into::into),
5066 };
5067 let content_mask = self.snapped_content_mask();
5068
5069 if subpixel_rendering {
5070 self.frame_state
5071 .next_frame
5072 .scene
5073 .insert_primitive(SubpixelSprite {
5074 order: 0,
5075 pad: 0,
5076 bounds,
5077 content_mask,
5078 color: color.opacity(element_opacity),
5079 tile,
5080 transformation: TransformationMatrix::unit(),
5081 });
5082 } else {
5083 self.frame_state
5084 .next_frame
5085 .scene
5086 .insert_primitive(MonochromeSprite {
5087 order: 0,
5088 pad: 0,
5089 bounds,
5090 content_mask,
5091 color: color.opacity(element_opacity),
5092 tile,
5093 transformation: TransformationMatrix::unit(),
5094 });
5095 }
5096 }
5097 Ok(())
5098 }
5099
5100 fn should_use_subpixel_rendering(&self, font_id: FontId, font_size: Pixels) -> bool {
5101 if self.core.platform_window.background_appearance() != WindowBackgroundAppearance::Opaque {
5102 return false;
5103 }
5104
5105 if !self.core.platform_window.is_subpixel_rendering_supported() {
5106 return false;
5107 }
5108
5109 let mode = match self.core.text_rendering_mode.get() {
5110 TextRenderingMode::PlatformDefault => self
5111 .text_system()
5112 .recommended_rendering_mode(font_id, font_size),
5113 mode => mode,
5114 };
5115
5116 mode == TextRenderingMode::Subpixel
5117 }
5118
5119 pub fn paint_emoji(
5128 &mut self,
5129 origin: Point<Pixels>,
5130 font_id: FontId,
5131 glyph_id: GlyphId,
5132 font_size: Pixels,
5133 ) -> Result<()> {
5134 self.core.invalidator.debug_assert_paint();
5135
5136 let scale_factor = self.scale_factor();
5137 let glyph_origin = origin.scale(scale_factor);
5138 let integer_origin = glyph_origin.map(|c| ScaledPixels(round_half_toward_zero(c.0)));
5139 let params = RenderGlyphParams {
5140 font_id,
5141 glyph_id,
5142 font_size,
5143 subpixel_variant: Default::default(),
5144 scale_factor,
5145 is_emoji: true,
5146 subpixel_rendering: false,
5147 dilation: 0,
5148 };
5149
5150 let raster_bounds = self.text_system().raster_bounds(¶ms)?;
5151 if !raster_bounds.is_zero() {
5152 let tile = self
5153 .core
5154 .sprite_atlas
5155 .get_or_insert_with(¶ms.clone().into(), &mut || {
5156 let (size, bytes) = self.text_system().rasterize_glyph(¶ms)?;
5157 Ok(Some((size, Cow::Owned(bytes))))
5158 })?
5159 .expect("Callback above only errors or returns Some");
5160
5161 let bounds = Bounds {
5162 origin: integer_origin + raster_bounds.origin.map(Into::into),
5163 size: tile.bounds.size.map(Into::into),
5164 };
5165 let content_mask = self.snapped_content_mask();
5166 let opacity = self.element_opacity();
5167
5168 self.frame_state
5169 .next_frame
5170 .scene
5171 .insert_primitive(PolychromeSprite {
5172 order: 0,
5173 pad: 0,
5174 grayscale: false.into(),
5175 bounds,
5176 corner_radii: Default::default(),
5177 content_mask,
5178 tile,
5179 opacity,
5180 });
5181 }
5182 Ok(())
5183 }
5184
5185 pub fn paint_svg(
5189 &mut self,
5190 bounds: Bounds<Pixels>,
5191 path: SharedString,
5192 mut data: Option<&[u8]>,
5193 transformation: TransformationMatrix,
5194 color: Hsla,
5195 cx: &App,
5196 ) -> Result<()> {
5197 self.core.invalidator.debug_assert_paint();
5198
5199 let element_opacity = self.element_opacity();
5200 let bounds = self.snap_bounds(bounds);
5201
5202 let params = RenderSvgParams {
5203 path,
5204 size: bounds.size.map(|pixels| {
5205 DevicePixels::from((pixels.0 * SMOOTH_SVG_SCALE_FACTOR).ceil() as i32)
5206 }),
5207 };
5208
5209 let Some(tile) =
5210 self.core
5211 .sprite_atlas
5212 .get_or_insert_with(¶ms.clone().into(), &mut || {
5213 let Some((size, bytes)) = cx.svg_renderer.render_alpha_mask(¶ms, data)?
5214 else {
5215 return Ok(None);
5216 };
5217 Ok(Some((size, Cow::Owned(bytes))))
5218 })?
5219 else {
5220 return Ok(());
5221 };
5222 let content_mask = self.snapped_content_mask();
5223 let svg_bounds = Bounds {
5224 origin: bounds.center()
5225 - Point::new(
5226 ScaledPixels(tile.bounds.size.width.0 as f32 / SMOOTH_SVG_SCALE_FACTOR / 2.),
5227 ScaledPixels(tile.bounds.size.height.0 as f32 / SMOOTH_SVG_SCALE_FACTOR / 2.),
5228 ),
5229 size: tile
5230 .bounds
5231 .size
5232 .map(|value| ScaledPixels(value.0 as f32 / SMOOTH_SVG_SCALE_FACTOR)),
5233 };
5234 let final_bounds = svg_bounds
5235 .map_origin(|value| ScaledPixels(round_half_toward_zero(value.0)))
5236 .map_size(|size| size.ceil());
5237
5238 self.frame_state
5239 .next_frame
5240 .scene
5241 .insert_primitive(MonochromeSprite {
5242 order: 0,
5243 pad: 0,
5244 bounds: final_bounds,
5245 content_mask,
5246 color: color.opacity(element_opacity),
5247 tile,
5248 transformation,
5249 });
5250
5251 Ok(())
5252 }
5253
5254 pub fn paint_image(
5264 &mut self,
5265 bounds: Bounds<Pixels>,
5266 image_bounds: Bounds<Pixels>,
5267 corner_radii: Corners<Pixels>,
5268 data: Arc<RenderImage>,
5269 frame_index: usize,
5270 grayscale: bool,
5271 ) -> Result<()> {
5272 self.core.invalidator.debug_assert_paint();
5273
5274 let visible_bounds = bounds.intersect(&image_bounds);
5275 if visible_bounds.size.width <= Pixels::ZERO || visible_bounds.size.height <= Pixels::ZERO {
5276 return Ok(());
5277 }
5278 if image_bounds.size.width <= Pixels::ZERO || image_bounds.size.height <= Pixels::ZERO {
5279 return Ok(());
5280 }
5281
5282 let params = RenderImageParams {
5283 image_id: data.id,
5284 frame_index,
5285 };
5286
5287 let tile = self
5288 .core
5289 .sprite_atlas
5290 .get_or_insert_with(¶ms.into(), &mut || {
5291 Ok(Some((
5292 data.size(frame_index),
5293 Cow::Borrowed(
5294 data.as_bytes(frame_index)
5295 .expect("It's the caller's job to pass a valid frame index"),
5296 ),
5297 )))
5298 })?
5299 .expect("Callback above only returns Some");
5300
5301 let visible_bounds_snapped = self.snap_bounds(visible_bounds);
5302
5303 let sub_tile = if visible_bounds == image_bounds {
5304 tile
5305 } else {
5306 let x_offset_ratio =
5307 (visible_bounds.origin.x - image_bounds.origin.x) / image_bounds.size.width;
5308 let y_offset_ratio =
5309 (visible_bounds.origin.y - image_bounds.origin.y) / image_bounds.size.height;
5310 let width_ratio = visible_bounds.size.width / image_bounds.size.width;
5311 let height_ratio = visible_bounds.size.height / image_bounds.size.height;
5312
5313 let tile_origin_x = tile.bounds.origin.x.0;
5314 let tile_origin_y = tile.bounds.origin.y.0;
5315 let tile_width = tile.bounds.size.width.0;
5316 let tile_height = tile.bounds.size.height.0;
5317
5318 let sub_origin_x = tile_origin_x + (x_offset_ratio * tile_width as f32).round() as i32;
5319 let sub_origin_y = tile_origin_y + (y_offset_ratio * tile_height as f32).round() as i32;
5320 let sub_width = (width_ratio * tile_width as f32).round() as i32;
5321 let sub_height = (height_ratio * tile_height as f32).round() as i32;
5322
5323 let max_x = tile_origin_x + tile_width;
5324 let max_y = tile_origin_y + tile_height;
5325
5326 let clamped_origin_x = sub_origin_x.clamp(tile_origin_x, max_x);
5327 let clamped_origin_y = sub_origin_y.clamp(tile_origin_y, max_y);
5328 let clamped_width = sub_width.min(max_x - clamped_origin_x).max(0);
5329 let clamped_height = sub_height.min(max_y - clamped_origin_y).max(0);
5330
5331 AtlasTile {
5332 bounds: Bounds {
5333 origin: point(
5334 DevicePixels(clamped_origin_x),
5335 DevicePixels(clamped_origin_y),
5336 ),
5337 size: size(DevicePixels(clamped_width), DevicePixels(clamped_height)),
5338 },
5339 ..tile
5340 }
5341 };
5342
5343 let content_mask = self.snapped_content_mask();
5344 let corner_radii = corner_radii
5345 .clamp_radii_for_quad_size(visible_bounds.size)
5346 .scale(self.scale_factor());
5347 let opacity = self.element_opacity();
5348
5349 self.frame_state
5350 .next_frame
5351 .scene
5352 .insert_primitive(PolychromeSprite {
5353 order: 0,
5354 pad: 0,
5355 grayscale: grayscale.into(),
5356 bounds: visible_bounds_snapped,
5357 content_mask,
5358 corner_radii,
5359 tile: sub_tile,
5360 opacity,
5361 });
5362 Ok(())
5363 }
5364
5365 pub fn drop_image(&mut self, data: Arc<RenderImage>) -> Result<()> {
5367 for frame_index in 0..data.frame_count() {
5368 let params = RenderImageParams {
5369 image_id: data.id,
5370 frame_index,
5371 };
5372
5373 self.core.sprite_atlas.remove(¶ms.clone().into());
5374 }
5375
5376 Ok(())
5377 }
5378
5379 #[cfg(any(test, feature = "test-support"))]
5381 pub fn has_image_atlas_entry(&self, data: &RenderImage) -> bool {
5382 data.frame_count() > 0
5383 && (0..data.frame_count()).all(|frame_index| {
5384 self.core.sprite_atlas.contains(
5385 &RenderImageParams {
5386 image_id: data.id,
5387 frame_index,
5388 }
5389 .into(),
5390 )
5391 })
5392 }
5393
5394 #[must_use]
5401 pub fn request_layout(
5402 &mut self,
5403 style: Style,
5404 children: impl IntoIterator<Item = LayoutId>,
5405 cx: &mut App,
5406 ) -> LayoutId {
5407 self.core.invalidator.debug_assert_prepaint();
5408
5409 cx.layout_id_buffer.clear();
5410 cx.layout_id_buffer.extend(children);
5411 let rem_size = self.rem_size();
5412 let scale_factor = self.scale_factor();
5413 let engine_style = to_engine_layout_style(&style);
5414
5415 self.frame_state.layout_session.request_layout(
5416 &engine_style,
5417 rem_size,
5418 scale_factor,
5419 &cx.layout_id_buffer,
5420 )
5421 }
5422
5423 pub fn request_measured_layout<F>(&mut self, style: Style, measure: F) -> LayoutId
5433 where
5434 F: Fn(Size<Option<Pixels>>, Size<AvailableSpace>, &mut Window, &mut App) -> Size<Pixels>
5435 + 'static,
5436 {
5437 self.core.invalidator.debug_assert_prepaint();
5438
5439 let rem_size = self.rem_size();
5440 let scale_factor = self.scale_factor();
5441 let engine_style = to_engine_layout_style(&style);
5442 let measure = move |known_dimensions, available_space, context: &mut dyn MeasureContext| {
5443 let MeasureHandles { window, app } = context.handles();
5444 let (core, frame_state) = window;
5445 let core = core
5446 .downcast_mut::<WindowHostCore>()
5447 .expect("measure context window half should be a window's core");
5448 let frame_state = frame_state
5449 .downcast_mut::<WindowFrameState>()
5450 .expect("measure context window half should be a window's frame state");
5451 let cx = app
5452 .downcast_mut::<App>()
5453 .expect("measure context app should be an App");
5454 measure(
5455 known_dimensions,
5456 available_space,
5457 &mut Window { core, frame_state },
5458 cx,
5459 )
5460 };
5461 self.frame_state.layout_session.request_measured_layout(
5462 &engine_style,
5463 rem_size,
5464 scale_factor,
5465 Box::new(measure),
5466 )
5467 }
5468
5469 pub(crate) fn compute_layout(
5475 &mut self,
5476 layout_id: LayoutId,
5477 available_space: Size<AvailableSpace>,
5478 cx: &mut App,
5479 ) {
5480 self.core.invalidator.debug_assert_prepaint();
5481
5482 let scale_factor = self.scale_factor();
5483 let layout_session = self.frame_state.layout_session.clone();
5484 let core = &mut *self.core;
5485 let frame_state = &mut *self.frame_state;
5486 layout_session.compute_layout(
5487 layout_id,
5488 available_space,
5489 scale_factor,
5490 &mut WindowMeasureContext {
5491 core,
5492 frame_state,
5493 cx,
5494 },
5495 );
5496 }
5497
5498 pub fn layout_bounds(&mut self, layout_id: LayoutId) -> Bounds<Pixels> {
5504 self.core.invalidator.debug_assert_prepaint();
5505
5506 let scale_factor = self.scale_factor();
5507 let mut bounds = self
5508 .frame_state
5509 .layout_session
5510 .layout_bounds(layout_id, scale_factor)
5511 .map(Into::into);
5512 let snapped_offset = self.pixel_snap_point(self.element_offset());
5513 bounds.origin += snapped_offset;
5514 bounds
5515 }
5516
5517 pub fn insert_hitbox(&mut self, bounds: Bounds<Pixels>, behavior: HitboxBehavior) -> Hitbox {
5524 self.core.invalidator.debug_assert_prepaint();
5525
5526 let content_mask = self.content_mask();
5527 let mut id = self.frame_state.next_hitbox_id;
5528 self.frame_state.next_hitbox_id = self.frame_state.next_hitbox_id.next();
5529 let hitbox = Hitbox {
5530 id,
5531 bounds,
5532 content_mask,
5533 behavior,
5534 };
5535 self.frame_state.next_frame.hitboxes.push(hitbox.clone());
5536 hitbox
5537 }
5538
5539 pub fn insert_window_control_hitbox(&mut self, area: WindowControlArea, hitbox: Hitbox) {
5543 self.core.invalidator.debug_assert_paint();
5544 self.frame_state
5545 .next_frame
5546 .window_control_hitboxes
5547 .push((area, hitbox));
5548 }
5549
5550 pub fn set_key_context(&mut self, context: KeyContext) {
5555 self.core.invalidator.debug_assert_paint();
5556 self.frame_state
5557 .next_frame
5558 .dispatch_tree
5559 .set_key_context(context);
5560 }
5561
5562 pub fn set_focus_handle(&mut self, focus_handle: &FocusHandle, _: &App) {
5567 self.core.invalidator.debug_assert_prepaint();
5568 if focus_handle.is_focused(self) {
5569 self.frame_state.next_frame.focus = Some(focus_handle.id);
5570 }
5571 self.frame_state
5572 .next_frame
5573 .dispatch_tree
5574 .set_focus_id(focus_handle.id);
5575 }
5576
5577 pub fn set_view_id(&mut self, view_id: EntityId) {
5583 self.core.invalidator.debug_assert_prepaint();
5584 self.frame_state
5585 .next_frame
5586 .dispatch_tree
5587 .set_view_id(view_id);
5588 }
5589
5590 pub fn current_view(&self) -> EntityId {
5592 self.core.invalidator.debug_assert_paint_or_prepaint();
5593 self.frame_state
5594 .rendered_entity_stack
5595 .last()
5596 .copied()
5597 .unwrap()
5598 }
5599
5600 #[inline]
5601 pub(crate) fn with_rendered_view<R>(
5602 &mut self,
5603 id: EntityId,
5604 f: impl FnOnce(&mut Self) -> R,
5605 ) -> R {
5606 self.frame_state.rendered_entity_stack.push(id);
5607 let result = f(self);
5608 self.frame_state.rendered_entity_stack.pop();
5609 result
5610 }
5611
5612 pub fn with_image_cache<F, R>(&mut self, image_cache: Option<AnyImageCache>, f: F) -> R
5614 where
5615 F: FnOnce(&mut Self) -> R,
5616 {
5617 if let Some(image_cache) = image_cache {
5618 self.frame_state.image_cache_stack.push(image_cache);
5619 let result = f(self);
5620 self.frame_state.image_cache_stack.pop();
5621 result
5622 } else {
5623 f(self)
5624 }
5625 }
5626
5627 pub fn handle_input(
5636 &mut self,
5637 focus_handle: &FocusHandle,
5638 input_handler: impl InputHandler,
5639 cx: &App,
5640 ) {
5641 self.core.invalidator.debug_assert_paint();
5642
5643 if focus_handle.is_focused(self) {
5644 let cx = self.to_async(cx);
5645 self.frame_state
5646 .next_frame
5647 .input_handlers
5648 .push(Some(new_platform_input_handler(
5649 cx,
5650 Box::new(input_handler),
5651 )));
5652 }
5653 }
5654
5655 fn apply_text_input_configuration(&mut self, cx: &mut App) {
5660 let configuration = match self.core.platform_window.take_input_handler() {
5661 Some(mut input_handler) => {
5662 let configuration = input_handler.text_input_configuration(self, cx);
5663 self.core.platform_window.set_input_handler(input_handler);
5664 configuration
5665 }
5666 None => TextInputConfiguration::default(),
5667 };
5668 if self.core.last_text_input_configuration.as_ref() != Some(&configuration) {
5669 self.core
5670 .platform_window
5671 .set_text_input_configuration(configuration.clone());
5672 self.core.last_text_input_configuration = Some(configuration);
5673 }
5674 }
5675
5676 pub fn on_mouse_event<Event: MouseEvent>(
5682 &mut self,
5683 mut listener: impl FnMut(&Event, DispatchPhase, &mut Window, &mut App) + 'static,
5684 ) {
5685 self.core.invalidator.debug_assert_paint();
5686
5687 self.frame_state
5688 .next_frame
5689 .mouse_listeners
5690 .push(Some(Box::new(
5691 move |event: &dyn Any, phase: DispatchPhase, window: &mut Window, cx: &mut App| {
5692 if let Some(event) = event.downcast_ref() {
5693 listener(event, phase, window, cx)
5694 }
5695 },
5696 )));
5697 }
5698
5699 pub fn on_key_event<Event: KeyEvent>(
5708 &mut self,
5709 listener: impl Fn(&Event, DispatchPhase, &mut Window, &mut App) + 'static,
5710 ) {
5711 self.core.invalidator.debug_assert_paint();
5712
5713 self.frame_state
5714 .next_frame
5715 .dispatch_tree
5716 .on_key_event(Rc::new(
5717 move |event: &dyn Any, phase, window: &mut Window, cx: &mut App| {
5718 if let Some(event) = event.downcast_ref::<Event>() {
5719 listener(event, phase, window, cx)
5720 }
5721 },
5722 ));
5723 }
5724
5725 pub fn on_modifiers_changed(
5732 &mut self,
5733 listener: impl Fn(&ModifiersChangedEvent, &mut Window, &mut App) + 'static,
5734 ) {
5735 self.core.invalidator.debug_assert_paint();
5736
5737 self.frame_state
5738 .next_frame
5739 .dispatch_tree
5740 .on_modifiers_changed(Rc::new(
5741 move |event: &ModifiersChangedEvent, window: &mut Window, cx: &mut App| {
5742 listener(event, window, cx)
5743 },
5744 ));
5745 }
5746
5747 pub fn on_focus_in(
5751 &mut self,
5752 handle: &FocusHandle,
5753 cx: &mut App,
5754 mut listener: impl FnMut(&mut Window, &mut App) + 'static,
5755 ) -> Subscription {
5756 let focus_id = handle.id;
5757 let (subscription, activate) =
5758 self.new_focus_listener(Box::new(move |event, window, cx| {
5759 if event.is_focus_in(focus_id) {
5760 listener(window, cx);
5761 }
5762 true
5763 }));
5764 cx.defer(move |_| activate());
5765 subscription
5766 }
5767
5768 pub fn on_focus_out(
5771 &mut self,
5772 handle: &FocusHandle,
5773 cx: &mut App,
5774 mut listener: impl FnMut(FocusOutEvent, &mut Window, &mut App) + 'static,
5775 ) -> Subscription {
5776 let focus_id = handle.id;
5777 let (subscription, activate) =
5778 self.new_focus_listener(Box::new(move |event, window, cx| {
5779 if let Some(blurred_id) = event.previous_focus_path.last().copied()
5780 && event.is_focus_out(focus_id)
5781 {
5782 let event = FocusOutEvent {
5783 blurred: WeakFocusHandle {
5784 id: blurred_id,
5785 handles: Arc::downgrade(&cx.focus_handles),
5786 },
5787 };
5788 listener(event, window, cx)
5789 }
5790 true
5791 }));
5792 cx.defer(move |_| activate());
5793 subscription
5794 }
5795
5796 fn reset_cursor_style(&self, cx: &mut App) {
5797 if self.is_window_hovered() {
5799 let style = self
5800 .frame_state
5801 .rendered_frame
5802 .cursor_style(self)
5803 .unwrap_or(CursorStyle::Arrow);
5804 cx.platform.set_cursor_style(style);
5805 }
5806 }
5807
5808 pub fn dispatch_keystroke(&mut self, keystroke: Keystroke, cx: &mut App) -> bool {
5811 let keystroke = keystroke.with_simulated_ime();
5812 let result = self.dispatch_event(
5813 PlatformInput::KeyDown(KeyDownEvent {
5814 keystroke: keystroke.clone(),
5815 is_held: false,
5816 prefer_character_input: false,
5817 }),
5818 cx,
5819 );
5820 if !result.propagate {
5821 return true;
5822 }
5823
5824 if let Some(input) = keystroke.key_char
5825 && let Some(mut input_handler) = self.core.platform_window.take_input_handler()
5826 {
5827 input_handler.dispatch_input(&input, self, cx);
5828 self.core.platform_window.set_input_handler(input_handler);
5829 return true;
5830 }
5831
5832 false
5833 }
5834
5835 pub fn keystroke_text_for(&self, action: &dyn Action) -> String {
5838 self.highest_precedence_binding_for_action(action)
5839 .map(|binding| {
5840 binding
5841 .keystrokes()
5842 .iter()
5843 .map(ToString::to_string)
5844 .collect::<Vec<_>>()
5845 .join(" ")
5846 })
5847 .unwrap_or_else(|| action.name().to_string())
5848 }
5849
5850 #[profiling::function]
5852 pub fn dispatch_event(&mut self, event: PlatformInput, cx: &mut App) -> DispatchEventResult {
5853 #[cfg(feature = "profiler")]
5854 self.core.window_profiler.begin_input(event.kind_name());
5855 let update_count_before = self.core.invalidator.update_count();
5856 let old_modality = self.core.last_input_modality;
5860 self.core.last_input_modality = match &event {
5861 PlatformInput::KeyDown(_) => InputModality::Keyboard,
5862 PlatformInput::MouseMove(_) | PlatformInput::MouseDown(_) => InputModality::Mouse,
5863 PlatformInput::Touch(_) => InputModality::Touch,
5864 _ => self.core.last_input_modality,
5865 };
5866 if self.core.last_input_modality != old_modality {
5867 self.refresh();
5868 }
5869
5870 cx.propagate_event = true;
5872 self.core.default_prevented = false;
5874
5875 let event = match event {
5876 PlatformInput::MouseMove(mouse_move) => {
5879 self.core.mouse_position = mouse_move.position;
5880 self.core.modifiers = mouse_move.modifiers;
5881 PlatformInput::MouseMove(mouse_move)
5882 }
5883 PlatformInput::MouseDown(mouse_down) => {
5884 self.core.mouse_position = mouse_down.position;
5885 self.core.modifiers = mouse_down.modifiers;
5886 PlatformInput::MouseDown(mouse_down)
5887 }
5888 PlatformInput::MouseUp(mouse_up) => {
5889 self.core.mouse_position = mouse_up.position;
5890 self.core.modifiers = mouse_up.modifiers;
5891 PlatformInput::MouseUp(mouse_up)
5892 }
5893 PlatformInput::MousePressure(mouse_pressure) => {
5894 PlatformInput::MousePressure(mouse_pressure)
5895 }
5896 PlatformInput::MouseExited(mouse_exited) => {
5897 self.core.modifiers = mouse_exited.modifiers;
5898 PlatformInput::MouseExited(mouse_exited)
5899 }
5900 PlatformInput::ModifiersChanged(modifiers_changed) => {
5901 self.core.modifiers = modifiers_changed.modifiers;
5902 self.core.capslock = modifiers_changed.capslock;
5903 PlatformInput::ModifiersChanged(modifiers_changed)
5904 }
5905 PlatformInput::ScrollWheel(scroll_wheel) => {
5906 self.core.mouse_position = scroll_wheel.position;
5907 self.core.modifiers = scroll_wheel.modifiers;
5908 PlatformInput::ScrollWheel(scroll_wheel)
5909 }
5910 PlatformInput::Pinch(pinch) => {
5911 self.core.mouse_position = pinch.position;
5912 self.core.modifiers = pinch.modifiers;
5913 PlatformInput::Pinch(pinch)
5914 }
5915 PlatformInput::FileDrop(file_drop) => match file_drop {
5918 FileDropEvent::Entered { position, paths } => {
5919 self.core.mouse_position = position;
5920 let source_window = self.core.handle.window_id();
5921 if !cx.restore_platform_drag(source_window) && cx.active_drag.is_none() {
5922 cx.active_drag = Some(AnyDrag {
5923 value: Arc::new(paths.clone()),
5924 view: cx.new(|_| paths).into(),
5925 cursor_offset: position,
5926 cursor_style: None,
5927 external_payload_source: None,
5928 });
5929 }
5930 PlatformInput::MouseMove(MouseMoveEvent {
5931 position,
5932 pressed_button: Some(MouseButton::Left),
5933 modifiers: Modifiers::default(),
5934 })
5935 }
5936 FileDropEvent::Pending { position } => {
5937 self.core.mouse_position = position;
5938 PlatformInput::MouseMove(MouseMoveEvent {
5939 position,
5940 pressed_button: Some(MouseButton::Left),
5941 modifiers: Modifiers::default(),
5942 })
5943 }
5944 FileDropEvent::Submit { position } => {
5945 cx.activate(true);
5946 self.core.mouse_position = position;
5947 PlatformInput::MouseUp(MouseUpEvent {
5948 button: MouseButton::Left,
5949 position,
5950 modifiers: Modifiers::default(),
5951 click_count: 1,
5952 })
5953 }
5954 FileDropEvent::Exited => {
5955 if !cx.hand_restored_drag_to_platform(self.core.handle.window_id()) {
5956 cx.active_drag.take();
5957 }
5958 self.refresh();
5959 PlatformInput::FileDrop(FileDropEvent::Exited)
5960 }
5961 FileDropEvent::Ended => {
5962 cx.end_platform_drag(self.core.handle.window_id());
5963 self.refresh();
5964 PlatformInput::FileDrop(FileDropEvent::Ended)
5965 }
5966 },
5967 PlatformInput::Touch(touch) => PlatformInput::Touch(touch),
5968 PlatformInput::LongPress(long_press) => {
5969 self.core.mouse_position = if long_press.phase == crate::TouchPhase::Started {
5970 long_press.start_position
5971 } else {
5972 long_press.position
5973 };
5974 if long_press.phase == crate::TouchPhase::Started {
5975 self.core.long_press_capture = None;
5976 }
5977 PlatformInput::LongPress(long_press)
5978 }
5979 PlatformInput::TouchDrag(touch_drag) => {
5980 self.core.mouse_position = touch_drag.start_position;
5981 PlatformInput::TouchDrag(touch_drag)
5982 }
5983 PlatformInput::KeyDown(_) | PlatformInput::KeyUp(_) => event,
5984 };
5985
5986 if let Some(any_mouse_event) = event.mouse_event() {
5987 self.dispatch_mouse_event(any_mouse_event, cx);
5988 } else if let Some(any_key_event) = event.keyboard_event() {
5989 self.dispatch_key_event(any_key_event, cx);
5990 } else if let Some(touch_event) = event.touch_event() {
5991 self.dispatch_touch_event(touch_event, cx);
5992 }
5993 if let PlatformInput::LongPress(long_press) = &event {
5994 match long_press.phase {
5995 crate::TouchPhase::Started if !self.core.default_prevented => {
5996 self.core.long_press_capture = None;
5997 }
5998 crate::TouchPhase::Ended | crate::TouchPhase::Cancelled => {
5999 self.core.long_press_capture = None;
6000 }
6001 crate::TouchPhase::Started | crate::TouchPhase::Moved => {}
6002 }
6003 }
6004
6005 self.promote_external_drag_to_platform(&event, cx);
6008
6009 let caused_invalidation = self.core.invalidator.update_count() > update_count_before;
6010 if caused_invalidation {
6011 self.core.input_rate_tracker.borrow_mut().record_input();
6012 }
6013 #[cfg(feature = "profiler")]
6014 self.core.window_profiler.end_input(caused_invalidation);
6015
6016 DispatchEventResult {
6017 propagate: cx.propagate_event,
6018 default_prevented: self.core.default_prevented,
6019 }
6020 }
6021
6022 fn promote_external_drag_to_platform(&mut self, event: &PlatformInput, cx: &mut App) {
6023 let PlatformInput::MouseMove(mouse_move) = event else {
6024 return;
6025 };
6026 if mouse_move.pressed_button != Some(MouseButton::Left) {
6027 return;
6028 }
6029 if Bounds::new(Point::default(), self.core.viewport_size).contains(&mouse_move.position) {
6030 return;
6031 }
6032 if !self.core.platform_window.can_start_external_drag() {
6033 return;
6034 }
6035 let Some(payload_source) = cx
6036 .active_drag
6037 .as_mut()
6038 .and_then(|drag| drag.external_payload_source.take())
6039 else {
6040 return;
6041 };
6042 let Some(payload) = payload_source(self, cx) else {
6043 return;
6044 };
6045 if self.core.platform_window.start_external_drag(&payload)
6046 && cx.hand_active_drag_to_platform(self.core.handle.window_id())
6047 {
6048 self.refresh();
6049 }
6050 }
6051
6052 pub fn touch_prediction_enabled(&self) -> bool {
6056 self.core.touch_prediction_enabled
6057 }
6058
6059 pub fn set_touch_prediction_enabled(&mut self, enabled: bool) {
6063 self.core.touch_prediction_enabled = enabled;
6064 }
6065
6066 fn dispatch_touch_event(&mut self, event: &TouchEvent, cx: &mut App) {
6070 let mut event = event.clone();
6071 if !self.core.touch_prediction_enabled {
6072 event.predicted_position = None;
6073 }
6074 let recognized_gestures = self.core.touch_gestures.handle_event(&event);
6075 if event.phase == crate::TouchPhase::Started
6076 && let Some(touch_drag) = self.core.touch_gestures.offer_touch_drag(event.id)
6077 {
6078 self.dispatch_recognized_touch_gesture(touch_drag, cx);
6079 }
6080 if event.phase == crate::TouchPhase::Started
6081 && self.core.touch_gestures.pending_long_press().is_some()
6082 {
6083 self.core.long_press_capture = None;
6084 }
6085 let mut tapped = false;
6086 for gesture in recognized_gestures {
6087 tapped |= matches!(gesture, RecognizedTouchGesture::Tap { .. });
6088 self.dispatch_recognized_touch_gesture(gesture, cx);
6089 }
6090 if event.phase == crate::TouchPhase::Started {
6091 self.schedule_long_press_timer(cx);
6092 } else if self.core.touch_gestures.pending_long_press().is_none() {
6093 self.core.long_press_timer.take();
6094 }
6095 if tapped && self.core.invalidator.is_dirty() {
6101 self.draw(cx).clear(cx);
6102 }
6103 if self.core.touch_gestures.has_momentum() {
6104 self.schedule_touch_momentum_tick();
6105 }
6106 }
6107
6108 fn dispatch_recognized_touch_gesture(&mut self, gesture: RecognizedTouchGesture, cx: &mut App) {
6109 match gesture {
6110 RecognizedTouchGesture::Scroll(scroll_wheel) => {
6111 self.core.mouse_position = scroll_wheel.position;
6112 cx.propagate_event = true;
6113 self.dispatch_mouse_event(&scroll_wheel, cx);
6114 }
6115 RecognizedTouchGesture::Tap { down, up } => {
6116 self.core.mouse_position = up.position;
6117 cx.propagate_event = true;
6118 self.dispatch_mouse_event(&down, cx);
6119 cx.propagate_event = true;
6120 self.dispatch_mouse_event(&up, cx);
6121 }
6122 RecognizedTouchGesture::TouchDrag(touch_drag) => {
6123 self.core.mouse_position = touch_drag.start_position;
6124 cx.propagate_event = true;
6125 self.core.default_prevented = false;
6126 let started = touch_drag.phase == crate::TouchPhase::Started;
6127 self.dispatch_mouse_event(&touch_drag, cx);
6128 if started {
6129 self.core
6130 .touch_gestures
6131 .resolve_touch_drag(self.core.default_prevented);
6132 }
6133 }
6134 RecognizedTouchGesture::LongPress(long_press) => {
6135 self.core.mouse_position = if long_press.phase == crate::TouchPhase::Started {
6136 long_press.start_position
6137 } else {
6138 long_press.position
6139 };
6140 cx.propagate_event = true;
6141 self.core.default_prevented = false;
6142 let started = long_press.phase == crate::TouchPhase::Started;
6143 let ended = matches!(
6144 long_press.phase,
6145 crate::TouchPhase::Ended | crate::TouchPhase::Cancelled
6146 );
6147 self.dispatch_mouse_event(&long_press, cx);
6148 if started {
6149 let claimed = self.core.default_prevented;
6150 self.core.touch_gestures.resolve_long_press(claimed);
6151 if !claimed {
6152 self.core.long_press_capture = None;
6153 }
6154 }
6155 if ended {
6156 self.core.long_press_capture = None;
6157 }
6158 }
6159 }
6160 }
6161
6162 fn schedule_long_press_timer(&mut self, cx: &mut App) {
6163 self.core.long_press_timer.take();
6164 let Some((touch_id, duration)) = self.core.touch_gestures.pending_long_press() else {
6165 return;
6166 };
6167 self.core.long_press_timer = Some(self.spawn(cx, async move |cx| {
6168 cx.background_executor.timer(duration).await;
6169 cx.update(move |window, cx| {
6170 window.core.long_press_timer.take();
6171 if let Some(gesture) = window.core.touch_gestures.offer_long_press(touch_id) {
6172 window.dispatch_recognized_touch_gesture(gesture, cx);
6173 }
6174 })
6175 .log_err();
6176 }));
6177 }
6178
6179 fn schedule_touch_momentum_tick(&mut self) {
6180 self.on_next_frame(|window, cx| {
6181 if let Some(gesture) = window.core.touch_gestures.tick_momentum() {
6182 window.dispatch_recognized_touch_gesture(gesture, cx);
6183 }
6184 if window.core.touch_gestures.has_momentum() {
6185 window.schedule_touch_momentum_tick();
6186 }
6187 });
6188 }
6189
6190 fn dispatch_mouse_event(&mut self, event: &dyn Any, cx: &mut App) {
6191 let hit_test = self
6192 .frame_state
6193 .rendered_frame
6194 .hit_test(self.mouse_position());
6195 if hit_test != self.core.mouse_hit_test {
6196 self.core.mouse_hit_test = hit_test;
6197 self.reset_cursor_style(cx);
6198 }
6199
6200 #[cfg(any(feature = "inspector", debug_assertions))]
6201 if self.is_inspector_picking(cx) {
6202 self.handle_inspector_mouse_event(event, cx);
6203 return;
6205 }
6206
6207 let mut mouse_listeners = mem::take(&mut self.frame_state.rendered_frame.mouse_listeners);
6208
6209 for listener in &mut mouse_listeners {
6212 let listener = listener.as_mut().unwrap();
6213 listener(event, DispatchPhase::Capture, self, cx);
6214 if !cx.propagate_event {
6215 break;
6216 }
6217 }
6218
6219 if cx.propagate_event {
6221 for listener in mouse_listeners.iter_mut().rev() {
6222 let listener = listener.as_mut().unwrap();
6223 listener(event, DispatchPhase::Bubble, self, cx);
6224 if !cx.propagate_event {
6225 break;
6226 }
6227 }
6228 }
6229
6230 self.frame_state.rendered_frame.mouse_listeners = mouse_listeners;
6231
6232 if cx.has_active_drag() {
6233 if event.is::<MouseMoveEvent>() {
6234 self.refresh();
6237 } else if event.is::<MouseUpEvent>() {
6238 cx.active_drag = None;
6241 self.refresh();
6242 }
6243 }
6244
6245 if event.is::<MouseUpEvent>() && self.core.captured_hitbox.is_some() {
6247 self.core.captured_hitbox = None;
6248 }
6249 }
6250
6251 fn dispatch_key_event(&mut self, event: &dyn Any, cx: &mut App) {
6252 if self.core.invalidator.is_dirty() {
6253 self.draw(cx).clear(cx);
6254 }
6255
6256 let node_id = self.focus_node_id_in_rendered_frame(self.core.focus);
6257 let dispatch_path = self
6258 .frame_state
6259 .rendered_frame
6260 .dispatch_tree
6261 .dispatch_path(node_id);
6262
6263 let mut keystroke: Option<Keystroke> = None;
6264
6265 if let Some(event) = event.downcast_ref::<ModifiersChangedEvent>() {
6266 if event.modifiers.number_of_modifiers() == 0
6267 && self.core.pending_modifier.modifiers.number_of_modifiers() == 1
6268 && !self.core.pending_modifier.saw_other_input
6269 {
6270 let key = match self.core.pending_modifier.modifiers {
6271 modifiers if modifiers.shift => Some("shift"),
6272 modifiers if modifiers.control => Some("control"),
6273 modifiers if modifiers.alt => Some("alt"),
6274 modifiers if modifiers.platform => Some("platform"),
6275 modifiers if modifiers.function => Some("function"),
6276 _ => None,
6277 };
6278 if let Some(key) = key {
6279 keystroke = Some(Keystroke {
6280 key: key.to_string(),
6281 key_char: None,
6282 modifiers: Modifiers::default(),
6283 });
6284 }
6285 }
6286
6287 if self.core.pending_modifier.modifiers.number_of_modifiers() == 0
6288 && event.modifiers.number_of_modifiers() == 1
6289 {
6290 self.core.pending_modifier.saw_other_input = false
6291 } else if event.modifiers.number_of_modifiers() > 1 {
6292 self.core.pending_modifier.saw_other_input = true
6293 }
6294 self.core.pending_modifier.modifiers = event.modifiers
6295 } else if let Some(key_down_event) = event.downcast_ref::<KeyDownEvent>() {
6296 self.core.pending_modifier.saw_other_input = true;
6297 keystroke = Some(key_down_event.keystroke.clone());
6298 if key_down_event.keystroke.key_char.is_some()
6299 && matches!(
6300 cx.cursor_hide_mode,
6301 CursorHideMode::OnTyping | CursorHideMode::OnTypingAndAction
6302 )
6303 {
6304 cx.platform.hide_cursor_until_mouse_moves();
6305 }
6306 }
6307
6308 let Some(keystroke) = keystroke else {
6309 self.finish_dispatch_key_event(event, dispatch_path, self.context_stack(), cx);
6310 return;
6311 };
6312
6313 cx.propagate_event = true;
6314 self.dispatch_keystroke_interceptors(event, self.context_stack(), cx);
6315 if !cx.propagate_event {
6316 self.finish_dispatch_key_event(event, dispatch_path, self.context_stack(), cx);
6317 return;
6318 }
6319
6320 let mut currently_pending = self.core.pending_input.take().unwrap_or_default();
6321 if currently_pending.focus.is_some() && currently_pending.focus != self.core.focus {
6322 currently_pending = PendingInput::default();
6323 }
6324
6325 let match_result = self.frame_state.rendered_frame.dispatch_tree.dispatch_key(
6326 currently_pending.keystrokes,
6327 keystroke,
6328 &dispatch_path,
6329 );
6330
6331 if !match_result.to_replay.is_empty() {
6332 self.replay_pending_input(match_result.to_replay, cx);
6333 cx.propagate_event = true;
6334 }
6335
6336 if !match_result.pending.is_empty() {
6337 let previous_timeout = currently_pending.timeout.take();
6338 currently_pending.keystrokes = match_result.pending;
6339 currently_pending.focus = self.core.focus;
6340
6341 let text_input_requires_timeout = event
6342 .downcast_ref::<KeyDownEvent>()
6343 .filter(|key_down| key_down.keystroke.key_char.is_some())
6344 .and_then(|_| self.core.platform_window.take_input_handler())
6345 .map_or(false, |mut input_handler| {
6346 let accepts = input_handler.accepts_text_input(self, cx);
6347 self.core.platform_window.set_input_handler(input_handler);
6348 accepts
6349 });
6350
6351 let needs_timeout = previous_timeout.is_some()
6352 || match_result.pending_has_binding
6353 || text_input_requires_timeout;
6354 currently_pending.timeout = if needs_timeout {
6355 match previous_timeout {
6356 Some(mut timeout) if timeout.is_paused() => {
6357 timeout.reset_duration(PENDING_INPUT_TIMEOUT);
6358 Some(timeout)
6359 }
6360 previous_timeout => {
6361 drop(previous_timeout);
6362 Some(self.new_pending_input_timeout(PENDING_INPUT_TIMEOUT, cx))
6363 }
6364 }
6365 } else {
6366 None
6367 };
6368 self.core.pending_input = Some(currently_pending);
6369 self.pending_input_changed(cx);
6370 cx.propagate_event = false;
6371 return;
6372 }
6373
6374 let skip_bindings = event
6375 .downcast_ref::<KeyDownEvent>()
6376 .filter(|key_down_event| key_down_event.prefer_character_input)
6377 .map(|_| {
6378 self.core
6379 .platform_window
6380 .take_input_handler()
6381 .map_or(false, |mut input_handler| {
6382 let accepts = input_handler.accepts_text_input(self, cx);
6383 self.core.platform_window.set_input_handler(input_handler);
6384 accepts
6387 })
6388 })
6389 .unwrap_or(false);
6390
6391 if !skip_bindings {
6392 for binding in match_result.bindings {
6393 self.dispatch_action_on_node(node_id, binding.action.as_ref(), cx);
6394 if !cx.propagate_event {
6395 self.dispatch_keystroke_observers(
6396 event,
6397 Some(binding.action),
6398 match_result.context_stack,
6399 cx,
6400 );
6401 self.pending_input_changed(cx);
6402 return;
6403 }
6404 }
6405 }
6406
6407 self.finish_dispatch_key_event(event, dispatch_path, match_result.context_stack, cx);
6408 self.pending_input_changed(cx);
6409 }
6410
6411 fn new_pending_input_timeout(&self, duration: Duration, cx: &App) -> PendingInputTimeout {
6412 let (started_at, task) = self.start_pending_input_timeout(duration, cx);
6413 PendingInputTimeout {
6414 duration,
6415 remaining: duration,
6416 state: PendingInputTimeoutState::Running { started_at, task },
6417 }
6418 }
6419
6420 fn start_pending_input_timeout(&self, remaining: Duration, cx: &App) -> (Instant, Task<()>) {
6421 let started_at = cx.background_executor().now();
6422 let task = self.spawn(cx, async move |cx| {
6423 cx.background_executor.timer(remaining).await;
6424 cx.update(move |window, cx| {
6425 let Some(currently_pending) = window
6426 .core
6427 .pending_input
6428 .take()
6429 .filter(|pending| pending.focus == window.core.focus)
6430 else {
6431 return;
6432 };
6433
6434 let node_id = window.focus_node_id_in_rendered_frame(window.core.focus);
6435 let dispatch_path = window
6436 .frame_state
6437 .rendered_frame
6438 .dispatch_tree
6439 .dispatch_path(node_id);
6440
6441 let to_replay = window
6442 .frame_state
6443 .rendered_frame
6444 .dispatch_tree
6445 .flush_dispatch(currently_pending.keystrokes, &dispatch_path);
6446
6447 window.pending_input_changed(cx);
6448 window.replay_pending_input(to_replay, cx)
6449 })
6450 .log_err();
6451 });
6452 (started_at, task)
6453 }
6454
6455 fn finish_dispatch_key_event(
6456 &mut self,
6457 event: &dyn Any,
6458 dispatch_path: SmallVec<[DispatchNodeId; 32]>,
6459 context_stack: Vec<KeyContext>,
6460 cx: &mut App,
6461 ) {
6462 self.dispatch_key_down_up_event(event, &dispatch_path, cx);
6463 if !cx.propagate_event {
6464 return;
6465 }
6466
6467 self.dispatch_modifiers_changed_event(event, &dispatch_path, cx);
6468 if !cx.propagate_event {
6469 return;
6470 }
6471
6472 self.dispatch_keystroke_observers(event, None, context_stack, cx);
6473 }
6474
6475 pub(crate) fn pending_input_changed(&mut self, cx: &mut App) {
6476 self.core
6477 .pending_input_observers
6478 .clone()
6479 .retain(&(), |callback| callback(self, cx));
6480 }
6481
6482 fn defer_pending_input_changed(&self, cx: &mut App) {
6483 let window_handle = self.core.handle;
6486 cx.defer(move |cx| {
6487 window_handle
6488 .update(cx, |_, window, cx| {
6489 window.pending_input_changed(cx);
6490 })
6491 .ok();
6492 });
6493 }
6494
6495 fn dispatch_key_down_up_event(
6496 &mut self,
6497 event: &dyn Any,
6498 dispatch_path: &SmallVec<[DispatchNodeId; 32]>,
6499 cx: &mut App,
6500 ) {
6501 for node_id in dispatch_path {
6503 let node = self.frame_state.rendered_frame.dispatch_tree.node(*node_id);
6504
6505 for key_listener in node.key_listeners.clone() {
6506 key_listener(event, DispatchPhase::Capture, self, cx);
6507 if !cx.propagate_event {
6508 return;
6509 }
6510 }
6511 }
6512
6513 for node_id in dispatch_path.iter().rev() {
6515 let node = self.frame_state.rendered_frame.dispatch_tree.node(*node_id);
6517 for key_listener in node.key_listeners.clone() {
6518 key_listener(event, DispatchPhase::Bubble, self, cx);
6519 if !cx.propagate_event {
6520 return;
6521 }
6522 }
6523 }
6524 }
6525
6526 fn dispatch_modifiers_changed_event(
6527 &mut self,
6528 event: &dyn Any,
6529 dispatch_path: &SmallVec<[DispatchNodeId; 32]>,
6530 cx: &mut App,
6531 ) {
6532 let Some(event) = event.downcast_ref::<ModifiersChangedEvent>() else {
6533 return;
6534 };
6535 for node_id in dispatch_path.iter().rev() {
6536 let node = self.frame_state.rendered_frame.dispatch_tree.node(*node_id);
6537 for listener in node.modifiers_changed_listeners.clone() {
6538 listener(event, self, cx);
6539 if !cx.propagate_event {
6540 return;
6541 }
6542 }
6543 }
6544 }
6545
6546 pub fn has_pending_keystrokes(&self) -> bool {
6548 self.pending_input().is_some()
6549 }
6550
6551 #[cfg(test)]
6552 pub(crate) fn pending_input_is_none(&self) -> bool {
6553 self.core.pending_input.is_none()
6554 }
6555
6556 pub(crate) fn clear_pending_keystrokes(&mut self, cx: &mut App) {
6557 if self.core.pending_input.take().is_some() {
6558 self.defer_pending_input_changed(cx);
6559 }
6560 }
6561
6562 pub fn pending_input(&self) -> Option<PendingInputStatus<'_>> {
6565 self.core
6566 .pending_input
6567 .as_ref()
6568 .filter(|pending_input| pending_input.focus == self.core.focus)
6569 .map(|pending_input| PendingInputStatus {
6570 keystrokes: pending_input.keystrokes.as_slice(),
6571 timeout: pending_input
6572 .timeout
6573 .as_ref()
6574 .map(PendingInputTimeout::status),
6575 })
6576 }
6577
6578 pub fn set_pending_input_timeout_paused<T: 'static>(
6583 &mut self,
6584 owner: &Entity<T>,
6585 paused: bool,
6586 cx: &mut App,
6587 ) -> bool {
6588 let owner_id = owner.entity_id();
6589 if !paused {
6590 return self.resume_pending_input_timeout(owner_id, cx);
6591 }
6592
6593 let timeout = self
6594 .core
6595 .pending_input
6596 .as_ref()
6597 .filter(|pending_input| pending_input.focus == self.core.focus)
6598 .and_then(|pending_input| pending_input.timeout.as_ref());
6599 let Some(timeout) = timeout else {
6600 return false;
6601 };
6602 if timeout.is_paused() {
6603 return false;
6604 }
6605
6606 let release_subscription = self.observe_release(owner, cx, move |_, window, cx| {
6607 window.resume_pending_input_timeout(owner_id, cx);
6608 });
6609 let now = cx.background_executor().now();
6610 let changed = self
6611 .core
6612 .pending_input
6613 .as_mut()
6614 .filter(|pending_input| pending_input.focus == self.core.focus)
6615 .and_then(|pending_input| pending_input.timeout.as_mut())
6616 .is_some_and(|timeout| {
6617 timeout.pause(
6618 PendingInputTimeoutPause {
6619 owner_id,
6620 _release_subscription: release_subscription,
6621 },
6622 now,
6623 )
6624 });
6625
6626 if changed {
6627 self.defer_pending_input_changed(cx);
6628 }
6629 changed
6630 }
6631
6632 fn resume_pending_input_timeout(&mut self, owner_id: EntityId, cx: &mut App) -> bool {
6633 let Some(remaining) = self
6634 .core
6635 .pending_input
6636 .as_ref()
6637 .and_then(|pending_input| pending_input.timeout.as_ref())
6638 .filter(|timeout| timeout.pause_owner_id() == Some(owner_id))
6639 .map(|timeout| timeout.remaining)
6640 else {
6641 return false;
6642 };
6643
6644 let (started_at, task) = self.start_pending_input_timeout(remaining, cx);
6645 let changed = self
6646 .core
6647 .pending_input
6648 .as_mut()
6649 .and_then(|pending_input| pending_input.timeout.as_mut())
6650 .is_some_and(|timeout| timeout.resume(owner_id, started_at, task));
6651
6652 if changed {
6653 self.defer_pending_input_changed(cx);
6654 }
6655 changed
6656 }
6657
6658 pub fn pending_input_keystrokes(&self) -> Option<&[Keystroke]> {
6660 self.pending_input()
6661 .map(|pending_input| pending_input.keystrokes())
6662 }
6663
6664 fn replay_pending_input(&mut self, replays: SmallVec<[Replay; 1]>, cx: &mut App) {
6665 let node_id = self.focus_node_id_in_rendered_frame(self.core.focus);
6666 let dispatch_path = self
6667 .frame_state
6668 .rendered_frame
6669 .dispatch_tree
6670 .dispatch_path(node_id);
6671
6672 'replay: for replay in replays {
6673 let event = KeyDownEvent {
6674 keystroke: replay.keystroke.clone(),
6675 is_held: false,
6676 prefer_character_input: true,
6677 };
6678
6679 cx.propagate_event = true;
6680 for binding in replay.bindings {
6681 self.dispatch_action_on_node(node_id, binding.action.as_ref(), cx);
6682 if !cx.propagate_event {
6683 self.dispatch_keystroke_observers(
6684 &event,
6685 Some(binding.action),
6686 Vec::default(),
6687 cx,
6688 );
6689 continue 'replay;
6690 }
6691 }
6692
6693 self.dispatch_key_down_up_event(&event, &dispatch_path, cx);
6694 if !cx.propagate_event {
6695 continue 'replay;
6696 }
6697 if let Some(input) = replay.keystroke.key_char.as_ref().cloned()
6698 && let Some(mut input_handler) = self.core.platform_window.take_input_handler()
6699 {
6700 input_handler.dispatch_input(&input, self, cx);
6701 self.core.platform_window.set_input_handler(input_handler)
6702 }
6703 }
6704 }
6705
6706 fn focus_node_id_in_rendered_frame(&self, focus_id: Option<FocusId>) -> DispatchNodeId {
6707 focus_id
6708 .and_then(|focus_id| {
6709 self.frame_state
6710 .rendered_frame
6711 .dispatch_tree
6712 .focusable_node_id(focus_id)
6713 })
6714 .unwrap_or_else(|| self.frame_state.rendered_frame.dispatch_tree.root_node_id())
6715 }
6716
6717 fn dispatch_action_on_node(
6718 &mut self,
6719 node_id: DispatchNodeId,
6720 action: &dyn Action,
6721 cx: &mut App,
6722 ) {
6723 self.dispatch_action_on_node_inner(node_id, action, cx);
6724
6725 if !cx.propagate_event
6726 && cx.cursor_hide_mode == CursorHideMode::OnTypingAndAction
6727 && self.last_input_was_keyboard()
6728 {
6729 cx.platform.hide_cursor_until_mouse_moves();
6730 }
6731 }
6732
6733 fn dispatch_action_on_node_inner(
6734 &mut self,
6735 node_id: DispatchNodeId,
6736 action: &dyn Action,
6737 cx: &mut App,
6738 ) {
6739 let dispatch_path = self
6740 .frame_state
6741 .rendered_frame
6742 .dispatch_tree
6743 .dispatch_path(node_id);
6744
6745 cx.propagate_event = true;
6747 if let Some(mut global_listeners) = cx
6748 .global_action_listeners
6749 .remove(&action.as_any().type_id())
6750 {
6751 for listener in &global_listeners {
6752 #[cfg(feature = "profiler")]
6753 self.core.window_profiler.begin_action_handler(action, cx);
6754 listener(action.as_any(), DispatchPhase::Capture, cx);
6755 #[cfg(feature = "profiler")]
6756 self.core.window_profiler.end_action_handler();
6757 if !cx.propagate_event {
6758 break;
6759 }
6760 }
6761
6762 global_listeners.extend(
6763 cx.global_action_listeners
6764 .remove(&action.as_any().type_id())
6765 .unwrap_or_default(),
6766 );
6767
6768 cx.global_action_listeners
6769 .insert(action.as_any().type_id(), global_listeners);
6770 }
6771
6772 if !cx.propagate_event {
6773 return;
6774 }
6775
6776 for node_id in &dispatch_path {
6778 let node = self.frame_state.rendered_frame.dispatch_tree.node(*node_id);
6779 for DispatchActionListener {
6780 action_type,
6781 listener,
6782 } in node.action_listeners.clone()
6783 {
6784 let any_action = action.as_any();
6785 if action_type == any_action.type_id() {
6786 #[cfg(feature = "profiler")]
6787 self.core.window_profiler.begin_action_handler(action, cx);
6788 listener(any_action, DispatchPhase::Capture, self, cx);
6789 #[cfg(feature = "profiler")]
6790 self.core.window_profiler.end_action_handler();
6791
6792 if !cx.propagate_event {
6793 return;
6794 }
6795 }
6796 }
6797 }
6798
6799 for node_id in dispatch_path.iter().rev() {
6801 let node = self.frame_state.rendered_frame.dispatch_tree.node(*node_id);
6802 for DispatchActionListener {
6803 action_type,
6804 listener,
6805 } in node.action_listeners.clone()
6806 {
6807 let any_action = action.as_any();
6808 if action_type == any_action.type_id() {
6809 cx.propagate_event = false; #[cfg(feature = "profiler")]
6811 self.core.window_profiler.begin_action_handler(action, cx);
6812 listener(any_action, DispatchPhase::Bubble, self, cx);
6813 #[cfg(feature = "profiler")]
6814 self.core.window_profiler.end_action_handler();
6815
6816 if !cx.propagate_event {
6817 return;
6818 }
6819 }
6820 }
6821 }
6822
6823 if let Some(mut global_listeners) = cx
6825 .global_action_listeners
6826 .remove(&action.as_any().type_id())
6827 {
6828 for listener in global_listeners.iter().rev() {
6829 cx.propagate_event = false; #[cfg(feature = "profiler")]
6832 self.core.window_profiler.begin_action_handler(action, cx);
6833 listener(action.as_any(), DispatchPhase::Bubble, cx);
6834 #[cfg(feature = "profiler")]
6835 self.core.window_profiler.end_action_handler();
6836 if !cx.propagate_event {
6837 break;
6838 }
6839 }
6840
6841 global_listeners.extend(
6842 cx.global_action_listeners
6843 .remove(&action.as_any().type_id())
6844 .unwrap_or_default(),
6845 );
6846
6847 cx.global_action_listeners
6848 .insert(action.as_any().type_id(), global_listeners);
6849 }
6850 }
6851
6852 pub fn observe_global<G: Global>(
6855 &mut self,
6856 cx: &mut App,
6857 f: impl Fn(&mut Window, &mut App) + 'static,
6858 ) -> Subscription {
6859 let window_handle = self.core.handle;
6860 let (subscription, activate) = cx.global_observers.insert(
6861 TypeId::of::<G>(),
6862 Box::new(move |cx| {
6863 window_handle
6864 .update(cx, |_, window, cx| f(window, cx))
6865 .is_ok()
6866 }),
6867 );
6868 cx.defer(move |_| activate());
6869 subscription
6870 }
6871
6872 pub fn activate_window(&self) {
6874 self.core.platform_window.activate();
6875 }
6876
6877 pub fn request_attention(&self) {
6879 self.core.platform_window.request_attention();
6880 }
6881
6882 pub fn minimize_window(&self) {
6884 self.core.platform_window.minimize();
6885 }
6886
6887 pub fn toggle_fullscreen(&self) {
6889 self.core.platform_window.toggle_fullscreen();
6890 }
6891
6892 pub fn toggle_simple_fullscreen(&self) {
6897 self.core.platform_window.toggle_simple_fullscreen();
6898 }
6899
6900 pub fn invalidate_character_coordinates(&self) {
6902 self.on_next_frame(|window, cx| {
6903 if let Some(mut input_handler) = window.core.platform_window.take_input_handler() {
6904 if let Some(bounds) = input_handler.selected_bounds(window, cx) {
6905 window.core.platform_window.update_ime_position(bounds);
6906 }
6907 window.core.platform_window.set_input_handler(input_handler);
6908 }
6909 });
6910 }
6911
6912 pub fn prompt<T>(
6916 &mut self,
6917 level: PromptLevel,
6918 message: &str,
6919 detail: Option<&str>,
6920 answers: &[T],
6921 cx: &mut App,
6922 ) -> oneshot::Receiver<usize>
6923 where
6924 T: Clone + Into<PromptButton>,
6925 {
6926 let prompt_builder = cx.prompt_builder.take();
6927 let Some(prompt_builder) = prompt_builder else {
6928 unreachable!("Re-entrant window prompting is not supported by GPUI");
6929 };
6930
6931 let answers = answers
6932 .iter()
6933 .map(|answer| answer.clone().into())
6934 .collect::<Vec<_>>();
6935
6936 let receiver = match &prompt_builder {
6937 PromptBuilder::Default => self
6938 .core
6939 .platform_window
6940 .prompt(level, message, detail, &answers)
6941 .unwrap_or_else(|| {
6942 self.build_custom_prompt(&prompt_builder, level, message, detail, &answers, cx)
6943 }),
6944 PromptBuilder::Custom(_) => {
6945 self.build_custom_prompt(&prompt_builder, level, message, detail, &answers, cx)
6946 }
6947 };
6948
6949 cx.prompt_builder = Some(prompt_builder);
6950
6951 receiver
6952 }
6953
6954 fn build_custom_prompt(
6955 &mut self,
6956 prompt_builder: &PromptBuilder,
6957 level: PromptLevel,
6958 message: &str,
6959 detail: Option<&str>,
6960 answers: &[PromptButton],
6961 cx: &mut App,
6962 ) -> oneshot::Receiver<usize> {
6963 let (sender, receiver) = oneshot::channel();
6964 let handle = PromptHandle::new(sender);
6965 let handle = (prompt_builder)(level, message, detail, answers, handle, self, cx);
6966 self.core.prompt = Some(handle);
6967 receiver
6968 }
6969
6970 pub fn has_active_prompt(&self) -> bool {
6975 self.core.prompt.is_some()
6976 }
6977
6978 pub fn context_stack(&self) -> Vec<KeyContext> {
6980 let node_id = self.focus_node_id_in_rendered_frame(self.core.focus);
6981 let dispatch_tree = &self.frame_state.rendered_frame.dispatch_tree;
6982 dispatch_tree
6983 .dispatch_path(node_id)
6984 .iter()
6985 .filter_map(move |&node_id| dispatch_tree.node(node_id).context.clone())
6986 .collect()
6987 }
6988
6989 pub fn available_actions(&self, cx: &App) -> Vec<Box<dyn Action>> {
6991 let node_id = self.focus_node_id_in_rendered_frame(self.core.focus);
6992 let mut actions = self
6993 .frame_state
6994 .rendered_frame
6995 .dispatch_tree
6996 .available_actions(node_id);
6997 for action_type in cx.global_action_listeners.keys() {
6998 if let Err(ix) = actions.binary_search_by_key(action_type, |a| a.as_any().type_id()) {
6999 let action = cx.actions.build_action_type(action_type).ok();
7000 if let Some(action) = action {
7001 actions.insert(ix, action);
7002 }
7003 }
7004 }
7005 actions
7006 }
7007
7008 pub fn bindings_for_action(&self, action: &dyn Action) -> Vec<KeyBinding> {
7011 self.frame_state
7012 .rendered_frame
7013 .dispatch_tree
7014 .bindings_for_action(
7015 action,
7016 &self.frame_state.rendered_frame.dispatch_tree.context_stack,
7017 )
7018 }
7019
7020 pub fn highest_precedence_binding_for_action(&self, action: &dyn Action) -> Option<KeyBinding> {
7023 self.frame_state
7024 .rendered_frame
7025 .dispatch_tree
7026 .highest_precedence_binding_for_action(
7027 action,
7028 &self.frame_state.rendered_frame.dispatch_tree.context_stack,
7029 )
7030 }
7031
7032 pub fn bindings_for_action_in_context(
7034 &self,
7035 action: &dyn Action,
7036 context: KeyContext,
7037 ) -> Vec<KeyBinding> {
7038 let dispatch_tree = &self.frame_state.rendered_frame.dispatch_tree;
7039 dispatch_tree.bindings_for_action(action, &[context])
7040 }
7041
7042 pub fn highest_precedence_binding_for_action_in_context(
7045 &self,
7046 action: &dyn Action,
7047 context: KeyContext,
7048 ) -> Option<KeyBinding> {
7049 let dispatch_tree = &self.frame_state.rendered_frame.dispatch_tree;
7050 dispatch_tree.highest_precedence_binding_for_action(action, &[context])
7051 }
7052
7053 pub fn bindings_for_action_in(
7057 &self,
7058 action: &dyn Action,
7059 focus_handle: &FocusHandle,
7060 ) -> Vec<KeyBinding> {
7061 let dispatch_tree = &self.frame_state.rendered_frame.dispatch_tree;
7062 let Some(context_stack) = self.context_stack_for_focus_handle(focus_handle) else {
7063 return vec![];
7064 };
7065 dispatch_tree.bindings_for_action(action, &context_stack)
7066 }
7067
7068 pub fn highest_precedence_binding_for_action_in(
7072 &self,
7073 action: &dyn Action,
7074 focus_handle: &FocusHandle,
7075 ) -> Option<KeyBinding> {
7076 let dispatch_tree = &self.frame_state.rendered_frame.dispatch_tree;
7077 let context_stack = self.context_stack_for_focus_handle(focus_handle)?;
7078 dispatch_tree.highest_precedence_binding_for_action(action, &context_stack)
7079 }
7080
7081 pub fn possible_bindings_for_input(&self, input: &[Keystroke]) -> Vec<KeyBinding> {
7083 self.frame_state
7084 .rendered_frame
7085 .dispatch_tree
7086 .possible_next_bindings_for_input(input, &self.context_stack())
7087 }
7088
7089 fn context_stack_for_focus_handle(
7090 &self,
7091 focus_handle: &FocusHandle,
7092 ) -> Option<Vec<KeyContext>> {
7093 let dispatch_tree = &self.frame_state.rendered_frame.dispatch_tree;
7094 let node_id = dispatch_tree.focusable_node_id(focus_handle.id)?;
7095 let context_stack: Vec<_> = dispatch_tree
7096 .dispatch_path(node_id)
7097 .into_iter()
7098 .filter_map(|node_id| dispatch_tree.node(node_id).context.clone())
7099 .collect();
7100 Some(context_stack)
7101 }
7102
7103 pub fn listener_for<T: 'static, E>(
7105 &self,
7106 view: &Entity<T>,
7107 f: impl Fn(&mut T, &E, &mut Window, &mut Context<T>) + 'static,
7108 ) -> impl Fn(&E, &mut Window, &mut App) + 'static {
7109 let view = view.downgrade();
7110 move |e: &E, window: &mut Window, cx: &mut App| {
7111 view.update(cx, |view, cx| f(view, e, window, cx)).ok();
7112 }
7113 }
7114
7115 pub fn handler_for<E: 'static, Callback: Fn(&mut E, &mut Window, &mut Context<E>) + 'static>(
7117 &self,
7118 entity: &Entity<E>,
7119 f: Callback,
7120 ) -> impl Fn(&mut Window, &mut App) + 'static {
7121 let entity = entity.downgrade();
7122 move |window: &mut Window, cx: &mut App| {
7123 entity.update(cx, |entity, cx| f(entity, window, cx)).ok();
7124 }
7125 }
7126
7127 pub fn on_window_should_close(
7130 &self,
7131 cx: &App,
7132 f: impl Fn(&mut Window, &mut App) -> bool + 'static,
7133 ) {
7134 let mut cx = self.to_async(cx);
7135 self.core.platform_window.on_should_close(Box::new(move || {
7136 cx.update(|window, cx| f(window, cx)).unwrap_or(true)
7137 }))
7138 }
7139
7140 pub fn on_action(
7149 &mut self,
7150 action_type: TypeId,
7151 listener: impl Fn(&dyn Any, DispatchPhase, &mut Window, &mut App) + 'static,
7152 ) {
7153 self.core.invalidator.debug_assert_paint();
7154
7155 self.frame_state
7156 .next_frame
7157 .dispatch_tree
7158 .on_action(action_type, Rc::new(listener));
7159 }
7160
7161 pub fn on_action_when(
7170 &mut self,
7171 condition: bool,
7172 action_type: TypeId,
7173 listener: impl Fn(&dyn Any, DispatchPhase, &mut Window, &mut App) + 'static,
7174 ) {
7175 self.core.invalidator.debug_assert_paint();
7176
7177 if condition {
7178 self.frame_state
7179 .next_frame
7180 .dispatch_tree
7181 .on_action(action_type, Rc::new(listener));
7182 }
7183 }
7184
7185 pub fn gpu_specs(&self) -> Option<GpuSpecs> {
7188 self.core.platform_window.gpu_specs()
7189 }
7190
7191 pub fn titlebar_double_click(&self) {
7194 self.core
7195 .platform_window
7196 .titlebar_double_click(self.core.is_resizable, self.core.is_minimizable);
7197 }
7198
7199 pub fn window_title(&self) -> String {
7202 self.core.platform_window.get_title()
7203 }
7204
7205 pub fn tabbed_windows(&self) -> Option<Vec<SystemWindowTab>> {
7208 self.core.platform_window.tabbed_windows()
7209 }
7210
7211 pub fn tab_bar_visible(&self) -> bool {
7214 self.core.platform_window.tab_bar_visible()
7215 }
7216
7217 pub fn merge_all_windows(&self) {
7220 self.core.platform_window.merge_all_windows()
7221 }
7222
7223 pub fn move_tab_to_new_window(&self) {
7226 self.core.platform_window.move_tab_to_new_window()
7227 }
7228
7229 pub fn toggle_window_tab_overview(&self) {
7232 self.core.platform_window.toggle_window_tab_overview()
7233 }
7234
7235 pub fn set_tabbing_identifier(&self, tabbing_identifier: Option<String>) {
7238 self.core
7239 .platform_window
7240 .set_tabbing_identifier(tabbing_identifier)
7241 }
7242
7243 pub fn play_system_bell(&self) {
7246 self.core.platform_window.play_system_bell()
7247 }
7248
7249 pub fn is_a11y_active(&self) -> bool {
7260 self.core.a11y.is_active()
7261 }
7262
7263 pub fn debug_a11y_tree_json(&self) -> Option<String> {
7265 self.core.a11y.debug_tree_json()
7266 }
7267
7268 pub fn on_a11y_action(
7274 &mut self,
7275 node_id: accesskit::NodeId,
7276 action: accesskit::Action,
7277 listener: impl FnMut(Option<&accesskit::ActionData>, &mut Window, &mut App) + 'static,
7278 ) {
7279 self.core
7280 .a11y
7281 .action_listeners
7282 .entry(node_id)
7283 .or_default()
7284 .push((action, Box::new(listener)));
7285 }
7286
7287 #[cfg(not(target_family = "wasm"))]
7288 pub(crate) fn handle_a11y_action(&mut self, request: accesskit::ActionRequest, cx: &mut App) {
7289 if let Some(mut listeners) = self.core.a11y.action_listeners.remove(&request.target_node) {
7292 let extra_data = request.data.as_ref();
7293 let mut matched = false;
7294 for (action, listener) in &mut listeners {
7295 if *action == request.action {
7296 listener(extra_data, self, cx);
7297 matched = true;
7298 }
7299 }
7300 self.core
7301 .a11y
7302 .action_listeners
7303 .insert(request.target_node, listeners);
7304 if matched {
7305 return;
7306 }
7307 }
7308
7309 match request.action {
7311 accesskit::Action::Click => {
7312 if let Some(bounds) = self
7313 .core
7314 .a11y
7315 .node_bounds
7316 .get(&request.target_node)
7317 .copied()
7318 {
7319 let center = bounds.center();
7320 let mouse_down = PlatformInput::MouseDown(crate::MouseDownEvent {
7321 button: MouseButton::Left,
7322 position: center,
7323 modifiers: Modifiers::default(),
7324 click_count: 1,
7325 first_mouse: false,
7326 });
7327 let mouse_up = PlatformInput::MouseUp(MouseUpEvent {
7328 button: MouseButton::Left,
7329 position: center,
7330 modifiers: Modifiers::default(),
7331 click_count: 1,
7332 });
7333 self.dispatch_event(mouse_down, cx);
7334 self.dispatch_event(mouse_up, cx);
7335 }
7336 }
7337 accesskit::Action::Focus => {
7338 if let Some(focus_id) = self.core.a11y.focus_ids.get(&request.target_node).copied()
7339 && let Some(handle) = FocusHandle::for_id(focus_id, &cx.focus_handles)
7340 {
7341 self.focus(&handle, cx);
7342 }
7343 }
7344 accesskit::Action::Blur => {
7345 self.blur(cx);
7346 }
7347 _ => {
7348 log::debug!(
7349 "Unhandled a11y action: {:?} on {:?}",
7350 request.action,
7351 request.target_node
7352 );
7353 }
7354 }
7355 }
7356
7357 #[cfg(any(feature = "inspector", debug_assertions))]
7359 pub fn toggle_inspector(&mut self, cx: &mut App) {
7360 self.core.inspector = match self.core.inspector {
7361 None => Some(cx.new(|_| Inspector::new())),
7362 Some(_) => None,
7363 };
7364 self.refresh();
7365 }
7366
7367 pub fn is_inspector_picking(&self, _cx: &App) -> bool {
7369 #[cfg(any(feature = "inspector", debug_assertions))]
7370 {
7371 if let Some(inspector) = &self.core.inspector {
7372 return inspector.read(_cx).is_picking();
7373 }
7374 }
7375 false
7376 }
7377
7378 pub(crate) fn set_inspector_element_id(
7382 &mut self,
7383 inspector_element_id: Option<crate::InspectorElementId>,
7384 ) -> Option<crate::InspectorElementId> {
7385 std::mem::replace(
7386 &mut self.frame_state.inspector_element_id,
7387 inspector_element_id,
7388 )
7389 }
7390
7391 #[cfg(any(feature = "inspector", debug_assertions))]
7396 pub fn with_inspector_state<T: 'static, R>(
7397 &mut self,
7398 inspector_id: Option<&crate::InspectorElementId>,
7399 cx: &mut App,
7400 f: impl FnOnce(&mut Option<T>, &mut Self) -> R,
7401 ) -> R {
7402 if let Some(inspector_id) = inspector_id
7403 && let Some(inspector) = &self.core.inspector
7404 {
7405 let inspector = inspector.clone();
7406 let active_element_id = inspector.read(cx).active_element_id();
7407 if Some(inspector_id) == active_element_id {
7408 return inspector.update(cx, |inspector, _cx| {
7409 inspector.with_active_element_state(self, f)
7410 });
7411 }
7412 }
7413 f(&mut None, self)
7414 }
7415
7416 #[cfg(any(feature = "inspector", debug_assertions))]
7422 pub fn with_current_inspector_state<T: 'static, R>(
7423 &mut self,
7424 cx: &mut App,
7425 f: impl FnOnce(&mut Option<T>, &mut Self) -> R,
7426 ) -> R {
7427 let inspector_id = self.frame_state.inspector_element_id.clone();
7428 self.with_inspector_state(inspector_id.as_ref(), cx, f)
7429 }
7430
7431 #[cfg(any(feature = "inspector", debug_assertions))]
7432 pub(crate) fn build_inspector_element_id(
7433 &mut self,
7434 path: crate::InspectorElementPath,
7435 ) -> crate::InspectorElementId {
7436 self.core.invalidator.debug_assert_paint_or_prepaint();
7437 let path = Rc::new(path);
7438 let next_instance_id = self
7439 .frame_state
7440 .next_frame
7441 .next_inspector_instance_ids
7442 .entry(path.clone())
7443 .or_insert(0);
7444 let instance_id = *next_instance_id;
7445 *next_instance_id += 1;
7446 crate::InspectorElementId { path, instance_id }
7447 }
7448
7449 #[cfg(any(feature = "inspector", debug_assertions))]
7450 fn prepaint_inspector(&mut self, inspector_width: Pixels, cx: &mut App) -> Option<AnyElement> {
7451 if let Some(inspector) = self.core.inspector.take() {
7452 let mut inspector_element = AnyView::from(inspector.clone()).into_any_element();
7453 inspector_element.prepaint_as_root(
7454 point(self.core.viewport_size.width - inspector_width, px(0.0)),
7455 size(inspector_width, self.core.viewport_size.height).into(),
7456 self,
7457 cx,
7458 );
7459 self.core.inspector = Some(inspector);
7460 Some(inspector_element)
7461 } else {
7462 None
7463 }
7464 }
7465
7466 #[cfg(any(feature = "inspector", debug_assertions))]
7467 fn paint_inspector(&mut self, mut inspector_element: Option<AnyElement>, cx: &mut App) {
7468 if let Some(mut inspector_element) = inspector_element {
7469 inspector_element.paint(self, cx);
7470 };
7471 }
7472
7473 #[cfg(any(feature = "inspector", debug_assertions))]
7479 pub(crate) fn insert_inspector_hitbox(&mut self, hitbox_id: HitboxId, cx: &App) {
7480 self.core.invalidator.debug_assert_paint_or_prepaint();
7481 if !self.is_inspector_picking(cx) {
7482 return;
7483 }
7484 if let Some(inspector_id) = self.frame_state.inspector_element_id.clone() {
7485 self.frame_state
7486 .next_frame
7487 .inspector_hitboxes
7488 .insert(hitbox_id, inspector_id);
7489 }
7490 }
7491
7492 #[cfg(any(feature = "inspector", debug_assertions))]
7493 fn paint_inspector_hitbox(&mut self, cx: &App) {
7494 if let Some(inspector) = self.core.inspector.as_ref() {
7495 let inspector = inspector.read(cx);
7496 if let Some((hitbox_id, _)) =
7497 self.hovered_inspector_hitbox(inspector, &self.frame_state.next_frame)
7498 && let Some(hitbox) = self
7499 .frame_state
7500 .next_frame
7501 .hitboxes
7502 .iter()
7503 .find(|hitbox| hitbox.id == hitbox_id)
7504 {
7505 self.paint_quad(crate::fill(hitbox.bounds, crate::rgba(0x61afef4d)));
7506 }
7507 }
7508 }
7509
7510 #[cfg(any(feature = "inspector", debug_assertions))]
7511 fn handle_inspector_mouse_event(&mut self, event: &dyn Any, cx: &mut App) {
7512 let Some(inspector) = self.core.inspector.clone() else {
7513 return;
7514 };
7515 if event.downcast_ref::<MouseMoveEvent>().is_some() {
7516 inspector.update(cx, |inspector, _cx| {
7517 if let Some((_, inspector_id)) =
7518 self.hovered_inspector_hitbox(inspector, &self.frame_state.rendered_frame)
7519 {
7520 inspector.hover(inspector_id, self);
7521 }
7522 });
7523 } else if event.downcast_ref::<crate::MouseDownEvent>().is_some() {
7524 inspector.update(cx, |inspector, _cx| {
7525 if let Some((_, inspector_id)) =
7526 self.hovered_inspector_hitbox(inspector, &self.frame_state.rendered_frame)
7527 {
7528 inspector.select(inspector_id, self);
7529 }
7530 });
7531 } else if let Some(event) = event.downcast_ref::<crate::ScrollWheelEvent>() {
7532 const SCROLL_LINES: f32 = 3.0;
7534 const SCROLL_PIXELS_PER_LAYER: f32 = 36.0;
7535 let delta_y = event
7536 .delta
7537 .pixel_delta(px(SCROLL_PIXELS_PER_LAYER / SCROLL_LINES))
7538 .y;
7539 if let Some(inspector) = self.core.inspector.clone() {
7540 inspector.update(cx, |inspector, _cx| {
7541 if let Some(depth) = inspector.pick_depth.as_mut() {
7542 *depth += f32::from(delta_y) / SCROLL_PIXELS_PER_LAYER;
7543 let max_depth = self.core.mouse_hit_test.ids.len() as f32 - 0.5;
7544 if *depth < 0.0 {
7545 *depth = 0.0;
7546 } else if *depth > max_depth {
7547 *depth = max_depth;
7548 }
7549 if let Some((_, inspector_id)) = self
7550 .hovered_inspector_hitbox(inspector, &self.frame_state.rendered_frame)
7551 {
7552 inspector.set_active_element_id(inspector_id, self);
7553 }
7554 }
7555 });
7556 }
7557 }
7558 }
7559
7560 #[cfg(any(feature = "inspector", debug_assertions))]
7561 fn hovered_inspector_hitbox(
7562 &self,
7563 inspector: &Inspector,
7564 frame: &Frame,
7565 ) -> Option<(HitboxId, crate::InspectorElementId)> {
7566 if let Some(pick_depth) = inspector.pick_depth {
7567 let depth = (pick_depth as i64).try_into().unwrap_or(0);
7568 let max_skipped = self.core.mouse_hit_test.ids.len().saturating_sub(1);
7569 let skip_count = (depth as usize).min(max_skipped);
7570 for hitbox_id in self.core.mouse_hit_test.ids.iter().skip(skip_count) {
7571 if let Some(inspector_id) = frame.inspector_hitboxes.get(hitbox_id) {
7572 return Some((*hitbox_id, inspector_id.clone()));
7573 }
7574 }
7575 }
7576 None
7577 }
7578
7579 #[cfg(any(test, feature = "test-support"))]
7582 pub fn set_modifiers(&mut self, modifiers: Modifiers) {
7583 self.core.modifiers = modifiers;
7584 }
7585
7586 #[cfg(any(test, feature = "test-support"))]
7590 pub fn simulate_mouse_move(&mut self, position: Point<Pixels>, cx: &mut App) {
7591 let event = PlatformInput::MouseMove(MouseMoveEvent {
7592 position,
7593 modifiers: self.core.modifiers,
7594 pressed_button: None,
7595 });
7596 let _ = self.dispatch_event(event, cx);
7597 }
7598}
7599
7600#[derive(Deref, DerefMut)]
7603pub struct WindowHandle<V> {
7604 #[deref]
7605 #[deref_mut]
7606 pub(crate) any_handle: AnyWindowHandle,
7607 state_type: PhantomData<fn(V) -> V>,
7608}
7609
7610impl<V> Debug for WindowHandle<V> {
7611 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
7612 f.debug_struct("WindowHandle")
7613 .field("any_handle", &self.any_handle.id.as_u64())
7614 .finish()
7615 }
7616}
7617
7618impl<V: 'static + Render> WindowHandle<V> {
7619 pub fn new(id: WindowId) -> Self {
7622 WindowHandle {
7623 any_handle: AnyWindowHandle {
7624 id,
7625 state_type: TypeId::of::<V>(),
7626 root_entity_type_name: std::any::type_name::<V>(),
7627 },
7628 state_type: PhantomData,
7629 }
7630 }
7631
7632 #[cfg(any(test, feature = "test-support"))]
7636 pub fn root<C>(&self, cx: &mut C) -> Result<Entity<V>>
7637 where
7638 C: AppContext,
7639 {
7640 cx.update_window(self.any_handle, |root_view, _, _| {
7641 root_view
7642 .downcast::<V>()
7643 .map_err(|_| anyhow!("the type of the window's root view has changed"))
7644 })?
7645 }
7646
7647 pub fn update<C, R>(
7651 &self,
7652 cx: &mut C,
7653 update: impl FnOnce(&mut V, &mut Window, &mut Context<V>) -> R,
7654 ) -> Result<R>
7655 where
7656 C: AppContext,
7657 {
7658 cx.update_window(self.any_handle, |root_view, window, cx| {
7659 let view = root_view
7660 .downcast::<V>()
7661 .map_err(|_| anyhow!("the type of the window's root view has changed"))?;
7662
7663 Ok(view.update(cx, |view, cx| update(view, window, cx)))
7664 })?
7665 }
7666
7667 pub fn read<'a>(&self, cx: &'a App) -> Result<&'a V> {
7671 let x = cx
7672 .windows
7673 .cell(self.id)
7674 .and_then(|cell| cell.borrow().core.root.clone())
7675 .map(|root_view| root_view.downcast::<V>())
7676 .context("window not found")?
7677 .map_err(|_| anyhow!("the type of the window's root view has changed"))?;
7678
7679 Ok(x.read(cx))
7680 }
7681
7682 pub fn read_with<C, R>(&self, cx: &C, read_with: impl FnOnce(&V, &App) -> R) -> Result<R>
7686 where
7687 C: AppContext,
7688 {
7689 cx.read_window(self, |root_view, cx| read_with(root_view.read(cx), cx))
7690 }
7691
7692 pub fn entity<C>(&self, cx: &C) -> Result<Entity<V>>
7696 where
7697 C: AppContext,
7698 {
7699 cx.read_window(self, |root_view, _cx| root_view)
7700 }
7701
7702 pub fn is_active(&self, cx: &mut App) -> Option<bool> {
7707 cx.update_window(self.any_handle, |_, window, _| window.is_window_active())
7708 .ok()
7709 }
7710}
7711
7712impl<V> Copy for WindowHandle<V> {}
7713
7714impl<V> Clone for WindowHandle<V> {
7715 fn clone(&self) -> Self {
7716 *self
7717 }
7718}
7719
7720impl<V> PartialEq for WindowHandle<V> {
7721 fn eq(&self, other: &Self) -> bool {
7722 self.any_handle == other.any_handle
7723 }
7724}
7725
7726impl<V> Eq for WindowHandle<V> {}
7727
7728impl<V> Hash for WindowHandle<V> {
7729 fn hash<H: Hasher>(&self, state: &mut H) {
7730 self.any_handle.hash(state);
7731 }
7732}
7733
7734impl<V: 'static> From<WindowHandle<V>> for AnyWindowHandle {
7735 fn from(val: WindowHandle<V>) -> Self {
7736 val.any_handle
7737 }
7738}
7739
7740#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
7742pub struct AnyWindowHandle {
7743 pub(crate) id: WindowId,
7744 state_type: TypeId,
7745 root_entity_type_name: &'static str,
7746}
7747
7748impl AnyWindowHandle {
7749 pub fn window_id(&self) -> WindowId {
7751 self.id
7752 }
7753
7754 pub fn metrics(&self, cx: &App) -> Option<WindowMetricsHandle> {
7761 cx.windows
7762 .cell(self.id)
7763 .map(|cell| cell.borrow().core.metrics_handle())
7764 }
7765
7766 pub fn root_entity_type_name(&self) -> &'static str {
7768 self.root_entity_type_name
7769 }
7770
7771 pub fn downcast<T: 'static>(&self) -> Option<WindowHandle<T>> {
7774 if TypeId::of::<T>() == self.state_type {
7775 Some(WindowHandle {
7776 any_handle: *self,
7777 state_type: PhantomData,
7778 })
7779 } else {
7780 None
7781 }
7782 }
7783
7784 pub fn update<C, R>(
7788 self,
7789 cx: &mut C,
7790 update: impl FnOnce(AnyView, &mut Window, &mut App) -> R,
7791 ) -> Result<R>
7792 where
7793 C: AppContext,
7794 {
7795 cx.update_window(self, update)
7796 }
7797
7798 pub fn read<T, C, R>(self, cx: &C, read: impl FnOnce(Entity<T>, &App) -> R) -> Result<R>
7802 where
7803 C: AppContext,
7804 T: 'static,
7805 {
7806 let view = self
7807 .downcast::<T>()
7808 .context("the type of the window's root view has changed")?;
7809
7810 cx.read_window(&view, read)
7811 }
7812}
7813
7814impl HasWindowHandle for Window<'_> {
7815 fn window_handle(&self) -> Result<raw_window_handle::WindowHandle<'_>, HandleError> {
7816 self.core.platform_window.window_handle()
7817 }
7818}
7819
7820impl HasDisplayHandle for Window<'_> {
7821 fn display_handle(
7822 &self,
7823 ) -> std::result::Result<raw_window_handle::DisplayHandle<'_>, HandleError> {
7824 self.core.platform_window.display_handle()
7825 }
7826}
7827
7828#[derive(Clone, Debug, Eq, PartialEq, Hash)]
7833pub enum ElementId {
7834 View(EntityId),
7836 Integer(u64),
7838 Name(SharedString),
7840 Uuid(Uuid),
7842 FocusHandle(FocusId),
7844 NamedInteger(SharedString, u64),
7846 Path(Arc<std::path::Path>),
7848 CodeLocation(core::panic::Location<'static>),
7850 NamedChild(Arc<ElementId>, SharedString),
7852 OpaqueId([u8; 20]),
7854}
7855
7856impl ElementId {
7857 pub fn named_usize(name: impl Into<SharedString>, integer: usize) -> ElementId {
7859 Self::NamedInteger(name.into(), integer as u64)
7860 }
7861}
7862
7863impl Display for ElementId {
7864 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
7865 match self {
7866 ElementId::View(entity_id) => write!(f, "view-{}", entity_id)?,
7867 ElementId::Integer(ix) => write!(f, "{}", ix)?,
7868 ElementId::Name(name) => write!(f, "{}", name)?,
7869 ElementId::FocusHandle(_) => write!(f, "FocusHandle")?,
7870 ElementId::NamedInteger(s, i) => write!(f, "{}-{}", s, i)?,
7871 ElementId::Uuid(uuid) => write!(f, "{}", uuid)?,
7872 ElementId::Path(path) => write!(f, "{}", path.display())?,
7873 ElementId::CodeLocation(location) => write!(f, "{}", location)?,
7874 ElementId::NamedChild(id, name) => write!(f, "{}-{}", id, name)?,
7875 ElementId::OpaqueId(opaque_id) => write!(f, "{:x?}", opaque_id)?,
7876 }
7877
7878 Ok(())
7879 }
7880}
7881
7882impl TryInto<SharedString> for ElementId {
7883 type Error = anyhow::Error;
7884
7885 fn try_into(self) -> anyhow::Result<SharedString> {
7886 if let ElementId::Name(name) = self {
7887 Ok(name)
7888 } else {
7889 anyhow::bail!("element id is not string")
7890 }
7891 }
7892}
7893
7894impl From<usize> for ElementId {
7895 fn from(id: usize) -> Self {
7896 ElementId::Integer(id as u64)
7897 }
7898}
7899
7900impl From<i32> for ElementId {
7901 fn from(id: i32) -> Self {
7902 Self::Integer(id as u64)
7903 }
7904}
7905
7906impl From<SharedString> for ElementId {
7907 fn from(name: SharedString) -> Self {
7908 ElementId::Name(name)
7909 }
7910}
7911
7912impl From<String> for ElementId {
7913 fn from(name: String) -> Self {
7914 ElementId::Name(name.into())
7915 }
7916}
7917
7918impl From<Arc<str>> for ElementId {
7919 fn from(name: Arc<str>) -> Self {
7920 ElementId::Name(name.into())
7921 }
7922}
7923
7924impl From<Arc<std::path::Path>> for ElementId {
7925 fn from(path: Arc<std::path::Path>) -> Self {
7926 ElementId::Path(path)
7927 }
7928}
7929
7930impl From<&'static str> for ElementId {
7931 fn from(name: &'static str) -> Self {
7932 ElementId::Name(SharedString::new_static(name))
7933 }
7934}
7935
7936impl<'a> From<&'a FocusHandle> for ElementId {
7937 fn from(handle: &'a FocusHandle) -> Self {
7938 ElementId::FocusHandle(handle.id)
7939 }
7940}
7941
7942impl From<(&'static str, EntityId)> for ElementId {
7943 fn from((name, id): (&'static str, EntityId)) -> Self {
7944 ElementId::NamedInteger(SharedString::new_static(name), id.as_u64())
7945 }
7946}
7947
7948impl From<(&'static str, usize)> for ElementId {
7949 fn from((name, id): (&'static str, usize)) -> Self {
7950 ElementId::NamedInteger(SharedString::new_static(name), id as u64)
7951 }
7952}
7953
7954impl From<(SharedString, usize)> for ElementId {
7955 fn from((name, id): (SharedString, usize)) -> Self {
7956 ElementId::NamedInteger(name, id as u64)
7957 }
7958}
7959
7960impl From<(&'static str, u64)> for ElementId {
7961 fn from((name, id): (&'static str, u64)) -> Self {
7962 ElementId::NamedInteger(SharedString::new_static(name), id)
7963 }
7964}
7965
7966impl From<Uuid> for ElementId {
7967 fn from(value: Uuid) -> Self {
7968 Self::Uuid(value)
7969 }
7970}
7971
7972impl From<(&'static str, u32)> for ElementId {
7973 fn from((name, id): (&'static str, u32)) -> Self {
7974 ElementId::NamedInteger(SharedString::new_static(name), u64::from(id))
7975 }
7976}
7977
7978impl<T: Into<SharedString>> From<(ElementId, T)> for ElementId {
7979 fn from((id, name): (ElementId, T)) -> Self {
7980 ElementId::NamedChild(Arc::new(id), name.into())
7981 }
7982}
7983
7984impl From<&'static core::panic::Location<'static>> for ElementId {
7985 fn from(location: &'static core::panic::Location<'static>) -> Self {
7986 ElementId::CodeLocation(*location)
7987 }
7988}
7989
7990impl From<[u8; 20]> for ElementId {
7991 fn from(opaque_id: [u8; 20]) -> Self {
7992 ElementId::OpaqueId(opaque_id)
7993 }
7994}
7995
7996#[derive(Clone)]
7999pub struct PaintQuad {
8000 pub bounds: Bounds<Pixels>,
8002 pub corner_radii: Corners<Pixels>,
8004 pub background: Background,
8006 pub border_widths: Edges<Pixels>,
8008 pub border_color: Hsla,
8010 pub border_style: BorderStyle,
8012}
8013
8014impl PaintQuad {
8015 pub fn corner_radii(self, corner_radii: impl Into<Corners<Pixels>>) -> Self {
8017 PaintQuad {
8018 corner_radii: corner_radii.into(),
8019 ..self
8020 }
8021 }
8022
8023 pub fn border_widths(self, border_widths: impl Into<Edges<Pixels>>) -> Self {
8025 PaintQuad {
8026 border_widths: border_widths.into(),
8027 ..self
8028 }
8029 }
8030
8031 pub fn border_color(self, border_color: impl Into<Hsla>) -> Self {
8033 PaintQuad {
8034 border_color: border_color.into(),
8035 ..self
8036 }
8037 }
8038
8039 pub fn background(self, background: impl Into<Background>) -> Self {
8041 PaintQuad {
8042 background: background.into(),
8043 ..self
8044 }
8045 }
8046}
8047
8048pub fn quad(
8050 bounds: Bounds<Pixels>,
8051 corner_radii: impl Into<Corners<Pixels>>,
8052 background: impl Into<Background>,
8053 border_widths: impl Into<Edges<Pixels>>,
8054 border_color: impl Into<Hsla>,
8055 border_style: BorderStyle,
8056) -> PaintQuad {
8057 PaintQuad {
8058 bounds,
8059 corner_radii: corner_radii.into(),
8060 background: background.into(),
8061 border_widths: border_widths.into(),
8062 border_color: border_color.into(),
8063 border_style,
8064 }
8065}
8066
8067pub fn fill(bounds: impl Into<Bounds<Pixels>>, background: impl Into<Background>) -> PaintQuad {
8069 PaintQuad {
8070 bounds: bounds.into(),
8071 corner_radii: (0.).into(),
8072 background: background.into(),
8073 border_widths: (0.).into(),
8074 border_color: transparent_black(),
8075 border_style: BorderStyle::default(),
8076 }
8077}
8078
8079pub fn outline(
8081 bounds: impl Into<Bounds<Pixels>>,
8082 border_color: impl Into<Hsla>,
8083 border_style: BorderStyle,
8084) -> PaintQuad {
8085 PaintQuad {
8086 bounds: bounds.into(),
8087 corner_radii: (0.).into(),
8088 background: transparent_black().into(),
8089 border_widths: (1.).into(),
8090 border_color: border_color.into(),
8091 border_style,
8092 }
8093}
8094
8095#[cfg(test)]
8096mod tests {
8097 use std::{
8098 cell::{Cell, RefCell},
8099 path::PathBuf,
8100 rc::Rc,
8101 time::Duration,
8102 };
8103
8104 use crate::{
8105 AnyWindowHandle, App, AppContext as _, ArenaClearNeeded, Bounds, Context, DispatchPhase,
8106 DragMoveEvent, Empty, ExternalDragPayload, ExternalPaths, FileDragPaths, FileDropEvent,
8107 FocusHandle, FocusId, FramePipeline, InputEvent as _, InteractiveElement as _, IntoElement,
8108 KeyDownEvent, Keystroke, LongPressEvent, MouseButton, MouseDownEvent, MouseMoveEvent,
8109 ParentElement, Pixels, PlatformInput, Point, Render, RequestFrameOptions,
8110 StandardImmediatePipeline, StatefulInteractiveElement as _, Styled, TestAppContext,
8111 TouchDragEvent, TouchEvent, TouchId, TouchPhase, Window, WindowAppearance, WindowMetrics,
8112 WindowOptions, canvas, div, point, px, size,
8113 };
8114
8115 #[gpui::test]
8119 fn test_window_visibility(cx: &mut TestAppContext) {
8120 use crate::WindowVisibility;
8121
8122 let window = cx.add_window(|_, _| EmptyView);
8123 let observed = Rc::new(RefCell::new(Vec::new()));
8124 let _subscription = window
8125 .update(cx, {
8126 let observed = observed.clone();
8127 move |_, window, _| {
8128 assert_eq!(window.visibility(), WindowVisibility::Visible);
8129 assert!(window.is_visible());
8130 window.observe_window_visibility(move |visibility, window, _| {
8131 assert_eq!(window.visibility(), visibility);
8132 observed.borrow_mut().push(visibility);
8133 })
8134 }
8135 })
8136 .unwrap();
8137 let test_window = cx.test_window(window.into());
8138 let frame_wake_count = test_window.frame_wake_count();
8139
8140 test_window.simulate_visibility_change(WindowVisibility::Hidden);
8141 assert_eq!(*observed.borrow(), [WindowVisibility::Hidden]);
8142 window
8143 .update(cx, |_, window, _| assert!(!window.is_visible()))
8144 .unwrap();
8145
8146 test_window.simulate_visibility_change(WindowVisibility::Hidden);
8148 assert_eq!(observed.borrow().len(), 1);
8149
8150 test_window.simulate_visibility_change(WindowVisibility::Visible);
8151 assert_eq!(
8152 *observed.borrow(),
8153 [WindowVisibility::Hidden, WindowVisibility::Visible]
8154 );
8155 window
8156 .update(cx, |_, window, _| assert!(window.is_visible()))
8157 .unwrap();
8158 assert_eq!(test_window.frame_wake_count(), frame_wake_count);
8159 }
8160
8161 #[gpui::test]
8164 fn a_window_draws_through_its_frame_pipeline(cx: &mut TestAppContext) {
8165 let recorded: Rc<RefCell<Vec<&'static str>>> = Rc::new(RefCell::new(Vec::new()));
8166 let recorder = recorded.clone();
8167 cx.update(move |cx| {
8168 cx.set_frame_pipeline_factory(Rc::new(move |_| {
8169 Box::new(RecordingPipeline(recorder.clone()))
8170 }));
8171 });
8172
8173 let window = cx.add_window(|_, _| EmptyView);
8174 recorded.borrow_mut().clear();
8175 cx.update_window(window.into(), |_, window, cx| window.draw(cx).clear(cx))
8176 .unwrap();
8177
8178 let phases = recorded.borrow();
8179 assert!(
8180 phases.starts_with(&[
8181 "begin_frame",
8182 "draw_roots",
8183 "finish_frame",
8184 "complete_frame",
8185 "end_frame"
8186 ]),
8187 "frame ran {phases:?}"
8188 );
8189 }
8190
8191 struct RecordingPipeline(Rc<RefCell<Vec<&'static str>>>);
8194
8195 impl FramePipeline for RecordingPipeline {
8196 fn begin_frame(&mut self, window: &mut Window, cx: &mut App) {
8197 self.0.borrow_mut().push("begin_frame");
8198 window.begin_frame(cx);
8199 }
8200
8201 fn draw_roots(&mut self, window: &mut Window, cx: &mut App) {
8202 self.0.borrow_mut().push("draw_roots");
8203 window.draw_roots(cx);
8204 }
8205
8206 fn finish_frame(&mut self, window: &mut Window, cx: &mut App) {
8207 self.0.borrow_mut().push("finish_frame");
8208 window.finish_frame(cx);
8209 }
8210
8211 fn complete_frame(&mut self, window: &mut Window, cx: &mut App) -> Option<FocusId> {
8212 self.0.borrow_mut().push("complete_frame");
8213 window.complete_frame(cx)
8214 }
8215
8216 fn end_frame(
8217 &mut self,
8218 window: &mut Window,
8219 cx: &mut App,
8220 focus_before_listeners: Option<FocusId>,
8221 ) {
8222 self.0.borrow_mut().push("end_frame");
8223 window.end_frame(cx, focus_before_listeners);
8224 }
8225 }
8226
8227 #[gpui::test]
8230 fn a_frame_that_skips_drawing_still_completes(cx: &mut TestAppContext) {
8231 cx.skip_drawing();
8232 let window = cx.add_window(|_, _| EmptyView);
8233
8234 cx.update_window(window.into(), |_, window, cx| window.draw(cx).clear(cx))
8235 .unwrap();
8236 }
8237
8238 #[cfg(debug_assertions)]
8241 #[gpui::test]
8242 #[should_panic(expected = "paint_roots ran while the frame was Evaluated")]
8243 fn a_frame_pass_out_of_order_is_rejected(cx: &mut TestAppContext) {
8244 let window = cx.add_window(|_, _| EmptyView);
8245
8246 cx.update_window(window.into(), |_, window, cx| {
8247 window.begin_frame(cx);
8248 let roots = window.evaluate_roots(cx);
8249 window.paint_roots(roots, cx);
8252 })
8253 .unwrap();
8254 }
8255
8256 struct PacingPipeline {
8258 frames: Rc<Cell<usize>>,
8259 asks: Rc<Cell<usize>>,
8260 allow: bool,
8261 }
8262
8263 impl FramePipeline for PacingPipeline {
8264 fn should_render(&mut self, is_dirty: bool, _metrics: &WindowMetrics) -> bool {
8265 self.asks.set(self.asks.get() + 1);
8266 self.allow && is_dirty
8267 }
8268
8269 fn draw(&mut self, window: &mut Window, cx: &mut App) -> ArenaClearNeeded {
8270 self.frames.set(self.frames.get() + 1);
8271 FramePipeline::draw(&mut StandardImmediatePipeline, window, cx)
8272 }
8273 }
8274
8275 fn install_pacing_pipeline(
8277 cx: &mut TestAppContext,
8278 frames: Rc<Cell<usize>>,
8279 asks: Rc<Cell<usize>>,
8280 allow: bool,
8281 ) {
8282 cx.update(move |cx| {
8283 cx.set_frame_pipeline_factory(Rc::new(move |_| {
8284 Box::new(PacingPipeline {
8285 frames: frames.clone(),
8286 asks: asks.clone(),
8287 allow,
8288 })
8289 }));
8290 });
8291 }
8292
8293 #[gpui::test]
8295 fn a_pipeline_can_defer_a_frame(cx: &mut TestAppContext) {
8296 let frames = Rc::new(Cell::new(0));
8297 let asks = Rc::new(Cell::new(0));
8298 install_pacing_pipeline(cx, frames.clone(), asks.clone(), false);
8299 let window = cx.add_window(|_, _| EmptyView);
8300 let test_window = cx.test_window(window.into());
8301 frames.set(0);
8302 asks.set(0);
8303
8304 window.update(cx, |_, _, cx| cx.notify()).unwrap();
8305 test_window.simulate_frame_request(RequestFrameOptions::default());
8306
8307 assert!(asks.get() > 0, "the pipeline was asked about the frame");
8308 assert_eq!(frames.get(), 0, "the deferred frame was never drawn");
8309 }
8310
8311 #[gpui::test]
8313 fn a_pipeline_can_allow_a_frame(cx: &mut TestAppContext) {
8314 let frames = Rc::new(Cell::new(0));
8315 let asks = Rc::new(Cell::new(0));
8316 install_pacing_pipeline(cx, frames.clone(), asks, true);
8317 let window = cx.add_window(|_, _| EmptyView);
8318 frames.set(0);
8319
8320 window.update(cx, |_, _, cx| cx.notify()).unwrap();
8321
8322 assert!(frames.get() > 0, "the allowed frame was drawn");
8323 }
8324
8325 #[gpui::test]
8326 fn test_fully_visible_bounds_preserve_layout_viewport(cx: &mut TestAppContext) {
8327 let window = cx.add_window(|_, _| EmptyView);
8328 let mut platform_window = cx.test_window(window.into());
8329 platform_window.simulate_resize(size(px(400.), px(800.)));
8330 window
8331 .update(cx, |_, window, _| {
8332 assert_eq!(
8333 window.visual_viewport_bounds(),
8334 Bounds::new(Point::default(), size(px(400.), px(800.)))
8335 );
8336 assert_eq!(
8337 window.fully_visible_bounds(),
8338 window.visual_viewport_bounds()
8339 );
8340 })
8341 .unwrap();
8342
8343 platform_window.simulate_frame_request(RequestFrameOptions::default());
8344 let wakes = platform_window.frame_wake_count();
8345 let visual_bounds = Bounds::new(point(px(10.), px(40.)), size(px(380.), px(460.)));
8346 platform_window.simulate_visual_viewport_change(visual_bounds);
8347 assert!(platform_window.frame_wake_count() > wakes);
8348 platform_window.simulate_frame_request(RequestFrameOptions::default());
8349 let wakes = platform_window.frame_wake_count();
8350 platform_window.simulate_insets_change(crate::WindowInsets {
8351 safe_area: crate::Edges {
8352 top: px(60.),
8353 right: px(20.),
8354 bottom: px(30.),
8355 left: px(-10.),
8356 },
8357 ime: crate::Edges {
8358 bottom: px(350.),
8359 ..Default::default()
8360 },
8361 });
8362 assert!(platform_window.frame_wake_count() > wakes);
8363 window
8364 .update(cx, |_, window, _| {
8365 assert_eq!(window.viewport_size(), size(px(400.), px(800.)));
8366 assert_eq!(window.visual_viewport_bounds(), visual_bounds);
8367 assert_eq!(
8368 window.fully_visible_bounds(),
8369 Bounds::new(point(px(10.), px(60.)), size(px(370.), px(390.)))
8370 );
8371 window.request_virtual_keyboard();
8372 window.dismiss_virtual_keyboard();
8373 assert_eq!(window.viewport_size(), size(px(400.), px(800.)));
8374 })
8375 .unwrap();
8376 assert_eq!(platform_window.virtual_keyboard_requests(), 1);
8377 assert_eq!(platform_window.virtual_keyboard_dismissals(), 1);
8378
8379 platform_window.simulate_insets_change(crate::WindowInsets {
8380 safe_area: crate::Edges {
8381 top: px(900.),
8382 left: px(500.),
8383 ..Default::default()
8384 },
8385 ..Default::default()
8386 });
8387 window
8388 .update(cx, |_, window, _| {
8389 assert_eq!(
8390 window.fully_visible_bounds().size,
8391 size(Pixels::ZERO, Pixels::ZERO)
8392 );
8393 })
8394 .unwrap();
8395 }
8396
8397 struct EmptyView;
8398
8399 impl Render for EmptyView {
8400 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
8401 div()
8402 }
8403 }
8404
8405 struct OpensWindowOnPaint {
8406 opened: Rc<Cell<bool>>,
8407 }
8408
8409 impl Render for OpensWindowOnPaint {
8410 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
8411 let opened = self.opened.clone();
8412 div()
8413 .size_full()
8414 .child(canvas(
8415 |_, _, _| {},
8416 move |_, _, _window, cx| {
8417 if !opened.replace(true) {
8418 cx.open_window(WindowOptions::default(), |_, cx| cx.new(|_| EmptyView))
8419 .unwrap();
8420 }
8421 },
8422 ))
8423 .child(div().child("after"))
8427 }
8428 }
8429
8430 #[test]
8436 fn test_window_opened_during_draw_defers_arena_clear() {
8437 let mut cx = TestAppContext::single();
8438
8439 let opened = Rc::new(Cell::new(false));
8440 let window = cx.add_window({
8442 let opened = opened.clone();
8443 move |_, _| OpensWindowOnPaint { opened }
8444 });
8445
8446 assert!(opened.get());
8447 assert_eq!(cx.windows().len(), 2);
8448
8449 cx.update_window(window.into(), |_, window, cx| window.draw(cx).clear(cx))
8452 .unwrap();
8453 }
8454
8455 #[test]
8456 fn test_scale_factor_change_preserves_bounds_and_survives_resize() {
8457 let mut cx = TestAppContext::single();
8458 let window = cx.add_window(|_, _| EmptyView);
8459 let handle: AnyWindowHandle = window.into();
8460 let window_state = |cx: &mut TestAppContext| {
8461 cx.update_window(handle, |_, window, _| {
8462 (
8463 window.scale_factor(),
8464 window.bounds(),
8465 window.viewport_size(),
8466 )
8467 })
8468 .unwrap()
8469 };
8470
8471 let (scale_factor, mut expected_bounds, _) = window_state(&mut cx);
8472 assert_eq!(scale_factor, 2.0);
8473
8474 for (scale_factor, resized_size) in [
8475 (1.0, size(px(800.), px(600.))),
8476 (1.25, size(px(640.), px(480.))),
8477 (2.0, size(px(1024.), px(768.))),
8478 ] {
8479 cx.simulate_window_scale_factor_change(handle, scale_factor);
8480 assert_eq!(
8481 window_state(&mut cx),
8482 (scale_factor, expected_bounds, expected_bounds.size)
8483 );
8484
8485 cx.simulate_window_resize(handle, resized_size);
8486 expected_bounds.size = resized_size;
8487 assert_eq!(
8488 window_state(&mut cx),
8489 (scale_factor, expected_bounds, resized_size)
8490 );
8491 }
8492 }
8493
8494 #[gpui::test]
8495 fn metrics_handle_agrees_with_the_window_and_tracks_resizes(cx: &mut TestAppContext) {
8496 let window = cx.add_window(|_, _| EmptyView);
8497 let handle: AnyWindowHandle = window.into();
8498
8499 let metrics = cx.read(|app| handle.metrics(app).expect("window is open"));
8500 assert_eq!(metrics.id(), handle.window_id());
8501 assert!(metrics.display_id().is_some());
8502
8503 let window_state = |cx: &mut TestAppContext| {
8505 cx.update_window(handle, |_, window, _| {
8506 assert_eq!(metrics.bounds(), window.bounds());
8507 assert_eq!(metrics.viewport(), window.visual_viewport_bounds());
8508 assert_eq!(metrics.content_size(), window.viewport_size());
8509 assert_eq!(metrics.scale_factor(), window.scale_factor());
8510 assert_eq!(metrics.is_active(), window.is_window_active());
8511 assert_eq!(metrics.is_fullscreen(), window.is_fullscreen());
8512 })
8513 .unwrap();
8514 };
8515 window_state(cx);
8516
8517 cx.simulate_window_resize(handle, size(px(800.), px(600.)));
8518 cx.simulate_window_scale_factor_change(handle, 1.25);
8519
8520 assert_eq!(metrics.content_size(), size(px(800.), px(600.)));
8523 assert_eq!(metrics.scale_factor(), 1.25);
8524 window_state(cx);
8525 }
8526
8527 #[gpui::test]
8531 fn metrics_track_viewport_changes_that_do_not_resize(cx: &mut TestAppContext) {
8532 let window = cx.add_window(|_, _| EmptyView);
8533 let handle: AnyWindowHandle = window.into();
8534 let metrics = cx.read(|app| handle.metrics(app).expect("window is open"));
8535
8536 let narrow = Bounds::new(point(px(0.), px(120.)), size(px(400.), px(680.)));
8537 assert_ne!(metrics.viewport(), narrow);
8538
8539 cx.simulate_window_visual_viewport_change(handle, narrow);
8540 assert_eq!(metrics.viewport(), narrow);
8541
8542 cx.update_window(handle, |_, window, _| {
8543 assert_eq!(metrics.viewport(), window.visual_viewport_bounds());
8544 assert_eq!(metrics.content_size(), window.viewport_size());
8546 })
8547 .unwrap();
8548 }
8549
8550 #[gpui::test]
8554 fn updating_a_window_from_within_its_own_update_reports_an_error(cx: &mut TestAppContext) {
8555 let window = cx.add_window(|_, _| EmptyView);
8556 let handle: AnyWindowHandle = window.into();
8557
8558 let nested_error = cx
8559 .update_window(handle, |_, _window, cx| {
8560 cx.update_window(handle, |_, _, _| ())
8561 .map_err(|error| error.to_string())
8562 .unwrap_err()
8563 })
8564 .expect("the outer update completes");
8565
8566 assert!(
8567 nested_error.contains("already being updated"),
8568 "unexpected error: {nested_error}"
8569 );
8570 }
8571
8572 #[gpui::test]
8575 fn a_window_can_be_updated_from_within_another_windows_update(cx: &mut TestAppContext) {
8576 let first: AnyWindowHandle = cx.add_window(|_, _| EmptyView).into();
8577 let second: AnyWindowHandle = cx.add_window(|_, _| EmptyView).into();
8578
8579 let expected = cx
8580 .update_window(second, |_, window, _| window.viewport_size())
8581 .expect("the window can be updated on its own");
8582
8583 let from_inner = cx
8584 .update_window(first, |_, _window, cx| {
8585 cx.update_window(second, |_, window, _| window.viewport_size())
8586 .expect("the inner update succeeds")
8587 })
8588 .expect("the outer update completes");
8589
8590 assert_eq!(from_inner, expected);
8591 }
8592
8593 #[gpui::test]
8596 fn metrics_handle_is_readable_from_another_thread(cx: &mut TestAppContext) {
8597 let window = cx.add_window(|_, _| EmptyView);
8598 let handle: AnyWindowHandle = window.into();
8599 cx.simulate_window_resize(handle, size(px(640.), px(480.)));
8600 let metrics = cx.read(|app| handle.metrics(app).expect("window is open"));
8601
8602 let (id, content_size, scale_factor) = std::thread::spawn(move || {
8603 (metrics.id(), metrics.content_size(), metrics.scale_factor())
8604 })
8605 .join()
8606 .expect("the metrics reader did not panic");
8607
8608 assert_eq!(id, handle.window_id());
8609 assert_eq!(content_size, size(px(640.), px(480.)));
8610 assert_eq!(scale_factor, 2.0);
8611 }
8612
8613 #[gpui::test]
8618 fn test_frame_waker_fires_on_frame_demand(cx: &mut TestAppContext) {
8619 let window = cx.add_window(|_, _| EmptyView);
8620 let test_window = cx.test_window(window.into());
8621
8622 assert!(
8626 test_window.frame_wake_count() >= 1,
8627 "opening a window must wake the frame source for the initial frame"
8628 );
8629
8630 test_window.simulate_frame_request(RequestFrameOptions::default());
8632
8633 let baseline = test_window.frame_wake_count();
8636 test_window.simulate_frame_request(RequestFrameOptions::default());
8637 window.update(cx, |_, _, _| {}).unwrap();
8638 assert_eq!(
8639 test_window.frame_wake_count(),
8640 baseline,
8641 "clean frames and non-notifying updates must not wake the frame source"
8642 );
8643
8644 window.update(cx, |_, _, cx| cx.notify()).unwrap();
8646 assert!(
8647 test_window.frame_wake_count() > baseline,
8648 "notifying a view in an idle window must wake the frame source"
8649 );
8650
8651 test_window.simulate_frame_request(RequestFrameOptions::default());
8653 let baseline = test_window.frame_wake_count();
8654 test_window.simulate_frame_request(RequestFrameOptions::default());
8655 assert_eq!(
8656 test_window.frame_wake_count(),
8657 baseline,
8658 "serving demand must return the window to idle"
8659 );
8660
8661 window
8663 .update(cx, |_, window, _| window.on_next_frame(|_, _| {}))
8664 .unwrap();
8665 assert!(
8666 test_window.frame_wake_count() > baseline,
8667 "scheduling a next-frame callback in an idle window must wake the frame source"
8668 );
8669 }
8670
8671 #[gpui::test]
8676 fn test_pending_next_frame_callbacks_are_not_stranded(cx: &mut TestAppContext) {
8677 let window = cx.add_window(|_, _| EmptyView);
8678 let test_window = cx.test_window(window.into());
8679 test_window.simulate_frame_request(RequestFrameOptions::default());
8682
8683 let callback_ran = Rc::new(Cell::new(false));
8684 window
8685 .update(cx, {
8686 let callback_ran = callback_ran.clone();
8687 move |_, window, _| {
8688 window.on_next_frame(move |_, _| callback_ran.set(true));
8689 }
8690 })
8691 .unwrap();
8692
8693 let baseline = test_window.frame_wake_count();
8694 test_window.simulate_frame_request(RequestFrameOptions::default());
8695 assert!(
8702 test_window.frame_wake_count() > baseline || callback_ran.get(),
8703 "a frame request with pending next-frame callbacks must either run them or re-arm the frame source"
8704 );
8705 }
8706
8707 #[gpui::test]
8708 fn test_window_reports_no_raw_handle_instead_of_panicking(cx: &mut TestAppContext) {
8709 use raw_window_handle::{HandleError, HasDisplayHandle as _, HasWindowHandle as _};
8710
8711 let window = cx.add_window(|_, _| EmptyView);
8712 window
8713 .update(cx, |_, window, _| {
8714 assert!(matches!(
8715 window.window_handle(),
8716 Err(HandleError::NotSupported)
8717 ));
8718 assert!(matches!(
8719 window.display_handle(),
8720 Err(HandleError::NotSupported)
8721 ));
8722 })
8723 .unwrap();
8724 }
8725
8726 #[gpui::test]
8727 fn test_appearance_change_runs_after_app_update(cx: &mut TestAppContext) {
8728 let window = cx.add_window(|_, _| EmptyView);
8729 let observed_appearance = Rc::new(Cell::new(None));
8730 let _subscription = window
8731 .update(cx, {
8732 let observed_appearance = observed_appearance.clone();
8733 move |_, window, _| {
8734 window.observe_window_appearance(move |window, _| {
8735 observed_appearance.set(Some(window.appearance()));
8736 })
8737 }
8738 })
8739 .unwrap();
8740 let test_window = cx.test_window(window.into());
8741
8742 cx.update(|_| {
8743 test_window.simulate_appearance_change(WindowAppearance::Dark);
8744 assert_eq!(observed_appearance.get(), None);
8745 });
8746 cx.run_until_parked();
8747
8748 assert_eq!(observed_appearance.get(), Some(WindowAppearance::Dark));
8749 }
8750
8751 #[gpui::test]
8752 fn queued_frame_callback_wakes_a_parked_render_loop(cx: &mut TestAppContext) {
8753 let window = cx.add_window(|_, _| Empty);
8754 let test_window = cx.test_window(window.into());
8755
8756 assert!(test_window.simulate_scheduled_frame());
8757 assert!(test_window.simulate_scheduled_frame());
8758 assert!(!test_window.frame_scheduled());
8759
8760 cx.update_window(window.into(), |_, window, _| {
8761 window.core.active.set(true);
8762 window.on_next_frame(|_, _| {});
8763 })
8764 .unwrap();
8765 assert!(
8766 test_window.frame_scheduled(),
8767 "queuing work on a parked window must wake the render loop"
8768 );
8769
8770 assert!(test_window.simulate_scheduled_frame());
8771 assert!(
8772 test_window.frame_scheduled(),
8773 "presenting the frame must await one compositor callback"
8774 );
8775 assert!(test_window.simulate_scheduled_frame());
8776 assert!(!test_window.frame_scheduled());
8777 }
8778
8779 #[gpui::test]
8780 fn pending_presentation_wakes_a_parked_render_loop(cx: &mut TestAppContext) {
8781 let window = cx.add_window(|_, _| Empty);
8782 let test_window = cx.test_window(window.into());
8783
8784 assert!(test_window.simulate_scheduled_frame());
8785 assert!(test_window.simulate_scheduled_frame());
8786 assert!(!test_window.frame_scheduled());
8787
8788 cx.update_window(window.into(), |_, window, cx| window.draw(cx).clear(cx))
8789 .unwrap();
8790
8791 assert!(
8792 test_window.frame_scheduled(),
8793 "a rendered scene awaiting presentation must wake the render loop"
8794 );
8795 }
8796
8797 #[gpui::test]
8798 fn callback_queued_during_a_frame_requests_a_follow_up(cx: &mut TestAppContext) {
8799 let window = cx.add_window(|_, _| Empty);
8800 let test_window = cx.test_window(window.into());
8801
8802 let callback_ran = Rc::new(Cell::new(false));
8803 cx.update_window(window.into(), |_, window, _| {
8804 window.core.active.set(true);
8807 let callback_ran = callback_ran.clone();
8808 window.on_next_frame(move |window, _| {
8809 window.on_next_frame(move |_, _| callback_ran.set(true));
8810 });
8811 })
8812 .unwrap();
8813
8814 assert!(test_window.simulate_scheduled_frame());
8815 assert!(!callback_ran.get());
8816 assert!(
8817 test_window.frame_scheduled(),
8818 "a callback queued mid-frame must schedule a follow-up before the loop parks"
8819 );
8820
8821 assert!(test_window.simulate_scheduled_frame());
8822 assert!(callback_ran.get());
8823 }
8824
8825 struct RootView {
8826 explicit_size: bool,
8827 child_bounds: Rc<Cell<Bounds<Pixels>>>,
8828 }
8829
8830 impl Render for RootView {
8831 fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
8832 let child_bounds = self.child_bounds.clone();
8833 let root = div().flex().flex_col().child(
8834 canvas(
8835 move |bounds, _, _| child_bounds.set(bounds),
8836 |_, _, _, _| {},
8837 )
8838 .size_full(),
8839 );
8840 if self.explicit_size {
8841 root.w(px(300.)).h(px(200.))
8842 } else {
8843 root
8844 }
8845 }
8846 }
8847
8848 #[test]
8849 fn auto_sized_window_root_fills_the_window() {
8850 let mut cx = TestAppContext::single();
8851 let child_bounds = Rc::new(Cell::new(Bounds::default()));
8852 let window = cx.add_window({
8853 let child_bounds = child_bounds.clone();
8854 move |_, _| RootView {
8855 explicit_size: false,
8856 child_bounds,
8857 }
8858 });
8859
8860 let viewport_size = cx
8861 .update_window(window.into(), |_, window, cx| {
8862 window.draw(cx).clear(cx);
8863 window.viewport_size()
8864 })
8865 .unwrap();
8866
8867 assert_eq!(child_bounds.get().size, viewport_size);
8868 }
8869
8870 #[test]
8871 fn explicitly_sized_window_root_keeps_its_size() {
8872 let mut cx = TestAppContext::single();
8873 let child_bounds = Rc::new(Cell::new(Bounds::default()));
8874 let window = cx.add_window({
8875 let child_bounds = child_bounds.clone();
8876 move |_, _| RootView {
8877 explicit_size: true,
8878 child_bounds,
8879 }
8880 });
8881
8882 cx.update_window(window.into(), |_, window, cx| {
8883 window.draw(cx).clear(cx);
8884 })
8885 .unwrap();
8886
8887 assert_eq!(child_bounds.get().size, size(px(300.), px(200.)));
8888 }
8889
8890 struct FileDragView {
8891 path: PathBuf,
8892 observed_drag_moves: Rc<RefCell<Vec<Point<Pixels>>>>,
8893 observed_drops: Rc<RefCell<Vec<PathBuf>>>,
8894 }
8895
8896 struct FileDropExitView(Rc<Cell<usize>>);
8897
8898 impl Render for FileDropExitView {
8899 fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
8900 div().size_full().on_file_drop_exit({
8901 let observed_file_drop_exit = self.0.clone();
8902 move |_, _, _| observed_file_drop_exit.set(observed_file_drop_exit.get() + 1)
8903 })
8904 }
8905 }
8906
8907 impl Render for FileDragView {
8908 fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
8909 div()
8910 .id("file-drag")
8911 .size_full()
8912 .on_drag(self.path.clone(), |_, _, _, cx| cx.new(|_| Empty))
8913 .external_drag_payload(|path: &PathBuf, _, _| {
8914 Some(ExternalDragPayload::Files(FileDragPaths::new([(
8915 path.clone(),
8916 true,
8917 )])))
8918 })
8919 .on_drag_move({
8920 let observed_drag_moves = self.observed_drag_moves.clone();
8921 move |event: &DragMoveEvent<PathBuf>, _, _| {
8922 observed_drag_moves.borrow_mut().push(event.event.position);
8923 }
8924 })
8925 .on_drop({
8926 let observed_drops = self.observed_drops.clone();
8927 move |path: &PathBuf, _, _| observed_drops.borrow_mut().push(path.clone())
8928 })
8929 }
8930 }
8931
8932 #[gpui::test]
8933 fn file_drag_is_promoted_once_and_restored_in_source_window(cx: &mut TestAppContext) {
8934 struct Drag {
8935 window: AnyWindowHandle,
8936 observed_drag_moves: Rc<RefCell<Vec<Point<Pixels>>>>,
8937 observed_drops: Rc<RefCell<Vec<PathBuf>>>,
8938 }
8939
8940 fn start_drag(cx: &mut TestAppContext, path: PathBuf, platform_result: bool) -> Drag {
8941 let observed_drag_moves = Rc::new(RefCell::new(Vec::new()));
8942 let observed_drops = Rc::new(RefCell::new(Vec::new()));
8943 let window: AnyWindowHandle = cx
8944 .add_window({
8945 let observed_drag_moves = observed_drag_moves.clone();
8946 let observed_drops = observed_drops.clone();
8947 move |_, _| FileDragView {
8948 path,
8949 observed_drag_moves,
8950 observed_drops,
8951 }
8952 })
8953 .into();
8954 cx.test_window(window)
8955 .set_start_external_drag_result(platform_result);
8956
8957 let update_result = cx.update_window(window, |_, window, cx| {
8958 window.draw(cx).clear(cx);
8959 window.dispatch_event(
8960 MouseDownEvent {
8961 position: point(px(10.), px(10.)),
8962 button: MouseButton::Left,
8963 modifiers: Default::default(),
8964 click_count: 1,
8965 first_mouse: false,
8966 }
8967 .to_platform_input(),
8968 cx,
8969 );
8970 window.dispatch_event(
8971 MouseMoveEvent {
8972 position: point(px(20.), px(20.)),
8973 pressed_button: Some(MouseButton::Left),
8974 modifiers: Default::default(),
8975 }
8976 .to_platform_input(),
8977 cx,
8978 );
8979 assert!(cx.active_drag.is_some());
8980 });
8981 assert!(
8982 update_result.is_ok(),
8983 "failed to start drag: {update_result:?}"
8984 );
8985
8986 assert!(cx.test_window(window).external_drag_files().is_empty());
8987 Drag {
8988 window,
8989 observed_drag_moves,
8990 observed_drops,
8991 }
8992 }
8993
8994 let successful_path = PathBuf::from("/tmp/successful-drag");
8995 let successful = start_drag(cx, successful_path.clone(), true);
8996 let outside_position = point(px(-1.), px(20.));
8997 let update_result = cx.update_window(successful.window, |_, window, cx| {
8998 window.dispatch_event(
8999 MouseMoveEvent {
9000 position: outside_position,
9001 pressed_button: Some(MouseButton::Left),
9002 modifiers: Default::default(),
9003 }
9004 .to_platform_input(),
9005 cx,
9006 );
9007 assert!(cx.active_drag.is_none());
9008 });
9009 assert!(
9010 update_result.is_ok(),
9011 "failed to promote drag: {update_result:?}"
9012 );
9013 assert_eq!(
9014 cx.test_window(successful.window).external_drag_files(),
9015 [(successful_path.clone(), true)]
9016 );
9017 assert_eq!(
9020 successful.observed_drag_moves.borrow().last(),
9021 Some(&outside_position)
9022 );
9023
9024 let first_destination_exit_count = Rc::new(Cell::new(0));
9025 let first_destination: AnyWindowHandle = cx
9026 .add_window({
9027 let first_destination_exit_count = first_destination_exit_count.clone();
9028 move |_, _| FileDropExitView(first_destination_exit_count)
9029 })
9030 .into();
9031 let second_destination_exit_count = Rc::new(Cell::new(0));
9032 let second_destination: AnyWindowHandle = cx
9033 .add_window({
9034 let second_destination_exit_count = second_destination_exit_count.clone();
9035 move |_, _| FileDropExitView(second_destination_exit_count)
9036 })
9037 .into();
9038 let reentry_position = point(px(30.), px(30.));
9039 let external_paths = || ExternalPaths([successful_path.clone()].into_iter().collect());
9040 let update_result = cx.update_window(first_destination, |_, window, cx| {
9041 window.draw(cx).clear(cx);
9042 window.dispatch_event(
9043 FileDropEvent::Entered {
9044 position: reentry_position,
9045 paths: external_paths(),
9046 }
9047 .to_platform_input(),
9048 cx,
9049 );
9050 assert!(
9051 cx.active_drag
9052 .as_ref()
9053 .is_some_and(|drag| drag.value.downcast_ref::<ExternalPaths>().is_some())
9054 );
9055 window.dispatch_event(FileDropEvent::Exited.to_platform_input(), cx);
9056 assert!(cx.active_drag.is_none());
9057 assert_eq!(first_destination_exit_count.get(), 1);
9058 assert_eq!(second_destination_exit_count.get(), 0);
9059 });
9060 assert!(
9061 update_result.is_ok(),
9062 "failed to handle drag in first destination window: {update_result:?}"
9063 );
9064
9065 let update_result = cx.update_window(second_destination, |_, window, cx| {
9066 window.draw(cx).clear(cx);
9067 window.dispatch_event(
9068 PlatformInput::KeyDown(KeyDownEvent {
9069 keystroke: Keystroke::parse("down").expect("valid keystroke"),
9070 is_held: false,
9071 prefer_character_input: false,
9072 }),
9073 cx,
9074 );
9075 window.dispatch_event(
9076 FileDropEvent::Entered {
9077 position: reentry_position,
9078 paths: external_paths(),
9079 }
9080 .to_platform_input(),
9081 cx,
9082 );
9083 assert!(
9084 cx.active_drag
9085 .as_ref()
9086 .is_some_and(|drag| drag.value.downcast_ref::<ExternalPaths>().is_some())
9087 );
9088 assert_eq!(first_destination_exit_count.get(), 1);
9089 assert_eq!(second_destination_exit_count.get(), 0);
9090
9091 window.dispatch_event(FileDropEvent::Exited.to_platform_input(), cx);
9092 assert!(cx.active_drag.is_none());
9093 assert_eq!(first_destination_exit_count.get(), 1);
9094 assert_eq!(second_destination_exit_count.get(), 1);
9095 });
9096 assert!(
9097 update_result.is_ok(),
9098 "failed to handle drag in second destination window: {update_result:?}"
9099 );
9100
9101 let update_result = cx.update_window(successful.window, |_, window, cx| {
9102 window.dispatch_event(
9103 FileDropEvent::Entered {
9104 position: reentry_position,
9105 paths: external_paths(),
9106 }
9107 .to_platform_input(),
9108 cx,
9109 );
9110 assert!(
9111 cx.active_drag
9112 .as_ref()
9113 .is_some_and(|drag| drag.value.downcast_ref::<PathBuf>().is_some())
9114 );
9115 assert_eq!(
9116 successful.observed_drag_moves.borrow().last(),
9117 Some(&reentry_position)
9118 );
9119
9120 window.dispatch_event(FileDropEvent::Exited.to_platform_input(), cx);
9121 assert!(cx.active_drag.is_none());
9122
9123 window.dispatch_event(
9124 FileDropEvent::Entered {
9125 position: reentry_position,
9126 paths: external_paths(),
9127 }
9128 .to_platform_input(),
9129 cx,
9130 );
9131 assert!(
9132 cx.active_drag
9133 .as_ref()
9134 .is_some_and(|drag| drag.value.downcast_ref::<PathBuf>().is_some())
9135 );
9136
9137 window.dispatch_event(
9138 FileDropEvent::Submit {
9139 position: reentry_position,
9140 }
9141 .to_platform_input(),
9142 cx,
9143 );
9144 assert_eq!(
9145 successful.observed_drops.borrow().as_slice(),
9146 std::slice::from_ref(&successful_path)
9147 );
9148 assert!(cx.active_drag.is_none());
9149
9150 window.dispatch_event(FileDropEvent::Exited.to_platform_input(), cx);
9151 assert!(cx.active_drag.is_none());
9152 window.dispatch_event(FileDropEvent::Ended.to_platform_input(), cx);
9153 assert!(cx.active_drag.is_none());
9154
9155 window.dispatch_event(
9156 FileDropEvent::Entered {
9157 position: reentry_position,
9158 paths: external_paths(),
9159 }
9160 .to_platform_input(),
9161 cx,
9162 );
9163 assert!(
9164 cx.active_drag
9165 .as_ref()
9166 .is_some_and(|drag| drag.value.downcast_ref::<ExternalPaths>().is_some())
9167 );
9168 window.dispatch_event(FileDropEvent::Exited.to_platform_input(), cx);
9169 });
9170 assert!(
9171 update_result.is_ok(),
9172 "failed to restore drag in source window: {update_result:?}"
9173 );
9174
9175 let cancelled_path = PathBuf::from("/tmp/cancelled-drag");
9176 let cancelled = start_drag(cx, cancelled_path.clone(), true);
9177 let update_result = cx.update_window(cancelled.window, |_, window, cx| {
9178 window.dispatch_event(
9179 MouseMoveEvent {
9180 position: outside_position,
9181 pressed_button: Some(MouseButton::Left),
9182 modifiers: Default::default(),
9183 }
9184 .to_platform_input(),
9185 cx,
9186 );
9187 assert!(cx.active_drag.is_none());
9188
9189 window.dispatch_event(
9190 FileDropEvent::Entered {
9191 position: reentry_position,
9192 paths: ExternalPaths([cancelled_path].into_iter().collect()),
9193 }
9194 .to_platform_input(),
9195 cx,
9196 );
9197 assert!(
9198 cx.active_drag
9199 .as_ref()
9200 .is_some_and(|drag| drag.value.downcast_ref::<PathBuf>().is_some())
9201 );
9202 assert!(cx.stop_active_drag(window));
9203 assert!(cx.active_drag.is_none());
9204 });
9205 assert!(
9206 update_result.is_ok(),
9207 "failed to cancel restored drag: {update_result:?}"
9208 );
9209 assert!(!cx.update(|cx| cx.end_platform_drag(cancelled.window.window_id())));
9210
9211 let removed_path = PathBuf::from("/tmp/removed-window-drag");
9212 let removed = start_drag(cx, removed_path, true);
9213 let removed_window_id = removed.window.window_id();
9214 let update_result = cx.update_window(removed.window, |_, window, cx| {
9215 window.dispatch_event(
9216 MouseMoveEvent {
9217 position: outside_position,
9218 pressed_button: Some(MouseButton::Left),
9219 modifiers: Default::default(),
9220 }
9221 .to_platform_input(),
9222 cx,
9223 );
9224 assert!(cx.active_drag.is_none());
9225 window.remove_window();
9226 });
9227 assert!(
9228 update_result.is_ok(),
9229 "failed to remove drag source window: {update_result:?}"
9230 );
9231 assert!(!cx.update(|cx| cx.end_platform_drag(removed_window_id)));
9232
9233 let failed_path = PathBuf::from("/tmp/failed-drag");
9234 let failed = start_drag(cx, failed_path.clone(), false);
9235 let update_result = cx.update_window(failed.window, |_, window, cx| {
9236 for x_position in [-1., -2.] {
9237 window.dispatch_event(
9238 MouseMoveEvent {
9239 position: point(px(x_position), px(20.)),
9240 pressed_button: Some(MouseButton::Left),
9241 modifiers: Default::default(),
9242 }
9243 .to_platform_input(),
9244 cx,
9245 );
9246 }
9247 assert!(cx.active_drag.is_some());
9248 });
9249 assert!(
9250 update_result.is_ok(),
9251 "failed to retain drag after platform failure: {update_result:?}"
9252 );
9253 assert_eq!(
9254 cx.test_window(failed.window).external_drag_files(),
9255 [(failed_path, true)]
9256 );
9257 }
9258
9259 struct FocusForwarder {
9260 a: FocusHandle,
9261 b: FocusHandle,
9262 }
9263
9264 impl Render for FocusForwarder {
9265 fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
9266 div()
9267 .size_full()
9268 .child(div().w(px(50.)).h(px(50.)).track_focus(&self.a))
9269 .child(div().w(px(50.)).h(px(50.)).track_focus(&self.b))
9270 }
9271 }
9272
9273 #[gpui::test]
9277 fn test_focus_moved_by_focus_listener_is_dispatched(cx: &mut TestAppContext) {
9278 let b_focus_count = Rc::new(Cell::new(0));
9279 let window = cx.add_window({
9280 let b_focus_count = b_focus_count.clone();
9281 move |window, cx| {
9282 let a = cx.focus_handle();
9283 let b = cx.focus_handle();
9284 cx.on_focus(&a, window, |this: &mut FocusForwarder, window, cx| {
9285 let b = this.b.clone();
9286 window.focus(&b, cx);
9287 })
9288 .detach();
9289 cx.on_focus(&b, window, move |_, _, _| {
9290 b_focus_count.set(b_focus_count.get() + 1);
9291 })
9292 .detach();
9293 FocusForwarder { a, b }
9294 }
9295 });
9296
9297 window
9298 .update(cx, |_, window, _| window.activate_window())
9299 .unwrap();
9300 cx.executor().run_until_parked();
9301
9302 window
9303 .update(cx, |this, window, cx| {
9304 let a = this.a.clone();
9305 window.focus(&a, cx);
9306 })
9307 .unwrap();
9308 cx.executor().run_until_parked();
9309
9310 window
9311 .update(cx, |this, window, _| {
9312 assert!(this.b.is_focused(window));
9313 })
9314 .unwrap();
9315 assert_eq!(b_focus_count.get(), 1);
9316 }
9317
9318 #[gpui::test]
9319 fn claimed_touch_drag_receives_movement_and_release(cx: &mut TestAppContext) {
9320 let events = Rc::new(RefCell::new(Vec::new()));
9321 let window = cx.add_window({
9322 let events = events.clone();
9323 move |_, _| TouchDragListener { events }
9324 });
9325 let touch = TouchId(1);
9326
9327 dispatch_touch(window, cx, touch, TouchPhase::Started, 10.);
9328 dispatch_touch(window, cx, touch, TouchPhase::Moved, 30.);
9329 dispatch_touch(window, cx, touch, TouchPhase::Ended, 40.);
9330
9331 assert_eq!(
9332 events.borrow().as_slice(),
9333 [
9334 (TouchPhase::Started, px(10.)),
9335 (TouchPhase::Moved, px(30.)),
9336 (TouchPhase::Ended, px(40.)),
9337 ]
9338 );
9339 }
9340
9341 struct TouchDragListener {
9342 events: Rc<RefCell<Vec<(TouchPhase, Pixels)>>>,
9343 }
9344
9345 impl Render for TouchDragListener {
9346 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
9347 let events = self.events.clone();
9348 canvas(
9349 |_, _, _| {},
9350 move |_, _, window, _| {
9351 window.on_mouse_event(move |event: &TouchDragEvent, phase, window, _cx| {
9352 if phase != DispatchPhase::Bubble {
9353 return;
9354 }
9355 events.borrow_mut().push((event.phase, event.position.x));
9356 if event.phase == TouchPhase::Started {
9357 window.prevent_default();
9358 }
9359 });
9360 },
9361 )
9362 }
9363 }
9364
9365 #[gpui::test]
9366 fn long_press_is_claimed_only_when_started_prevents_default(cx: &mut TestAppContext) {
9367 for response in [
9368 LongPressResponse::PreventDefault,
9369 LongPressResponse::StopPropagation,
9370 LongPressResponse::None,
9371 ] {
9372 let phases = Rc::new(RefCell::new(Vec::new()));
9373 let window = cx.add_window({
9374 let phases = phases.clone();
9375 move |_, _| LongPressListener { phases, response }
9376 });
9377 dispatch_touch(window, cx, TouchId(1), TouchPhase::Started, 0.);
9378 cx.executor().advance_clock(Duration::from_millis(501));
9379 cx.executor().run_until_parked();
9380 window
9381 .update(cx, |_, window, _| {
9382 assert_eq!(
9383 window.core.long_press_capture.is_some(),
9384 response == LongPressResponse::PreventDefault
9385 );
9386 })
9387 .unwrap();
9388 dispatch_touch(window, cx, TouchId(1), TouchPhase::Moved, 2.);
9389 dispatch_touch(window, cx, TouchId(1), TouchPhase::Ended, 2.);
9390 window
9391 .update(cx, |_, window, _| {
9392 assert!(window.core.long_press_capture.is_none());
9393 })
9394 .unwrap();
9395
9396 let phases = phases.borrow();
9397 if response == LongPressResponse::PreventDefault {
9398 assert_eq!(
9399 phases.as_slice(),
9400 [TouchPhase::Started, TouchPhase::Moved, TouchPhase::Ended]
9401 );
9402 } else {
9403 assert_eq!(phases.as_slice(), [TouchPhase::Started]);
9404 }
9405 }
9406 }
9407
9408 #[gpui::test]
9409 fn stale_default_prevention_does_not_claim_long_press(cx: &mut TestAppContext) {
9410 let phases = Rc::new(RefCell::new(Vec::new()));
9411 let window = cx.add_window({
9412 let phases = phases.clone();
9413 move |_, _| LongPressListener {
9414 phases,
9415 response: LongPressResponse::None,
9416 }
9417 });
9418 window
9419 .update(cx, |_, window, _| {
9420 window.prevent_default();
9421 })
9422 .unwrap();
9423
9424 dispatch_touch(window, cx, TouchId(1), TouchPhase::Started, 0.);
9425 cx.executor().advance_clock(Duration::from_millis(501));
9426 cx.executor().run_until_parked();
9427 dispatch_touch(window, cx, TouchId(1), TouchPhase::Moved, 2.);
9428
9429 assert_eq!(phases.borrow().as_slice(), [TouchPhase::Started]);
9430 }
9431
9432 #[gpui::test]
9433 fn resolved_touch_cancels_scheduled_long_press(cx: &mut TestAppContext) {
9434 for (phase, position) in [
9435 (TouchPhase::Ended, 0.),
9436 (TouchPhase::Cancelled, 0.),
9437 (TouchPhase::Moved, 20.),
9438 ] {
9439 let phases = Rc::new(RefCell::new(Vec::new()));
9440 let window = cx.add_window({
9441 let phases = phases.clone();
9442 move |_, _| LongPressListener {
9443 phases,
9444 response: LongPressResponse::PreventDefault,
9445 }
9446 });
9447 dispatch_touch(window, cx, TouchId(1), TouchPhase::Started, 0.);
9448 dispatch_touch(window, cx, TouchId(1), phase, position);
9449 cx.executor().advance_clock(Duration::from_millis(501));
9450 cx.executor().run_until_parked();
9451
9452 assert!(phases.borrow().is_empty(), "{phase:?} allowed long press");
9453 }
9454 }
9455
9456 #[gpui::test]
9457 fn stale_long_press_timer_cannot_affect_replacement_touch(cx: &mut TestAppContext) {
9458 let phases = Rc::new(RefCell::new(Vec::new()));
9459 let window = cx.add_window({
9460 let phases = phases.clone();
9461 move |_, _| LongPressListener {
9462 phases,
9463 response: LongPressResponse::PreventDefault,
9464 }
9465 });
9466 let first_touch = TouchId(1);
9467 dispatch_touch(window, cx, first_touch, TouchPhase::Started, 0.);
9468 cx.executor().advance_clock(Duration::from_millis(250));
9469 dispatch_touch(window, cx, first_touch, TouchPhase::Cancelled, 0.);
9470 dispatch_touch(window, cx, TouchId(2), TouchPhase::Started, 10.);
9471
9472 cx.executor().advance_clock(Duration::from_millis(251));
9473 cx.executor().run_until_parked();
9474 assert!(phases.borrow().is_empty());
9475
9476 cx.executor().advance_clock(Duration::from_millis(250));
9477 cx.executor().run_until_parked();
9478 assert_eq!(phases.borrow().as_slice(), [TouchPhase::Started]);
9479 }
9480
9481 #[derive(Clone, Copy, PartialEq)]
9482 enum LongPressResponse {
9483 PreventDefault,
9484 StopPropagation,
9485 None,
9486 }
9487
9488 struct LongPressListener {
9489 phases: Rc<RefCell<Vec<TouchPhase>>>,
9490 response: LongPressResponse,
9491 }
9492
9493 impl Render for LongPressListener {
9494 fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
9495 let entity = cx.entity();
9496 let phases = self.phases.clone();
9497 let response = self.response;
9498 canvas(
9499 |_, _, _| {},
9500 move |_, _, window, _| {
9501 window.on_mouse_event(move |event: &LongPressEvent, phase, window, cx| {
9502 if phase != DispatchPhase::Bubble {
9503 return;
9504 }
9505 phases.borrow_mut().push(event.phase);
9506 match response {
9507 LongPressResponse::PreventDefault => {
9508 window.capture_long_press(&entity);
9509 window.prevent_default();
9510 }
9511 LongPressResponse::StopPropagation => cx.stop_propagation(),
9512 LongPressResponse::None => {}
9513 }
9514 });
9515 },
9516 )
9517 }
9518 }
9519
9520 fn dispatch_touch<T: 'static>(
9521 window: crate::WindowHandle<T>,
9522 cx: &mut TestAppContext,
9523 id: TouchId,
9524 phase: TouchPhase,
9525 x: f32,
9526 ) {
9527 window
9528 .update(cx, |_, window, cx| {
9529 window.dispatch_event(
9530 TouchEvent {
9531 id,
9532 phase,
9533 position: point(px(x), px(0.)),
9534 predicted_position: None,
9535 force: None,
9536 }
9537 .to_platform_input(),
9538 cx,
9539 );
9540 })
9541 .unwrap();
9542 }
9543}