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, Context, Corners, CursorHideMode, CursorStyle, Decorations, DevicePixels,
11 DispatchActionListener, DispatchNodeId, DispatchTree, DisplayId, Edges, Effect, Entity,
12 EntityId, EventEmitter, FileDropEvent, FontId, Global, GlobalElementId, GlyphId, GpuSpecs,
13 Hsla, InputHandler, InputPreference, IsZero, KeyBinding, KeyContext, KeyDownEvent, KeyEvent,
14 Keystroke, KeystrokeEvent, LayoutId, LineLayoutIndex, Modifiers, ModifiersChangedEvent,
15 MonochromeSprite, MouseButton, MouseEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels,
16 PlatformAtlas, PlatformDisplay, PlatformInput, PlatformInputHandler, PlatformWindow, Point,
17 PolychromeSprite, Priority, PromptButton, PromptLevel, Quad, Render, RenderGlyphParams,
18 RenderImage, RenderImageParams, RenderSvgParams, Replay, ResizeEdge, SMOOTH_SVG_SCALE_FACTOR,
19 SUBPIXEL_VARIANTS_X, SUBPIXEL_VARIANTS_Y, ScaledPixels, Scene, Shadow, SharedString, Size,
20 StrikethroughStyle, Style, SubpixelSprite, SubscriberSet, Subscription, SystemWindowTab,
21 SystemWindowTabController, TabStopMap, TaffyLayoutEngine, Task, TextInputConfiguration,
22 TextInputStateChange, TextRenderingMode, TextStyle, TextStyleRefinement, ThermalState,
23 TransformationMatrix, Underline, UnderlineStyle, WindowAppearance, WindowBackgroundAppearance,
24 WindowBounds, WindowControls, WindowDecorations, WindowInsets, WindowOptions, WindowParams,
25 WindowTextSystem, WindowVisibility, point, prelude::*, px, rems, size, transparent_black,
26};
27
28use crate::gestures::{GestureTuning, RecognizedTouchGesture, TouchGestureRecognizer};
29use crate::interactive::TouchEvent;
30use anyhow::{Context as _, Result, anyhow};
31use collections::{FxHashMap, FxHashSet};
32use derive_more::{Deref, DerefMut};
33use futures::channel::oneshot;
34use gpui_util::post_inc;
35use gpui_util::{ResultExt, measure};
36use itertools::FoldWhile::{Continue, Done};
37use itertools::Itertools;
38#[cfg(any(target_os = "macos", target_os = "ios"))]
39use objc2_core_foundation::CFRetained;
40#[cfg(any(target_os = "macos", target_os = "ios"))]
41use objc2_core_video::CVPixelBuffer;
42use parking_lot::{RwLock, RwLockUpgradableReadGuard};
43use raw_window_handle::{HandleError, HasDisplayHandle, HasWindowHandle};
44use refineable::Refineable;
45use scheduler::Instant;
46use slotmap::SlotMap;
47use smallvec::SmallVec;
48use std::{
49 any::{Any, TypeId},
50 borrow::Cow,
51 cell::{Cell, RefCell},
52 cmp,
53 fmt::{Debug, Display},
54 hash::{Hash, Hasher},
55 marker::PhantomData,
56 mem,
57 ops::{DerefMut, Range},
58 rc::Rc,
59 sync::{
60 Arc, Weak,
61 atomic::{AtomicBool, AtomicUsize, Ordering::SeqCst},
62 },
63 thread::AccessError,
64 time::Duration,
65};
66use uuid::Uuid;
67
68pub(crate) mod a11y;
69mod prompts;
70
71pub use a11y::A11ySubtreeBuilder;
72
73use self::a11y::A11y;
74#[cfg(not(target_family = "wasm"))]
75use self::a11y::ROOT_NODE_ID;
76use crate::util::{
77 atomic_incr_if_not_zero, ceil_to_device_pixel, floor_to_device_pixel, round_half_toward_zero,
78 round_half_toward_zero_f64, round_stroke_to_device_pixel, round_to_device_pixel,
79};
80pub use prompts::*;
81
82pub const DEFAULT_WINDOW_SIZE: Size<Pixels> = size(px(1536.), px(1095.));
84
85pub const DEFAULT_ADDITIONAL_WINDOW_SIZE: Size<Pixels> = Size {
88 width: Pixels(900.),
89 height: Pixels(750.),
90};
91
92#[derive(Default, Copy, Clone, Debug, Eq, PartialEq)]
94pub enum DispatchPhase {
95 #[default]
100 Bubble,
101 Capture,
107}
108
109impl DispatchPhase {
110 #[inline]
112 pub fn bubble(self) -> bool {
113 self == DispatchPhase::Bubble
114 }
115
116 #[inline]
118 pub fn capture(self) -> bool {
119 self == DispatchPhase::Capture
120 }
121}
122
123struct WindowInvalidatorInner {
124 #[cfg(feature = "profiler")]
125 pub window_id: WindowId,
126 pub dirty: bool,
127 pub draw_phase: DrawPhase,
128 pub dirty_views: FxHashSet<EntityId>,
129 pub update_count: usize,
130 #[cfg(feature = "profiler")]
131 pub frame_dirty: FrameDirtyAccumulator,
132 pub platform_waker: Option<Rc<dyn Fn()>>,
133}
134
135#[cfg(feature = "profiler")]
141#[derive(Default)]
142struct FrameDirtyAccumulator {
143 dirty_at: Option<Instant>,
144 invalidations: u64,
145}
146
147#[derive(Clone, Copy)]
149enum FrameRateLimit {
150 Inactive,
152 Thermal,
154}
155
156#[derive(Clone)]
157pub(crate) struct WindowInvalidator {
158 inner: Rc<RefCell<WindowInvalidatorInner>>,
159}
160
161impl WindowInvalidator {
162 pub fn new(#[allow(unused_variables)] window_id: WindowId) -> Self {
163 WindowInvalidator {
164 inner: Rc::new(RefCell::new(WindowInvalidatorInner {
165 #[cfg(feature = "profiler")]
166 window_id,
167 dirty: true,
168 draw_phase: DrawPhase::None,
169 dirty_views: FxHashSet::default(),
170 update_count: 0,
171 #[cfg(feature = "profiler")]
172 frame_dirty: FrameDirtyAccumulator::default(),
173 platform_waker: None,
174 })),
175 }
176 }
177
178 pub fn invalidate_view(&self, entity: EntityId, cx: &mut App) -> bool {
179 let mut inner = self.inner.borrow_mut();
180 inner.update_count += 1;
181 inner.dirty_views.insert(entity);
182 if inner.draw_phase == DrawPhase::None {
183 #[cfg(feature = "profiler")]
184 let dirty_at = Self::record_frame_dirty(&mut inner);
185 let became_dirty = !inner.dirty;
186 inner.dirty = true;
187 let waker = became_dirty.then(|| inner.platform_waker.clone()).flatten();
188 #[cfg(feature = "profiler")]
189 let window_id = inner.window_id;
190 drop(inner);
191 #[cfg(feature = "profiler")]
192 if became_dirty {
193 profiler::journal::record_frame_pending(window_id, dirty_at);
194 }
195 cx.push_effect(Effect::Notify { emitter: entity });
196 if let Some(waker) = waker {
197 waker();
198 }
199 true
200 } else {
201 false
202 }
203 }
204
205 pub fn is_dirty(&self) -> bool {
206 self.inner.borrow().dirty
207 }
208
209 pub fn set_dirty(&self, dirty: bool) {
210 let mut inner = self.inner.borrow_mut();
211 let became_dirty = dirty && !inner.dirty;
212 inner.dirty = dirty;
213 if dirty {
214 inner.update_count += 1;
215 }
216 #[cfg(feature = "profiler")]
217 let dirty_at = dirty.then(|| Self::record_frame_dirty(&mut inner));
218 let waker = became_dirty.then(|| inner.platform_waker.clone()).flatten();
219 #[cfg(feature = "profiler")]
220 let window_id = inner.window_id;
221 drop(inner);
222 #[cfg(feature = "profiler")]
223 if became_dirty && let Some(dirty_at) = dirty_at {
224 profiler::journal::record_frame_pending(window_id, dirty_at);
225 }
226 if let Some(waker) = waker {
227 waker();
228 }
229 }
230
231 pub fn set_platform_waker(&self, waker: Option<Rc<dyn Fn()>>) {
232 let mut inner = self.inner.borrow_mut();
233 inner.platform_waker = waker;
234 let waker = inner.dirty.then(|| inner.platform_waker.clone()).flatten();
235 drop(inner);
236 if let Some(waker) = waker {
237 waker();
238 }
239 }
240
241 pub fn wake_platform(&self) {
245 let waker = self.inner.borrow().platform_waker.clone();
246 if let Some(waker) = waker {
247 waker();
248 }
249 }
250
251 pub fn set_phase(&self, phase: DrawPhase) {
252 self.inner.borrow_mut().draw_phase = phase
253 }
254
255 pub fn update_count(&self) -> usize {
256 self.inner.borrow().update_count
257 }
258
259 #[cfg(feature = "profiler")]
260 fn record_frame_dirty(inner: &mut WindowInvalidatorInner) -> Instant {
261 let dirty_at = *inner.frame_dirty.dirty_at.get_or_insert_with(Instant::now);
262 inner.frame_dirty.invalidations += 1;
263 dirty_at
264 }
265
266 #[cfg(feature = "profiler")]
267 fn take_frame_dirty(&self) -> FrameDirtyAccumulator {
268 mem::take(&mut self.inner.borrow_mut().frame_dirty)
269 }
270
271 pub fn take_views(&self) -> FxHashSet<EntityId> {
272 mem::take(&mut self.inner.borrow_mut().dirty_views)
273 }
274
275 pub fn replace_views(&self, views: FxHashSet<EntityId>) {
276 self.inner.borrow_mut().dirty_views = views;
277 }
278
279 pub fn not_drawing(&self) -> bool {
280 self.inner.borrow().draw_phase == DrawPhase::None
281 }
282
283 #[track_caller]
284 pub fn debug_assert_paint(&self) {
285 debug_assert!(
286 matches!(self.inner.borrow().draw_phase, DrawPhase::Paint),
287 "this method can only be called during paint"
288 );
289 }
290
291 #[track_caller]
292 pub fn debug_assert_prepaint(&self) {
293 debug_assert!(
294 matches!(self.inner.borrow().draw_phase, DrawPhase::Prepaint),
295 "this method can only be called during request_layout, or prepaint"
296 );
297 }
298
299 #[track_caller]
300 pub fn debug_assert_paint_or_prepaint(&self) {
301 debug_assert!(
302 matches!(
303 self.inner.borrow().draw_phase,
304 DrawPhase::Paint | DrawPhase::Prepaint
305 ),
306 "this method can only be called during request_layout, prepaint, or paint"
307 );
308 }
309}
310
311type AnyObserver = Box<dyn FnMut(&mut Window, &mut App) -> bool + 'static>;
312
313pub(crate) type AnyWindowFocusListener =
314 Box<dyn FnMut(&WindowFocusEvent, &mut Window, &mut App) -> bool + 'static>;
315
316pub(crate) struct WindowFocusEvent {
317 pub(crate) previous_focus_path: SmallVec<[FocusId; 8]>,
318 pub(crate) current_focus_path: SmallVec<[FocusId; 8]>,
319}
320
321impl WindowFocusEvent {
322 pub fn is_focus_in(&self, focus_id: FocusId) -> bool {
323 !self.previous_focus_path.contains(&focus_id) && self.current_focus_path.contains(&focus_id)
324 }
325
326 pub fn is_focus_out(&self, focus_id: FocusId) -> bool {
327 self.previous_focus_path.contains(&focus_id) && !self.current_focus_path.contains(&focus_id)
328 }
329}
330
331pub struct FocusOutEvent {
333 pub blurred: WeakFocusHandle,
335}
336
337slotmap::new_key_type! {
338 pub struct FocusId;
340}
341
342thread_local! {
343 pub(crate) static ELEMENT_ARENA: RefCell<Arena> = RefCell::new(Arena::new(1024 * 1024));
346
347 static CURRENT_ELEMENT_ARENA: Cell<Option<*const RefCell<Arena>>> = const { Cell::new(None) };
351}
352
353fn draw_in_progress() -> bool {
364 CURRENT_ELEMENT_ARENA.with(|current| current.get().is_some())
365}
366
367#[inline(always)]
370pub(crate) fn with_element_arena<R>(callback: impl FnOnce(&mut Arena) -> R) -> R {
371 let mut callback = Some(callback);
372 let mut result = None;
373 let access = with_element_arena_erased(&mut |arena| {
374 result = Some(callback.take().expect("arena callback runs once")(arena));
375 });
376 drop(callback);
377 access.expect("cannot access a Thread Local Storage value during or after destruction");
378 result.expect("arena callback produces a result")
379}
380
381pub(crate) struct ElementArenaScope {
396 entered: *const RefCell<Arena>,
399 previous: Option<*const RefCell<Arena>>,
400 exited: bool,
401}
402
403impl ElementArenaScope {
404 pub(crate) fn enter(arena: &RefCell<Arena>) -> Self {
406 arena.borrow_mut().begin_scope();
407 let previous = CURRENT_ELEMENT_ARENA.with(|current| {
408 let prev = current.get();
409 current.set(Some(arena as *const RefCell<Arena>));
410 prev
411 });
412 Self {
413 entered: arena as *const RefCell<Arena>,
414 previous,
415 exited: false,
416 }
417 }
418
419 pub(crate) fn exit(mut self, arena: &RefCell<Arena>) -> ArenaClearNeeded {
428 assert!(
429 std::ptr::eq(self.entered, arena),
430 "ElementArenaScope::exit called with a different arena than was entered"
431 );
432 self.exited = true;
433 ArenaClearNeeded::new(arena)
438 }
439}
440
441impl Drop for ElementArenaScope {
442 fn drop(&mut self) {
443 CURRENT_ELEMENT_ARENA.with(|current| {
450 current.set(self.previous);
451 });
452 unsafe { &*self.entered }.borrow_mut().end_scope();
456 if !self.exited && !std::thread::panicking() {
457 debug_assert!(false, "ElementArenaScope dropped without calling exit()");
458 log::error!(
459 "ElementArenaScope dropped without calling exit(); \
460 the arena clear for this draw was never requested"
461 );
462 }
463 }
464}
465
466#[must_use]
468pub struct ArenaClearNeeded {
469 arena: *const RefCell<Arena>,
472}
473
474impl ArenaClearNeeded {
475 fn new(arena: &RefCell<Arena>) -> Self {
478 Self {
479 arena: arena as *const RefCell<Arena>,
480 }
481 }
482
483 pub fn clear(self, cx: &mut App) {
492 assert!(
493 std::ptr::eq(self.arena, &cx.element_arena),
494 "ArenaClearNeeded::clear called with a different App than the draw ran against"
495 );
496 cx.element_arena.borrow_mut().clear();
497 }
498}
499
500#[derive(Default)]
501pub(crate) struct FocusMap {
502 pub(crate) handles: SlotMap<FocusId, FocusRef>,
503 pub(crate) dropped_handles: Vec<FocusId>,
504}
505
506pub(crate) struct FocusRef {
507 pub(crate) ref_count: AtomicUsize,
508 pub(crate) tab_index: isize,
509 pub(crate) tab_stop: bool,
510}
511
512impl FocusId {
513 pub fn is_focused(&self, window: &Window) -> bool {
515 window.focus == Some(*self)
516 }
517
518 pub fn contains_focused(&self, window: &Window, cx: &App) -> bool {
521 window
522 .focused(cx)
523 .is_some_and(|focused| self.contains(focused.id, window))
524 }
525
526 pub fn within_focused(&self, window: &Window, cx: &App) -> bool {
529 let focused = window.focused(cx);
530 focused.is_some_and(|focused| focused.id.contains(*self, window))
531 }
532
533 pub(crate) fn contains(&self, other: Self, window: &Window) -> bool {
535 window
536 .rendered_frame
537 .dispatch_tree
538 .focus_contains(*self, other)
539 }
540}
541
542pub struct FocusHandle {
544 pub(crate) id: FocusId,
545 handles: Arc<RwLock<FocusMap>>,
546 pub tab_index: isize,
548 pub tab_stop: bool,
550}
551
552impl std::fmt::Debug for FocusHandle {
553 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
554 f.write_fmt(format_args!("FocusHandle({:?})", self.id))
555 }
556}
557
558impl FocusHandle {
559 pub(crate) fn new(handles: &Arc<RwLock<FocusMap>>) -> Self {
560 let id = handles.write().handles.insert(FocusRef {
561 ref_count: AtomicUsize::new(1),
562 tab_index: 0,
563 tab_stop: false,
564 });
565
566 Self {
567 id,
568 tab_index: 0,
569 tab_stop: false,
570 handles: handles.clone(),
571 }
572 }
573
574 pub(crate) fn for_id(id: FocusId, handles: &Arc<RwLock<FocusMap>>) -> Option<Self> {
575 let lock = handles.read();
576 let focus = lock.handles.get(id)?;
577 if atomic_incr_if_not_zero(&focus.ref_count) == 0 {
578 return None;
579 }
580 Some(Self {
581 id,
582 tab_index: focus.tab_index,
583 tab_stop: focus.tab_stop,
584 handles: handles.clone(),
585 })
586 }
587
588 pub fn tab_index(mut self, index: isize) -> Self {
590 self.tab_index = index;
591 if let Some(focus) = self.handles.write().handles.get_mut(self.id) {
592 focus.tab_index = index;
593 }
594 self
595 }
596
597 pub fn tab_stop(mut self, tab_stop: bool) -> Self {
601 self.tab_stop = tab_stop;
602 if let Some(focus) = self.handles.write().handles.get_mut(self.id) {
603 focus.tab_stop = tab_stop;
604 }
605 self
606 }
607
608 pub fn downgrade(&self) -> WeakFocusHandle {
610 WeakFocusHandle {
611 id: self.id,
612 handles: Arc::downgrade(&self.handles),
613 }
614 }
615
616 pub fn focus(&self, window: &mut Window, cx: &mut App) {
618 window.focus(self, cx)
619 }
620
621 pub fn is_focused(&self, window: &Window) -> bool {
623 self.id.is_focused(window)
624 }
625
626 pub fn contains_focused(&self, window: &Window, cx: &App) -> bool {
629 self.id.contains_focused(window, cx)
630 }
631
632 pub fn within_focused(&self, window: &Window, cx: &mut App) -> bool {
635 self.id.within_focused(window, cx)
636 }
637
638 pub fn contains(&self, other: &Self, window: &Window) -> bool {
640 self.id.contains(other.id, window)
641 }
642
643 pub fn dispatch_action(&self, action: &dyn Action, window: &mut Window, cx: &mut App) {
645 if let Some(node_id) = window
646 .rendered_frame
647 .dispatch_tree
648 .focusable_node_id(self.id)
649 {
650 window.dispatch_action_on_node(node_id, action, cx)
651 }
652 }
653}
654
655impl Clone for FocusHandle {
656 fn clone(&self) -> Self {
657 Self::for_id(self.id, &self.handles).unwrap()
658 }
659}
660
661impl PartialEq for FocusHandle {
662 fn eq(&self, other: &Self) -> bool {
663 self.id == other.id
664 }
665}
666
667impl Eq for FocusHandle {}
668
669impl Drop for FocusHandle {
670 fn drop(&mut self) {
671 let handles = self.handles.upgradable_read();
672 let focus = handles.handles.get(self.id).expect("focus handle missing");
673 let previous_count = focus.ref_count.fetch_sub(1, SeqCst);
674 assert_ne!(previous_count, 0, "over-released focus handle");
675 if previous_count == 1 {
676 RwLockUpgradableReadGuard::upgrade(handles)
677 .dropped_handles
678 .push(self.id);
679 }
680 }
681}
682
683#[derive(Clone, Debug)]
685pub struct WeakFocusHandle {
686 pub(crate) id: FocusId,
687 pub(crate) handles: Weak<RwLock<FocusMap>>,
688}
689
690impl WeakFocusHandle {
691 pub fn upgrade(&self) -> Option<FocusHandle> {
693 let handles = self.handles.upgrade()?;
694 FocusHandle::for_id(self.id, &handles)
695 }
696}
697
698impl PartialEq for WeakFocusHandle {
699 fn eq(&self, other: &WeakFocusHandle) -> bool {
700 self.id == other.id
701 }
702}
703
704impl Eq for WeakFocusHandle {}
705
706impl PartialEq<FocusHandle> for WeakFocusHandle {
707 fn eq(&self, other: &FocusHandle) -> bool {
708 self.id == other.id
709 }
710}
711
712impl PartialEq<WeakFocusHandle> for FocusHandle {
713 fn eq(&self, other: &WeakFocusHandle) -> bool {
714 self.id == other.id
715 }
716}
717
718pub trait Focusable: 'static {
721 fn focus_handle(&self, cx: &App) -> FocusHandle;
723}
724
725impl<V: Focusable> Focusable for Entity<V> {
726 fn focus_handle(&self, cx: &App) -> FocusHandle {
727 self.read(cx).focus_handle(cx)
728 }
729}
730
731pub trait ManagedView: Focusable + EventEmitter<DismissEvent> + Render {}
734
735impl<M: Focusable + EventEmitter<DismissEvent> + Render> ManagedView for M {}
736
737pub struct DismissEvent;
739
740type FrameCallback = Box<dyn FnOnce(&mut Window, &mut App)>;
741
742pub(crate) type AnyMouseListener =
743 Box<dyn FnMut(&dyn Any, DispatchPhase, &mut Window, &mut App) + 'static>;
744
745#[derive(Clone)]
746pub(crate) struct CursorStyleRequest {
747 pub(crate) hitbox_id: Option<HitboxId>,
748 pub(crate) style: CursorStyle,
749}
750
751#[derive(Default, Eq, PartialEq)]
752pub(crate) struct HitTest {
753 pub(crate) ids: SmallVec<[HitboxId; 8]>,
754 pub(crate) hover_hitbox_count: usize,
755}
756
757#[derive(Clone, Copy, Debug, Eq, PartialEq)]
759pub enum WindowControlArea {
760 Drag,
762 Close,
764 Max,
766 Min,
768}
769
770#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
772pub struct HitboxId(u64);
773
774#[cfg(feature = "test-support")]
775impl HitboxId {
776 pub const fn placeholder() -> Self {
781 Self(0)
782 }
783}
784
785impl HitboxId {
786 pub fn is_hovered(self, window: &Window) -> bool {
793 if window.captured_hitbox == Some(self) {
795 return true;
796 }
797 if window.last_input_was_keyboard() {
798 return false;
799 }
800 self.hit_test(window)
801 }
802
803 pub(crate) fn is_hovered_ignoring_last_input(self, window: &Window) -> bool {
808 if window.captured_hitbox == Some(self) {
810 return true;
811 }
812 self.hit_test(window)
813 }
814
815 fn hit_test(self, window: &Window) -> bool {
816 let hit_test = &window.mouse_hit_test;
817 for id in hit_test.ids.iter().take(hit_test.hover_hitbox_count) {
818 if self == *id {
819 return true;
820 }
821 }
822 false
823 }
824
825 pub fn should_handle_scroll(self, window: &Window) -> bool {
830 window.mouse_hit_test.ids.contains(&self)
831 }
832
833 fn next(mut self) -> HitboxId {
834 HitboxId(self.0.wrapping_add(1))
835 }
836}
837
838#[derive(Clone, Debug, Deref)]
841pub struct Hitbox {
842 pub id: HitboxId,
844 #[deref]
846 pub bounds: Bounds<Pixels>,
847 pub content_mask: ContentMask<Pixels>,
849 pub behavior: HitboxBehavior,
851}
852
853impl Hitbox {
854 pub fn is_hovered(&self, window: &Window) -> bool {
871 self.id.is_hovered(window)
872 }
873
874 pub fn is_hovered_at(&self, position: Point<Pixels>, window: &Window) -> bool {
877 let hit_test = window.rendered_frame.hit_test(position);
878 hit_test
879 .ids
880 .iter()
881 .take(hit_test.hover_hitbox_count)
882 .any(|id| self.id == *id)
883 }
884
885 pub fn should_handle_scroll(&self, window: &Window) -> bool {
892 self.id.should_handle_scroll(window)
893 }
894}
895
896#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
898pub enum HitboxBehavior {
899 #[default]
901 Normal,
902
903 BlockMouse,
925
926 BlockMouseExceptScroll,
953}
954
955#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
957pub struct TooltipId(usize);
958
959impl TooltipId {
960 pub fn is_hovered(&self, window: &Window) -> bool {
962 window
963 .tooltip_bounds
964 .as_ref()
965 .is_some_and(|tooltip_bounds| {
966 tooltip_bounds.id == *self
967 && tooltip_bounds.bounds.contains(&window.mouse_position())
968 })
969 }
970}
971
972pub(crate) struct TooltipBounds {
973 id: TooltipId,
974 bounds: Bounds<Pixels>,
975}
976
977#[derive(Clone)]
978pub(crate) struct TooltipRequest {
979 id: TooltipId,
980 tooltip: AnyTooltip,
981}
982
983#[derive(Clone, Default)]
989pub(crate) struct ElementIdStack {
990 ids: SmallVec<[ElementId; 32]>,
991 hashes: SmallVec<[u64; 32]>,
992}
993
994impl ElementIdStack {
995 pub(crate) fn push(&mut self, id: ElementId) {
996 self.hashes.push(crate::extend_path_hash(self.hash(), &id));
997 self.ids.push(id);
998 }
999
1000 pub(crate) fn pop(&mut self) -> Option<ElementId> {
1001 self.hashes.pop();
1002 self.ids.pop()
1003 }
1004
1005 pub(crate) fn clear(&mut self) {
1006 self.ids.clear();
1007 self.hashes.clear();
1008 }
1009
1010 fn hash(&self) -> u64 {
1012 self.hashes
1013 .last()
1014 .copied()
1015 .unwrap_or(crate::EMPTY_PATH_HASH)
1016 }
1017
1018 pub(crate) fn global_id(&self) -> GlobalElementId {
1019 GlobalElementId::with_hash(&self.ids, self.hash())
1020 }
1021}
1022
1023impl std::ops::Deref for ElementIdStack {
1024 type Target = [ElementId];
1025
1026 fn deref(&self) -> &Self::Target {
1027 &self.ids
1028 }
1029}
1030
1031pub(crate) struct DeferredDraw {
1032 current_view: EntityId,
1033 priority: usize,
1034 parent_node: DispatchNodeId,
1035 element_id_stack: ElementIdStack,
1036 text_style_stack: Vec<TextStyleRefinement>,
1037 content_mask: Option<ContentMask<Pixels>>,
1038 rem_size: Pixels,
1039 element: Option<AnyElement>,
1040 absolute_offset: Point<Pixels>,
1041 prepaint_range: Range<PrepaintStateIndex>,
1042 paint_range: Range<PaintIndex>,
1043}
1044
1045pub(crate) struct Frame {
1046 pub(crate) focus: Option<FocusId>,
1047 pub(crate) window_active: bool,
1048 pub(crate) element_states: FxHashMap<(GlobalElementId, TypeId), ElementStateBox>,
1049 accessed_element_states: Vec<(GlobalElementId, TypeId)>,
1050 pub(crate) mouse_listeners: Vec<Option<AnyMouseListener>>,
1051 pub(crate) dispatch_tree: DispatchTree,
1052 pub(crate) scene: Scene,
1053 pub(crate) hitboxes: Vec<Hitbox>,
1054 pub(crate) window_control_hitboxes: Vec<(WindowControlArea, Hitbox)>,
1055 pub(crate) deferred_draws: Vec<DeferredDraw>,
1056 pub(crate) input_handlers: Vec<Option<PlatformInputHandler>>,
1057 pub(crate) tooltip_requests: Vec<Option<TooltipRequest>>,
1058 pub(crate) cursor_styles: Vec<CursorStyleRequest>,
1059 #[cfg(any(test, feature = "test-support"))]
1060 pub(crate) debug_bounds: FxHashMap<String, Bounds<Pixels>>,
1061 #[cfg(any(test, feature = "test-support"))]
1062 debug_bounds_records: Vec<(String, Bounds<Pixels>)>,
1063 #[cfg(any(feature = "inspector", debug_assertions))]
1064 pub(crate) next_inspector_instance_ids: FxHashMap<Rc<crate::InspectorElementPath>, usize>,
1065 #[cfg(any(feature = "inspector", debug_assertions))]
1066 pub(crate) inspector_hitboxes: FxHashMap<HitboxId, crate::InspectorElementId>,
1067 pub(crate) tab_stops: TabStopMap,
1068}
1069
1070#[derive(Clone, Default)]
1071pub(crate) struct PrepaintStateIndex {
1072 hitboxes_index: usize,
1073 tooltips_index: usize,
1074 deferred_draws_index: usize,
1075 dispatch_tree_index: usize,
1076 accessed_element_states_index: usize,
1077 line_layout_index: LineLayoutIndex,
1078}
1079
1080#[derive(Clone, Default)]
1081pub(crate) struct PaintIndex {
1082 scene_index: usize,
1083 #[cfg(any(test, feature = "test-support"))]
1084 debug_bounds_index: usize,
1085 mouse_listeners_index: usize,
1086 input_handlers_index: usize,
1087 cursor_styles_index: usize,
1088 accessed_element_states_index: usize,
1089 tab_handle_index: usize,
1090 line_layout_index: LineLayoutIndex,
1091}
1092
1093impl Frame {
1094 #[cfg(any(test, feature = "test-support"))]
1095 pub(crate) fn record_debug_bounds(&mut self, selector: String, bounds: Bounds<Pixels>) {
1096 self.debug_bounds.insert(selector.clone(), bounds);
1097 self.debug_bounds_records.push((selector, bounds));
1098 }
1099
1100 pub(crate) fn new(dispatch_tree: DispatchTree) -> Self {
1101 Frame {
1102 focus: None,
1103 window_active: false,
1104 element_states: FxHashMap::default(),
1105 accessed_element_states: Vec::new(),
1106 mouse_listeners: Vec::new(),
1107 dispatch_tree,
1108 scene: Scene::default(),
1109 hitboxes: Vec::new(),
1110 window_control_hitboxes: Vec::new(),
1111 deferred_draws: Vec::new(),
1112 input_handlers: Vec::new(),
1113 tooltip_requests: Vec::new(),
1114 cursor_styles: Vec::new(),
1115
1116 #[cfg(any(test, feature = "test-support"))]
1117 debug_bounds: FxHashMap::default(),
1118 #[cfg(any(test, feature = "test-support"))]
1119 debug_bounds_records: Vec::new(),
1120
1121 #[cfg(any(feature = "inspector", debug_assertions))]
1122 next_inspector_instance_ids: FxHashMap::default(),
1123
1124 #[cfg(any(feature = "inspector", debug_assertions))]
1125 inspector_hitboxes: FxHashMap::default(),
1126 tab_stops: TabStopMap::default(),
1127 }
1128 }
1129
1130 pub(crate) fn clear(&mut self) {
1131 self.element_states.clear();
1132 self.accessed_element_states.clear();
1133 self.mouse_listeners.clear();
1134 self.dispatch_tree.clear();
1135 self.scene.clear();
1136 self.input_handlers.clear();
1137 self.tooltip_requests.clear();
1138 self.cursor_styles.clear();
1139 self.hitboxes.clear();
1140 self.window_control_hitboxes.clear();
1141 self.deferred_draws.clear();
1142 self.tab_stops.clear();
1143 self.focus = None;
1144
1145 #[cfg(any(test, feature = "test-support"))]
1146 {
1147 self.debug_bounds.clear();
1148 self.debug_bounds_records.clear();
1149 }
1150
1151 #[cfg(any(feature = "inspector", debug_assertions))]
1152 {
1153 self.next_inspector_instance_ids.clear();
1154 self.inspector_hitboxes.clear();
1155 }
1156 }
1157
1158 pub(crate) fn cursor_style(&self, window: &Window) -> Option<CursorStyle> {
1159 self.cursor_styles
1160 .iter()
1161 .rev()
1162 .fold_while(None, |style, request| match request.hitbox_id {
1163 None => Done(Some(request.style)),
1164 Some(hitbox_id) => Continue(style.or_else(|| {
1165 hitbox_id
1166 .is_hovered_ignoring_last_input(window)
1167 .then_some(request.style)
1168 })),
1169 })
1170 .into_inner()
1171 }
1172
1173 pub(crate) fn hit_test(&self, position: Point<Pixels>) -> HitTest {
1174 let mut set_hover_hitbox_count = false;
1175 let mut hit_test = HitTest::default();
1176 for hitbox in self.hitboxes.iter().rev() {
1177 let bounds = hitbox.bounds.intersect(&hitbox.content_mask.bounds);
1178 if bounds.contains(&position) {
1179 hit_test.ids.push(hitbox.id);
1180 if !set_hover_hitbox_count
1181 && hitbox.behavior == HitboxBehavior::BlockMouseExceptScroll
1182 {
1183 hit_test.hover_hitbox_count = hit_test.ids.len();
1184 set_hover_hitbox_count = true;
1185 }
1186 if hitbox.behavior == HitboxBehavior::BlockMouse {
1187 break;
1188 }
1189 }
1190 }
1191 if !set_hover_hitbox_count {
1192 hit_test.hover_hitbox_count = hit_test.ids.len();
1193 }
1194 hit_test
1195 }
1196
1197 pub(crate) fn focus_path(&self) -> SmallVec<[FocusId; 8]> {
1198 self.focus
1199 .map(|focus_id| self.dispatch_tree.focus_path(focus_id))
1200 .unwrap_or_default()
1201 }
1202
1203 pub(crate) fn finish(&mut self, prev_frame: &mut Self) {
1204 for element_state_key in &self.accessed_element_states {
1205 if let Some((element_state_key, element_state)) =
1206 prev_frame.element_states.remove_entry(element_state_key)
1207 {
1208 self.element_states.insert(element_state_key, element_state);
1209 }
1210 }
1211
1212 self.scene.finish();
1213 }
1214}
1215
1216#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
1217enum InputModality {
1218 Mouse,
1219 Keyboard,
1220 Touch,
1221}
1222
1223pub struct Window {
1225 pub(crate) handle: AnyWindowHandle,
1226 pub(crate) invalidator: WindowInvalidator,
1227 pub(crate) removed: bool,
1228 pub(crate) platform_window: Box<dyn PlatformWindow>,
1229 pub(crate) display_id: Option<DisplayId>,
1230 pub(crate) display_observers: SubscriberSet<(), AnyObserver>,
1231 is_resizable: bool,
1232 is_minimizable: bool,
1233 sprite_atlas: Arc<dyn PlatformAtlas>,
1234 text_system: Arc<WindowTextSystem>,
1235 text_rendering_mode: Rc<Cell<TextRenderingMode>>,
1236 rem_size: Pixels,
1237 rem_size_override_stack: SmallVec<[Pixels; 8]>,
1242 pub(crate) viewport_size: Size<Pixels>,
1243 layout_engine: Option<TaffyLayoutEngine>,
1244 pub(crate) root: Option<AnyView>,
1245 pub(crate) element_id_stack: ElementIdStack,
1246 pub(crate) text_style_stack: Vec<TextStyleRefinement>,
1247 pub(crate) rendered_entity_stack: Vec<EntityId>,
1248 pub(crate) element_offset_stack: Vec<Point<Pixels>>,
1249 pub(crate) element_opacity: f32,
1250 pub(crate) content_mask_stack: Vec<ContentMask<Pixels>>,
1251 pub(crate) requested_autoscroll: Option<Bounds<Pixels>>,
1252 last_text_input_configuration: Option<TextInputConfiguration>,
1256 focused_text_input: Option<FocusId>,
1257 pub(crate) image_cache_stack: Vec<AnyImageCache>,
1258 pub(crate) rendered_frame: Frame,
1259 pub(crate) next_frame: Frame,
1260 next_hitbox_id: HitboxId,
1261 pub(crate) next_tooltip_id: TooltipId,
1262 pub(crate) tooltip_bounds: Option<TooltipBounds>,
1263 pub(crate) next_frame_callbacks: Rc<RefCell<Vec<FrameCallback>>>,
1264 pub(crate) dirty_views: FxHashSet<EntityId>,
1265 focus_listeners: SubscriberSet<(), AnyWindowFocusListener>,
1266 pub(crate) focus_lost_listeners: SubscriberSet<(), AnyObserver>,
1267 focus_lost_path: SmallVec<[FocusId; 8]>,
1268 default_prevented: bool,
1269 mouse_position: Point<Pixels>,
1270 mouse_hit_test: HitTest,
1271 modifiers: Modifiers,
1272 capslock: Capslock,
1273 scale_factor: f32,
1274 pub(crate) bounds_observers: SubscriberSet<(), AnyObserver>,
1275 appearance: WindowAppearance,
1276 pub(crate) appearance_observers: SubscriberSet<(), AnyObserver>,
1277 pub(crate) button_layout_observers: SubscriberSet<(), AnyObserver>,
1278 active: Rc<Cell<bool>>,
1279 visibility: WindowVisibility,
1280 pub(crate) visibility_observers:
1281 SubscriberSet<(), Box<dyn FnMut(WindowVisibility, &mut Window, &mut App) -> bool>>,
1282 hovered: Rc<Cell<bool>>,
1283 pub(crate) needs_present: Rc<Cell<bool>>,
1284 pub(crate) input_rate_tracker: Rc<RefCell<InputRateTracker>>,
1287 #[cfg(feature = "profiler")]
1288 pub(crate) window_profiler: profiler::WindowProfiler,
1289 last_input_modality: InputModality,
1290 touch_gestures: TouchGestureRecognizer,
1291 touch_prediction_enabled: bool,
1292 long_press_timer: Option<Task<()>>,
1293 long_press_capture: Option<EntityId>,
1294 pub(crate) refreshing: bool,
1295 pub(crate) activation_observers: SubscriberSet<(), AnyObserver>,
1296 pub(crate) focus: Option<FocusId>,
1297 focus_enabled: bool,
1298 pub(crate) focus_generation: u64,
1301 pending_input: Option<PendingInput>,
1302 pending_modifier: ModifierState,
1303 pub(crate) pending_input_observers: SubscriberSet<(), AnyObserver>,
1304 prompt: Option<RenderablePromptHandle>,
1305 pub(crate) client_inset: Option<Pixels>,
1306 captured_hitbox: Option<HitboxId>,
1309 #[cfg(any(feature = "inspector", debug_assertions))]
1310 inspector: Option<Entity<Inspector>>,
1311 #[cfg(feature = "profiler")]
1312 debug_frame_overlay: crate::debug_overlay::DebugFrameOverlay,
1313 pub(crate) a11y: A11y,
1314}
1315
1316#[derive(Clone, Debug, Default)]
1317struct ModifierState {
1318 modifiers: Modifiers,
1319 saw_other_input: bool,
1320}
1321
1322#[derive(Clone, Debug)]
1325pub(crate) struct InputRateTracker {
1326 timestamps: Vec<Instant>,
1327 window: Duration,
1328 inputs_per_second: u32,
1329 sustain_until: Instant,
1330 sustain_duration: Duration,
1331}
1332
1333impl Default for InputRateTracker {
1334 fn default() -> Self {
1335 Self {
1336 timestamps: Vec::new(),
1337 window: Duration::from_millis(100),
1338 inputs_per_second: 60,
1339 sustain_until: Instant::now(),
1340 sustain_duration: Duration::from_secs(1),
1341 }
1342 }
1343}
1344
1345impl InputRateTracker {
1346 pub fn record_input(&mut self) {
1347 let now = Instant::now();
1348 self.timestamps.push(now);
1349 self.prune_old_timestamps(now);
1350
1351 let min_events = self.inputs_per_second as u128 * self.window.as_millis() / 1000;
1352 if self.timestamps.len() as u128 >= min_events {
1353 self.sustain_until = now + self.sustain_duration;
1354 }
1355 }
1356
1357 pub fn is_high_rate(&self) -> bool {
1358 Instant::now() < self.sustain_until
1359 }
1360
1361 fn prune_old_timestamps(&mut self, now: Instant) {
1362 self.timestamps
1363 .retain(|&t| now.duration_since(t) <= self.window);
1364 }
1365}
1366
1367#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1368pub(crate) enum DrawPhase {
1369 None,
1370 Prepaint,
1371 Paint,
1372 Focus,
1373}
1374
1375pub(crate) const PENDING_INPUT_TIMEOUT: Duration = Duration::from_secs(1);
1376
1377pub struct PendingInputStatus<'a> {
1379 keystrokes: &'a [Keystroke],
1380 timeout: Option<PendingInputTimeoutStatus>,
1381}
1382
1383impl<'a> PendingInputStatus<'a> {
1384 pub fn keystrokes(&self) -> &'a [Keystroke] {
1386 self.keystrokes
1387 }
1388
1389 pub fn timeout(&self) -> Option<PendingInputTimeoutStatus> {
1391 self.timeout
1392 }
1393}
1394
1395#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1397pub struct PendingInputTimeoutStatus {
1398 duration: Duration,
1399 remaining: Duration,
1400 started_at: Option<Instant>,
1401 paused: bool,
1402}
1403
1404impl PendingInputTimeoutStatus {
1405 pub fn duration(&self) -> Duration {
1407 self.duration
1408 }
1409
1410 pub fn remaining(&self, cx: &App) -> Duration {
1412 self.started_at
1413 .map(|started_at| {
1414 self.remaining
1415 .saturating_sub(cx.background_executor().now() - started_at)
1416 })
1417 .unwrap_or(self.remaining)
1418 }
1419
1420 pub fn is_paused(&self) -> bool {
1422 self.paused
1423 }
1424}
1425
1426#[derive(Debug)]
1427struct PendingInputTimeout {
1428 duration: Duration,
1429 remaining: Duration,
1430 state: PendingInputTimeoutState,
1431}
1432
1433#[derive(Debug)]
1434enum PendingInputTimeoutState {
1435 Running { started_at: Instant, task: Task<()> },
1436 Paused { pause: PendingInputTimeoutPause },
1437}
1438
1439#[derive(Debug)]
1440struct PendingInputTimeoutPause {
1441 owner_id: EntityId,
1442 _release_subscription: Subscription,
1443}
1444
1445impl PendingInputTimeout {
1446 fn is_paused(&self) -> bool {
1447 matches!(&self.state, PendingInputTimeoutState::Paused { .. })
1448 }
1449
1450 fn pause(&mut self, pause: PendingInputTimeoutPause, now: Instant) -> bool {
1451 match std::mem::replace(&mut self.state, PendingInputTimeoutState::Paused { pause }) {
1452 PendingInputTimeoutState::Running { started_at, task } => {
1453 self.remaining = self.remaining.saturating_sub(now - started_at);
1454 drop(task);
1455 true
1456 }
1457 previous_state @ PendingInputTimeoutState::Paused { .. } => {
1458 self.state = previous_state;
1459 false
1460 }
1461 }
1462 }
1463
1464 fn pause_owner_id(&self) -> Option<EntityId> {
1465 match &self.state {
1466 PendingInputTimeoutState::Running { .. } => None,
1467 PendingInputTimeoutState::Paused { pause } => Some(pause.owner_id),
1468 }
1469 }
1470
1471 fn resume(&mut self, owner_id: EntityId, started_at: Instant, task: Task<()>) -> bool {
1472 match std::mem::replace(
1473 &mut self.state,
1474 PendingInputTimeoutState::Running { started_at, task },
1475 ) {
1476 PendingInputTimeoutState::Paused { pause } if pause.owner_id == owner_id => true,
1477 previous_state => {
1478 self.state = previous_state;
1479 false
1480 }
1481 }
1482 }
1483
1484 fn reset_duration(&mut self, duration: Duration) {
1485 self.duration = duration;
1486 self.remaining = duration;
1487 }
1488
1489 fn status(&self) -> PendingInputTimeoutStatus {
1490 let (started_at, paused) = match &self.state {
1491 PendingInputTimeoutState::Running { started_at, .. } => (Some(*started_at), false),
1492 PendingInputTimeoutState::Paused { .. } => (None, true),
1493 };
1494 PendingInputTimeoutStatus {
1495 duration: self.duration,
1496 remaining: self.remaining,
1497 started_at,
1498 paused,
1499 }
1500 }
1501}
1502
1503#[derive(Default, Debug)]
1504struct PendingInput {
1505 keystrokes: SmallVec<[Keystroke; 1]>,
1506 focus: Option<FocusId>,
1507 timeout: Option<PendingInputTimeout>,
1508}
1509
1510pub(crate) struct ElementStateBox {
1511 pub(crate) inner: Box<dyn Any>,
1512 #[cfg(debug_assertions)]
1513 pub(crate) type_name: &'static str,
1514}
1515
1516fn default_bounds(display_id: Option<DisplayId>, cx: &mut App) -> WindowBounds {
1517 let active_window_bounds = cx
1522 .active_window()
1523 .and_then(|w| w.update(cx, |_, window, _| window.window_bounds()).ok());
1524
1525 const CASCADE_OFFSET: f32 = 25.0;
1526
1527 let display = display_id
1528 .map(|id| cx.find_display(id))
1529 .unwrap_or_else(|| cx.primary_display());
1530
1531 let default_placement = || Bounds::new(point(px(0.), px(0.)), DEFAULT_WINDOW_SIZE);
1532
1533 let display_bounds = display
1535 .as_ref()
1536 .map(|d| d.visible_bounds())
1537 .unwrap_or_else(default_placement);
1538
1539 let (
1540 Bounds {
1541 origin: base_origin,
1542 size: base_size,
1543 },
1544 window_bounds_ctor,
1545 ): (_, fn(Bounds<Pixels>) -> WindowBounds) = match active_window_bounds {
1546 Some(bounds) => match bounds {
1547 WindowBounds::Windowed(bounds) => (bounds, WindowBounds::Windowed),
1548 WindowBounds::Maximized(bounds) => (bounds, WindowBounds::Maximized),
1549 WindowBounds::Fullscreen(bounds) => (bounds, WindowBounds::Fullscreen),
1550 },
1551 None => (
1552 display
1553 .as_ref()
1554 .map(|d| d.default_bounds())
1555 .unwrap_or_else(default_placement),
1556 WindowBounds::Windowed,
1557 ),
1558 };
1559
1560 let cascade_offset = point(px(CASCADE_OFFSET), px(CASCADE_OFFSET));
1561 let proposed_origin = base_origin + cascade_offset;
1562 let proposed_bounds = Bounds::new(proposed_origin, base_size);
1563
1564 let display_right = display_bounds.origin.x + display_bounds.size.width;
1565 let display_bottom = display_bounds.origin.y + display_bounds.size.height;
1566 let window_right = proposed_bounds.origin.x + proposed_bounds.size.width;
1567 let window_bottom = proposed_bounds.origin.y + proposed_bounds.size.height;
1568
1569 let fits_horizontally = window_right <= display_right;
1570 let fits_vertically = window_bottom <= display_bottom;
1571
1572 let final_origin = match (fits_horizontally, fits_vertically) {
1573 (true, true) => proposed_origin,
1574 (false, true) => point(display_bounds.origin.x, base_origin.y),
1575 (true, false) => point(base_origin.x, display_bounds.origin.y),
1576 (false, false) => display_bounds.origin,
1577 };
1578 window_bounds_ctor(Bounds::new(final_origin, base_size))
1579}
1580
1581impl Window {
1582 pub(crate) fn new(
1583 handle: AnyWindowHandle,
1584 options: WindowOptions,
1585 cx: &mut App,
1586 ) -> Result<Self> {
1587 let WindowOptions {
1588 window_bounds,
1589 titlebar,
1590 focus,
1591 show,
1592 kind,
1593 is_movable,
1594 app_owns_titlebar_drag,
1595 inactive_frame_interval,
1596 is_resizable,
1597 is_minimizable,
1598 display_id,
1599 window_background,
1600 app_id,
1601 window_min_size,
1602 window_decorations,
1603 #[cfg_attr(
1604 not(any(target_os = "linux", target_os = "freebsd")),
1605 allow(unused_variables)
1606 )]
1607 icon,
1608 #[cfg_attr(not(target_os = "macos"), allow(unused_variables))]
1609 tabbing_identifier,
1610 #[cfg_attr(not(target_os = "macos"), allow(unused_variables))]
1611 use_display_p3,
1612 } = options;
1613
1614 let initial_window_title = titlebar
1615 .as_ref()
1616 .and_then(|titlebar| titlebar.title.clone());
1617
1618 let window_bounds = window_bounds.unwrap_or_else(|| default_bounds(display_id, cx));
1619 let mut platform_window = cx.platform.open_window(
1620 handle,
1621 WindowParams {
1622 bounds: window_bounds.get_bounds(),
1623 titlebar,
1624 kind,
1625 is_movable,
1626 app_owns_titlebar_drag,
1627 is_resizable,
1628 is_minimizable,
1629 focus,
1630 show,
1631 display_id,
1632 window_min_size,
1633 app_id: app_id.clone(),
1634 icon,
1635 #[cfg(target_os = "macos")]
1636 tabbing_identifier,
1637 #[cfg(target_os = "macos")]
1638 use_display_p3,
1639 },
1640 )?;
1641
1642 let tab_bar_visible = platform_window.tab_bar_visible();
1643 SystemWindowTabController::init_visible(cx, tab_bar_visible);
1644 if let Some(tabs) = platform_window.tabbed_windows() {
1645 SystemWindowTabController::add_tab(cx, handle.window_id(), tabs);
1646 }
1647
1648 let display_id = platform_window.display().map(|display| display.id());
1649 let sprite_atlas = platform_window.sprite_atlas();
1650 let mouse_position = platform_window.mouse_position();
1651 let modifiers = platform_window.modifiers();
1652 let capslock = platform_window.capslock();
1653 let content_size = platform_window.content_size();
1654 let scale_factor = platform_window.scale_factor();
1655 let appearance = platform_window.appearance();
1656 let text_system = Arc::new(WindowTextSystem::new(cx.text_system().clone()));
1657 let invalidator = WindowInvalidator::new(handle.window_id());
1658 let active = Rc::new(Cell::new(platform_window.is_active()));
1659 let visibility = platform_window.visibility();
1660 #[cfg(feature = "profiler")]
1661 profiler::journal::record_window_visibility(handle.window_id(), visibility);
1662 let hovered = Rc::new(Cell::new(platform_window.is_hovered()));
1663 let needs_present = Rc::new(Cell::new(false));
1664 let next_frame_callbacks: Rc<RefCell<Vec<FrameCallback>>> = Default::default();
1665 let input_rate_tracker = Rc::new(RefCell::new(InputRateTracker::default()));
1666 let last_frame_time = Rc::new(Cell::new(None));
1667
1668 platform_window
1669 .request_decorations(window_decorations.unwrap_or(WindowDecorations::Server));
1670 platform_window.set_background_appearance(window_background);
1671
1672 match window_bounds {
1673 WindowBounds::Fullscreen(_) => platform_window.toggle_fullscreen(),
1674 WindowBounds::Maximized(_) => platform_window.zoom(),
1675 WindowBounds::Windowed(_) => {}
1676 }
1677
1678 let accessibility_force_disabled = cx.accessibility_force_disabled;
1679 let a11y_active_flag = Arc::new(AtomicBool::new(false));
1680
1681 #[cfg(not(target_family = "wasm"))]
1682 if !accessibility_force_disabled {
1683 let mut initial_root_node = accesskit::Node::new(accesskit::Role::Window);
1684 if let Some(title) = &initial_window_title {
1685 initial_root_node.set_label(title.to_string());
1686 }
1687 let initial_tree = accesskit::TreeUpdate {
1688 nodes: vec![(ROOT_NODE_ID, initial_root_node)],
1689 tree: Some(accesskit::Tree::new(ROOT_NODE_ID)),
1690 tree_id: accesskit::TreeId::ROOT,
1691 focus: ROOT_NODE_ID,
1692 };
1693 let (activation_sender, activation_receiver) = async_channel::unbounded::<()>();
1694 let (deactivation_sender, deactivation_receiver) = async_channel::unbounded::<()>();
1695 let (action_sender, action_receiver) =
1696 async_channel::unbounded::<accesskit::ActionRequest>();
1697
1698 platform_window.a11y_init(crate::A11yCallbacks {
1699 activation: {
1700 let active_flag = a11y_active_flag.clone();
1701 Box::new(move || {
1702 log::info!("Accessibility activated");
1703 active_flag.store(true, SeqCst);
1704 activation_sender.send_blocking(()).log_err();
1705 Some(initial_tree.clone())
1706 })
1707 },
1708 action: Box::new(move |request| {
1709 action_sender.send_blocking(request).log_err();
1710 }),
1711 deactivation: {
1712 let active_flag = a11y_active_flag.clone();
1713 Box::new(move || {
1714 log::info!("Accessibility deactivated");
1715 active_flag.store(false, SeqCst);
1716 deactivation_sender.send_blocking(()).log_err();
1717 })
1718 },
1719 });
1720
1721 let mut async_cx = cx.to_async();
1727 cx.foreground_executor()
1728 .spawn(async move {
1729 while activation_receiver.recv().await.is_ok() {
1730 handle
1731 .update(&mut async_cx, |_, window, _| window.refresh())
1732 .log_err();
1733 }
1734 })
1735 .detach();
1736
1737 let mut async_cx = cx.to_async();
1738 cx.foreground_executor()
1739 .spawn(async move {
1740 while deactivation_receiver.recv().await.is_ok() {
1741 handle
1742 .update(&mut async_cx, |_, window, _| window.refresh())
1743 .log_err();
1744 }
1745 })
1746 .detach();
1747
1748 let mut async_cx = cx.to_async();
1749 cx.foreground_executor()
1750 .spawn(async move {
1751 while let Ok(request) = action_receiver.recv().await {
1752 handle
1753 .update(&mut async_cx, |_, window, cx| {
1754 window.handle_a11y_action(request, cx);
1755 })
1756 .log_err();
1757 }
1758 })
1759 .detach();
1760 }
1761
1762 platform_window.on_close(Box::new({
1763 let window_id = handle.window_id();
1764 let mut cx = cx.to_async();
1765 move || {
1766 let _ = handle.update(&mut cx, |_, window, _| window.remove_window());
1767 let _ = cx.update(|cx| {
1768 SystemWindowTabController::remove_tab(cx, window_id);
1769 });
1770 }
1771 }));
1772 platform_window.on_request_frame(Box::new({
1773 let mut cx = cx.to_async();
1774 let invalidator = invalidator.clone();
1775 let active = active.clone();
1776 let needs_present = needs_present.clone();
1777 let next_frame_callbacks = next_frame_callbacks.clone();
1778 let input_rate_tracker = input_rate_tracker.clone();
1779 let mut deferred_force_render = false;
1780 move |request_frame_options| {
1781 #[cfg(feature = "profiler")]
1782 let (_foreground_turn, window_id) = {
1783 let foreground_turn = profiler::journal::foreground_turn();
1784 let window_id = handle.window_id();
1785 profiler::journal::record_platform_signal(profiler::journal::PlatformSignal {
1786 window_id,
1787 signal_at: request_frame_options.signal_at,
1788 handled_at: Instant::now(),
1789 source: request_frame_options.signal_source,
1790 });
1791 (foreground_turn, window_id)
1792 };
1793 if draw_in_progress() {
1809 log::debug!("deferring re-entrant window draw request");
1810 deferred_force_render |= request_frame_options.force_render;
1811 #[cfg(feature = "profiler")]
1812 profiler::journal::record_reentrant_frame_skipped(window_id, Instant::now());
1813 return;
1814 }
1815 let force_render =
1819 mem::take(&mut deferred_force_render) || request_frame_options.force_render;
1820
1821 let thermal_state = handle
1822 .update(&mut cx, |_, _, cx| cx.thermal_state())
1823 .log_err();
1824
1825 let min_frame_interval = if request_frame_options.require_presentation
1829 || (!request_frame_options.force_render
1830 && next_frame_callbacks.borrow().is_empty())
1831 {
1832 None
1833 } else if !active.get() && !input_rate_tracker.borrow_mut().is_high_rate() {
1834 inactive_frame_interval.map(|interval| (interval, FrameRateLimit::Inactive))
1835 } else if let Some(ThermalState::Critical | ThermalState::Serious) = thermal_state {
1836 Some((Duration::from_micros(16667), FrameRateLimit::Thermal))
1837 } else {
1838 None
1839 };
1840
1841 let now = Instant::now();
1842 #[cfg_attr(not(feature = "profiler"), expect(unused_variables))]
1843 if let Some((min_interval, limit)) = min_frame_interval {
1844 if let Some(last_frame) = last_frame_time.get()
1845 && now.duration_since(last_frame) < min_interval
1846 {
1847 deferred_force_render |= force_render;
1849 handle
1851 .update(&mut cx, |_, window, _| {
1852 window.platform_window.schedule_frame();
1853 })
1854 .log_err();
1855 invalidator.wake_platform();
1860 #[cfg(feature = "profiler")]
1861 profiler::journal::record_frame_skipped(
1862 window_id,
1863 Instant::now(),
1864 match limit {
1865 FrameRateLimit::Inactive => {
1866 profiler::journal::FrameSkipReason::InactiveFrameRateLimit
1867 }
1868 FrameRateLimit::Thermal => {
1869 profiler::journal::FrameSkipReason::ThermalFrameRateLimit
1870 }
1871 },
1872 );
1873 return;
1874 }
1875 }
1876 last_frame_time.set(Some(now));
1877
1878 let pending_next_frame_callbacks = next_frame_callbacks.take();
1879 if !pending_next_frame_callbacks.is_empty() {
1880 handle
1881 .update(&mut cx, |_, window, cx| {
1882 for callback in pending_next_frame_callbacks {
1883 callback(window, cx);
1884 }
1885 })
1886 .log_err();
1887 }
1888
1889 let needs_present = request_frame_options.require_presentation
1893 || needs_present.get()
1894 || input_rate_tracker.borrow_mut().is_high_rate();
1895
1896 let should_draw = invalidator.is_dirty() || force_render;
1897 if should_draw {
1898 measure("frame duration", || {
1899 handle
1900 .update(&mut cx, |_, window, cx| {
1901 #[cfg(feature = "profiler")]
1902 window
1903 .window_profiler
1904 .record_frame_signal(request_frame_options.signal_at);
1905 if force_render {
1906 window.refresh();
1909 }
1910 let arena_clear_needed = window.draw(cx);
1911 window.present();
1912 arena_clear_needed.clear(cx);
1913 })
1914 .log_err();
1915 })
1916 } else if needs_present {
1917 handle
1918 .update(&mut cx, |_, window, _| window.present())
1919 .log_err();
1920 }
1921
1922 handle
1923 .update(&mut cx, |_, window, _| {
1924 if window.invalidator.is_dirty()
1925 || !window.next_frame_callbacks.borrow().is_empty()
1926 {
1927 window.platform_window.schedule_frame();
1928 }
1929 })
1930 .log_err();
1931
1932 if invalidator.is_dirty() || !next_frame_callbacks.borrow().is_empty() {
1938 invalidator.wake_platform();
1939 }
1940 #[cfg(feature = "profiler")]
1941 if !should_draw {
1942 profiler::journal::record_frame_skipped(
1943 window_id,
1944 Instant::now(),
1945 profiler::journal::FrameSkipReason::NoRenderNeeded,
1946 );
1947 }
1948 }
1949 }));
1950 invalidator.set_platform_waker(platform_window.frame_waker());
1951 platform_window.on_visual_viewport_changed(Box::new({
1952 let mut cx = cx.to_async();
1953 move || {
1954 handle
1955 .update(&mut cx, |_, window, _| window.refresh())
1956 .log_err();
1957 }
1958 }));
1959 platform_window.on_insets_changed(Box::new({
1960 let mut cx = cx.to_async();
1961 move |_| {
1962 handle
1963 .update(&mut cx, |_, window, _| window.refresh())
1964 .log_err();
1965 }
1966 }));
1967 platform_window.on_resize(Box::new({
1968 let mut cx = cx.to_async();
1969 move |_, _| {
1970 handle
1971 .update(&mut cx, |_, window, cx| window.bounds_changed(cx))
1972 .log_err();
1973 }
1974 }));
1975 platform_window.on_moved(Box::new({
1976 let mut cx = cx.to_async();
1977 move || {
1978 handle
1979 .update(&mut cx, |_, window, cx| window.bounds_changed(cx))
1980 .log_err();
1981 }
1982 }));
1983 platform_window.on_display_changed(Box::new({
1984 let cx = cx.to_async();
1985 move || cx.update(|cx| Window::display_changed(handle, cx))
1986 }));
1987 platform_window.on_appearance_changed(Box::new({
1988 let cx = cx.to_async();
1989 let foreground_executor = cx.foreground_executor().clone();
1990 move || {
1991 let mut cx = cx.clone();
1992 foreground_executor
1995 .spawn(async move {
1996 handle
1997 .update(&mut cx, |_, window, cx| window.appearance_changed(cx))
1998 .log_err();
1999 })
2000 .detach();
2001 }
2002 }));
2003 platform_window.on_button_layout_changed(Box::new({
2004 let mut cx = cx.to_async();
2005 move || {
2006 handle
2007 .update(&mut cx, |_, window, cx| window.button_layout_changed(cx))
2008 .log_err();
2009 }
2010 }));
2011 platform_window.on_active_status_change(Box::new({
2012 let mut cx = cx.to_async();
2013 move |active| {
2014 handle
2015 .update(&mut cx, |_, window, cx| {
2016 window.active.set(active);
2017 window.modifiers = window.platform_window.modifiers();
2018 window.capslock = window.platform_window.capslock();
2019 window
2020 .activation_observers
2021 .clone()
2022 .retain(&(), |callback| callback(window, cx));
2023
2024 window.bounds_changed(cx);
2025 window.refresh();
2026
2027 SystemWindowTabController::update_last_active(cx, window.handle.id);
2028 })
2029 .log_err();
2030 }
2031 }));
2032 platform_window.on_visibility_change(Box::new({
2033 let mut cx = cx.to_async();
2034 move |_| {
2035 handle
2036 .update(&mut cx, |_, window, cx| {
2037 window.refresh_visibility(cx);
2038 })
2039 .log_err();
2040 }
2041 }));
2042 platform_window.on_hover_status_change(Box::new({
2043 let mut cx = cx.to_async();
2044 move |active| {
2045 handle
2046 .update(&mut cx, |_, window, _| {
2047 window.hovered.set(active);
2048 window.refresh();
2049 })
2050 .log_err();
2051 }
2052 }));
2053 platform_window.on_input({
2054 let mut cx = cx.to_async();
2055 Box::new(move |event| {
2056 handle
2057 .update(&mut cx, |_, window, cx| window.dispatch_event(event, cx))
2058 .log_err()
2059 .unwrap_or(DispatchEventResult::default())
2060 })
2061 });
2062 platform_window.on_hit_test_window_control({
2063 let mut cx = cx.to_async();
2064 Box::new(move || {
2065 handle
2066 .update(&mut cx, |_, window, _cx| {
2067 for (area, hitbox) in &window.rendered_frame.window_control_hitboxes {
2068 if window.mouse_hit_test.ids.contains(&hitbox.id) {
2069 return Some(*area);
2070 }
2071 }
2072 None
2073 })
2074 .log_err()
2075 .unwrap_or(None)
2076 })
2077 });
2078 platform_window.on_move_tab_to_new_window({
2079 let mut cx = cx.to_async();
2080 Box::new(move || {
2081 handle
2082 .update(&mut cx, |_, _window, cx| {
2083 SystemWindowTabController::move_tab_to_new_window(cx, handle.window_id());
2084 })
2085 .log_err();
2086 })
2087 });
2088 platform_window.on_merge_all_windows({
2089 let mut cx = cx.to_async();
2090 Box::new(move || {
2091 handle
2092 .update(&mut cx, |_, _window, cx| {
2093 SystemWindowTabController::merge_all_windows(cx, handle.window_id());
2094 })
2095 .log_err();
2096 })
2097 });
2098 platform_window.on_select_next_tab({
2099 let mut cx = cx.to_async();
2100 Box::new(move || {
2101 handle
2102 .update(&mut cx, |_, _window, cx| {
2103 SystemWindowTabController::select_next_tab(cx, handle.window_id());
2104 })
2105 .log_err();
2106 })
2107 });
2108 platform_window.on_select_previous_tab({
2109 let mut cx = cx.to_async();
2110 Box::new(move || {
2111 handle
2112 .update(&mut cx, |_, _window, cx| {
2113 SystemWindowTabController::select_previous_tab(cx, handle.window_id())
2114 })
2115 .log_err();
2116 })
2117 });
2118 platform_window.on_toggle_tab_bar({
2119 let mut cx = cx.to_async();
2120 Box::new(move || {
2121 handle
2122 .update(&mut cx, |_, window, cx| {
2123 let tab_bar_visible = window.platform_window.tab_bar_visible();
2124 SystemWindowTabController::set_visible(cx, tab_bar_visible);
2125 })
2126 .log_err();
2127 })
2128 });
2129
2130 if let Some(app_id) = app_id {
2131 platform_window.set_app_id(&app_id);
2132 }
2133
2134 platform_window.map_window().unwrap();
2135
2136 Ok(Window {
2137 handle,
2138 invalidator,
2139 removed: false,
2140 platform_window,
2141 display_id,
2142 display_observers: SubscriberSet::new(),
2143 is_resizable,
2144 is_minimizable,
2145 sprite_atlas,
2146 text_system,
2147 text_rendering_mode: cx.text_rendering_mode.clone(),
2148 rem_size: px(16.),
2149 rem_size_override_stack: SmallVec::new(),
2150 viewport_size: content_size,
2151 layout_engine: Some(TaffyLayoutEngine::new()),
2152 root: None,
2153 element_id_stack: ElementIdStack::default(),
2154 text_style_stack: Vec::new(),
2155 rendered_entity_stack: Vec::new(),
2156 element_offset_stack: Vec::new(),
2157 content_mask_stack: Vec::new(),
2158 element_opacity: 1.0,
2159 requested_autoscroll: None,
2160 last_text_input_configuration: None,
2161 focused_text_input: None,
2162 rendered_frame: Frame::new(DispatchTree::new(cx.keymap.clone(), cx.actions.clone())),
2163 next_frame: Frame::new(DispatchTree::new(cx.keymap.clone(), cx.actions.clone())),
2164 next_frame_callbacks,
2165 next_hitbox_id: HitboxId(0),
2166 next_tooltip_id: TooltipId::default(),
2167 tooltip_bounds: None,
2168 dirty_views: FxHashSet::default(),
2169 focus_listeners: SubscriberSet::new(),
2170 focus_lost_listeners: SubscriberSet::new(),
2171 focus_lost_path: SmallVec::new(),
2172 default_prevented: true,
2173 mouse_position,
2174 mouse_hit_test: HitTest::default(),
2175 modifiers,
2176 capslock,
2177 scale_factor,
2178 bounds_observers: SubscriberSet::new(),
2179 appearance,
2180 appearance_observers: SubscriberSet::new(),
2181 button_layout_observers: SubscriberSet::new(),
2182 active,
2183 visibility,
2184 visibility_observers: SubscriberSet::new(),
2185 hovered,
2186 needs_present,
2187 input_rate_tracker,
2188 #[cfg(feature = "profiler")]
2189 window_profiler: profiler::WindowProfiler::new(handle.window_id())?,
2190 last_input_modality: InputModality::Mouse,
2191 touch_gestures: TouchGestureRecognizer::new(
2192 cx.platform
2193 .gestures()
2194 .map_or_else(GestureTuning::default, |gestures| gestures.tuning()),
2195 ),
2196 touch_prediction_enabled: true,
2197 long_press_timer: None,
2198 long_press_capture: None,
2199 refreshing: false,
2200 activation_observers: SubscriberSet::new(),
2201 focus: None,
2202 focus_enabled: true,
2203 focus_generation: 0,
2204 pending_input: None,
2205 pending_modifier: ModifierState::default(),
2206 pending_input_observers: SubscriberSet::new(),
2207 prompt: None,
2208 client_inset: None,
2209 image_cache_stack: Vec::new(),
2210 captured_hitbox: None,
2211 #[cfg(any(feature = "inspector", debug_assertions))]
2212 inspector: None,
2213 #[cfg(feature = "profiler")]
2214 debug_frame_overlay: crate::debug_overlay::DebugFrameOverlay::new(),
2215 a11y: A11y::new(
2216 a11y_active_flag,
2217 accessibility_force_disabled,
2218 initial_window_title,
2219 ),
2220 })
2221 }
2222
2223 pub(crate) fn new_focus_listener(
2224 &self,
2225 value: AnyWindowFocusListener,
2226 ) -> (Subscription, impl FnOnce() + use<>) {
2227 self.focus_listeners.insert((), value)
2228 }
2229}
2230
2231#[derive(Clone, Debug, Default, PartialEq, Eq)]
2232#[expect(missing_docs)]
2233pub struct DispatchEventResult {
2234 pub propagate: bool,
2235 pub default_prevented: bool,
2236}
2237
2238#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
2242#[repr(C)]
2243pub struct ContentMask<P: Clone + Debug + Default + PartialEq> {
2244 pub bounds: Bounds<P>,
2246}
2247
2248impl ContentMask<Pixels> {
2249 pub fn scale(&self, factor: f32) -> ContentMask<ScaledPixels> {
2251 ContentMask {
2252 bounds: self.bounds.scale(factor),
2253 }
2254 }
2255
2256 pub fn intersect(&self, other: &Self) -> Self {
2258 let bounds = self.bounds.intersect(&other.bounds);
2259 ContentMask { bounds }
2260 }
2261}
2262
2263impl Window {
2264 fn mark_view_dirty(&mut self, view_id: EntityId) {
2265 for view_id in self
2268 .rendered_frame
2269 .dispatch_tree
2270 .view_path_reversed(view_id)
2271 {
2272 if !self.dirty_views.insert(view_id) {
2273 break;
2274 }
2275 }
2276 }
2277
2278 pub(crate) fn refresh_visibility(&mut self, cx: &mut App) {
2279 let visibility = self.platform_window.visibility();
2280 if self.visibility != visibility {
2281 self.visibility = visibility;
2282 #[cfg(feature = "profiler")]
2283 profiler::journal::record_window_visibility(self.handle.window_id(), visibility);
2284 self.visibility_observers
2285 .clone()
2286 .retain(&(), |callback| callback(visibility, self, cx));
2287 }
2288 #[cfg(feature = "profiler")]
2289 if self.invalidator.is_dirty() || self.needs_present.get() {
2290 profiler::journal::record_frame_pending(self.handle.window_id(), Instant::now());
2291 }
2292 }
2293
2294 pub fn visibility(&self) -> WindowVisibility {
2297 self.visibility
2298 }
2299
2300 pub fn is_visible(&self) -> bool {
2306 self.visibility.is_visible()
2307 }
2308
2309 pub fn observe_window_visibility(
2311 &self,
2312 mut callback: impl FnMut(WindowVisibility, &mut Window, &mut App) + 'static,
2313 ) -> Subscription {
2314 let (subscription, activate) = self.visibility_observers.insert(
2315 (),
2316 Box::new(move |visibility, window, cx| {
2317 callback(visibility, window, cx);
2318 true
2319 }),
2320 );
2321 activate();
2322 subscription
2323 }
2324
2325 pub fn observe_window_appearance(
2327 &self,
2328 mut callback: impl FnMut(&mut Window, &mut App) + 'static,
2329 ) -> Subscription {
2330 let (subscription, activate) = self.appearance_observers.insert(
2331 (),
2332 Box::new(move |window, cx| {
2333 callback(window, cx);
2334 true
2335 }),
2336 );
2337 activate();
2338 subscription
2339 }
2340
2341 pub fn observe_button_layout_changed(
2343 &self,
2344 mut callback: impl FnMut(&mut Window, &mut App) + 'static,
2345 ) -> Subscription {
2346 let (subscription, activate) = self.button_layout_observers.insert(
2347 (),
2348 Box::new(move |window, cx| {
2349 callback(window, cx);
2350 true
2351 }),
2352 );
2353 activate();
2354 subscription
2355 }
2356
2357 pub fn replace_root<E>(
2359 &mut self,
2360 cx: &mut App,
2361 build_view: impl FnOnce(&mut Window, &mut Context<E>) -> E,
2362 ) -> Entity<E>
2363 where
2364 E: 'static + Render,
2365 {
2366 let view = cx.new(|cx| build_view(self, cx));
2367 self.root = Some(view.clone().into());
2368 self.refresh();
2369 view
2370 }
2371
2372 pub fn root<E>(&self) -> Option<Option<Entity<E>>>
2374 where
2375 E: 'static + Render,
2376 {
2377 self.root
2378 .as_ref()
2379 .map(|view| view.clone().downcast::<E>().ok())
2380 }
2381
2382 pub fn window_handle(&self) -> AnyWindowHandle {
2384 self.handle
2385 }
2386
2387 pub fn refresh(&mut self) {
2389 if self.invalidator.not_drawing() {
2390 self.refreshing = true;
2391 self.invalidator.set_dirty(true);
2392 }
2393 }
2394
2395 pub fn remove_window(&mut self) {
2397 self.removed = true;
2398 }
2399
2400 pub fn focused(&self, cx: &App) -> Option<FocusHandle> {
2402 self.focus
2403 .and_then(|id| FocusHandle::for_id(id, &cx.focus_handles))
2404 }
2405
2406 pub fn focus_lost_restore_target(&self, cx: &App) -> Option<FocusHandle> {
2410 let (_leaf, ancestors) = self.focus_lost_path.split_last()?;
2411 ancestors.iter().rev().find_map(|id| {
2412 self.rendered_frame.dispatch_tree.focusable_node_id(*id)?;
2413 FocusHandle::for_id(*id, &cx.focus_handles)
2414 })
2415 }
2416
2417 pub fn focus(&mut self, handle: &FocusHandle, cx: &mut App) {
2419 if !self.focus_enabled || self.focus == Some(handle.id) {
2420 return;
2421 }
2422
2423 self.focus = Some(handle.id);
2424 self.focus_generation = self.focus_generation.wrapping_add(1);
2425 self.clear_pending_keystrokes(cx);
2426
2427 self.refresh();
2428 }
2429
2430 pub fn blur(&mut self, cx: &mut App) {
2432 self.clear_pending_keystrokes(cx);
2433
2434 if !self.focus_enabled {
2435 return;
2436 }
2437
2438 if self.focus.is_some() {
2439 self.focus_generation = self.focus_generation.wrapping_add(1);
2440 }
2441 self.focus = None;
2442 self.refresh();
2443 }
2444
2445 pub fn disable_focus(&mut self, cx: &mut App) {
2447 self.blur(cx);
2448 self.focus_enabled = false;
2449 }
2450
2451 pub fn focus_next(&mut self, cx: &mut App) {
2453 if !self.focus_enabled {
2454 return;
2455 }
2456
2457 if let Some(handle) = self.rendered_frame.tab_stops.next(self.focus.as_ref()) {
2458 self.focus(&handle, cx)
2459 }
2460 }
2461
2462 pub fn focus_prev(&mut self, cx: &mut App) {
2464 if !self.focus_enabled {
2465 return;
2466 }
2467
2468 if let Some(handle) = self.rendered_frame.tab_stops.prev(self.focus.as_ref()) {
2469 self.focus(&handle, cx)
2470 }
2471 }
2472
2473 pub fn text_system(&self) -> &Arc<WindowTextSystem> {
2475 &self.text_system
2476 }
2477
2478 pub fn text_style(&self) -> TextStyle {
2480 let mut style = TextStyle::default();
2481 for refinement in &self.text_style_stack {
2482 style.refine(refinement);
2483 }
2484 style
2485 }
2486
2487 pub fn is_maximized(&self) -> bool {
2491 self.platform_window.is_maximized()
2492 }
2493
2494 pub fn request_decorations(&self, decorations: WindowDecorations) {
2496 self.platform_window.request_decorations(decorations);
2497 }
2498
2499 pub fn set_exclusive_zone(&self, zone: Pixels) {
2505 self.platform_window.set_exclusive_zone(zone);
2506 }
2507
2508 #[cfg(all(target_os = "linux", feature = "wayland"))]
2513 pub fn set_exclusive_edge(&self, edge: crate::layer_shell::Anchor) {
2514 self.platform_window.set_exclusive_edge(edge);
2515 }
2516
2517 pub fn start_window_resize(&self, edge: ResizeEdge) {
2519 if self.is_resizable {
2520 self.platform_window.start_window_resize(edge);
2521 }
2522 }
2523
2524 pub fn set_input_region(&self, region: Option<&[Bounds<Pixels>]>) {
2531 self.platform_window.set_input_region(region);
2532 }
2533
2534 pub fn window_bounds(&self) -> WindowBounds {
2537 self.platform_window.window_bounds()
2538 }
2539
2540 pub fn inner_window_bounds(&self) -> WindowBounds {
2542 self.platform_window.inner_window_bounds()
2543 }
2544
2545 pub fn native_window_state(&self) -> Option<Vec<u8>> {
2548 self.platform_window.native_window_state()
2549 }
2550
2551 pub fn restore_native_window_state(&self, state: &[u8]) {
2554 self.platform_window.restore_native_window_state(state);
2555 }
2556
2557 pub fn dispatch_action(&mut self, action: Box<dyn Action>, cx: &mut App) {
2559 let focus_id = self.focused(cx).map(|handle| handle.id);
2560
2561 let window = self.handle;
2562 cx.defer(move |cx| {
2563 window
2564 .update(cx, |_, window, cx| {
2565 let node_id = window.focus_node_id_in_rendered_frame(focus_id);
2566 window.dispatch_action_on_node(node_id, action.as_ref(), cx);
2567 })
2568 .log_err();
2569 })
2570 }
2571
2572 pub(crate) fn dispatch_keystroke_observers(
2573 &mut self,
2574 keystroke: &Keystroke,
2575 input_preference: InputPreference,
2576 action: Option<&dyn Action>,
2577 context_stack: Vec<KeyContext>,
2578 cx: &mut App,
2579 ) {
2580 cx.keystroke_observers.clone().retain(&(), move |callback| {
2581 (callback)(
2582 &KeystrokeEvent {
2583 keystroke: keystroke.clone(),
2584 input_preference,
2585 action: action.map(|action| action.boxed_clone()),
2586 context_stack: context_stack.clone(),
2587 },
2588 self,
2589 cx,
2590 )
2591 });
2592 }
2593
2594 pub(crate) fn dispatch_keystroke_interceptors(
2595 &mut self,
2596 keystroke: &Keystroke,
2597 input_preference: InputPreference,
2598 context_stack: Vec<KeyContext>,
2599 cx: &mut App,
2600 ) {
2601 cx.keystroke_interceptors
2602 .clone()
2603 .retain(&(), move |callback| {
2604 (callback)(
2605 &KeystrokeEvent {
2606 keystroke: keystroke.clone(),
2607 input_preference,
2608 action: None,
2609 context_stack: context_stack.clone(),
2610 },
2611 self,
2612 cx,
2613 )
2614 });
2615 }
2616
2617 pub fn defer(&self, cx: &mut App, f: impl FnOnce(&mut Window, &mut App) + 'static) {
2620 let handle = self.handle;
2621 cx.defer(move |cx| {
2622 handle.update(cx, |_, window, cx| f(window, cx)).ok();
2623 });
2624 }
2625
2626 pub fn observe<T: 'static>(
2630 &mut self,
2631 observed: &Entity<T>,
2632 cx: &mut App,
2633 mut on_notify: impl FnMut(Entity<T>, &mut Window, &mut App) + 'static,
2634 ) -> Subscription {
2635 let entity_id = observed.entity_id();
2636 let observed = observed.downgrade();
2637 let window_handle = self.handle;
2638 cx.new_observer(
2639 entity_id,
2640 Box::new(move |cx| {
2641 window_handle
2642 .update(cx, |_, window, cx| {
2643 if let Some(handle) = observed.upgrade() {
2644 on_notify(handle, window, cx);
2645 true
2646 } else {
2647 false
2648 }
2649 })
2650 .unwrap_or(false)
2651 }),
2652 )
2653 }
2654
2655 pub fn subscribe<Emitter, Evt>(
2659 &mut self,
2660 entity: &Entity<Emitter>,
2661 cx: &mut App,
2662 mut on_event: impl FnMut(Entity<Emitter>, &Evt, &mut Window, &mut App) + 'static,
2663 ) -> Subscription
2664 where
2665 Emitter: EventEmitter<Evt>,
2666 Evt: 'static,
2667 {
2668 let entity_id = entity.entity_id();
2669 let handle = entity.downgrade();
2670 let window_handle = self.handle;
2671 cx.new_subscription(
2672 entity_id,
2673 (
2674 TypeId::of::<Evt>(),
2675 Box::new(move |event, cx| {
2676 window_handle
2677 .update(cx, |_, window, cx| {
2678 if let Some(entity) = handle.upgrade() {
2679 let event = event.downcast_ref().expect("invalid event type");
2680 on_event(entity, event, window, cx);
2681 true
2682 } else {
2683 false
2684 }
2685 })
2686 .unwrap_or(false)
2687 }),
2688 ),
2689 )
2690 }
2691
2692 pub fn observe_release<T>(
2694 &self,
2695 entity: &Entity<T>,
2696 cx: &mut App,
2697 mut on_release: impl FnOnce(&mut T, &mut Window, &mut App) + 'static,
2698 ) -> Subscription
2699 where
2700 T: 'static,
2701 {
2702 let entity_id = entity.entity_id();
2703 let window_handle = self.handle;
2704 let (subscription, activate) = cx.release_listeners.insert(
2705 entity_id,
2706 Box::new(move |entity, cx| {
2707 let entity = entity.downcast_mut().expect("invalid entity type");
2708 let _ = window_handle.update(cx, |_, window, cx| on_release(entity, window, cx));
2709 }),
2710 );
2711 activate();
2712 subscription
2713 }
2714
2715 pub fn to_async(&self, cx: &App) -> AsyncWindowContext {
2718 AsyncWindowContext::new_context(cx.to_async(), self.handle)
2719 }
2720
2721 pub fn on_next_frame(&self, callback: impl FnOnce(&mut Window, &mut App) + 'static) {
2723 RefCell::borrow_mut(&self.next_frame_callbacks).push(Box::new(callback));
2724 self.platform_window.schedule_frame();
2725 self.invalidator.wake_platform();
2728 }
2729
2730 pub fn request_animation_frame(&self) {
2743 let entity = self.current_view();
2744 self.on_next_frame(move |_, cx| cx.notify(entity));
2745 }
2746
2747 #[cfg(any(test, feature = "test-support"))]
2752 pub fn simulate_next_frame(&mut self, cx: &mut App) -> usize {
2753 let callbacks = self.next_frame_callbacks.take();
2754 let count = callbacks.len();
2755 for callback in callbacks {
2756 callback(self, cx);
2757 }
2758 count
2759 }
2760
2761 #[track_caller]
2765 pub fn spawn<AsyncFn, R>(&self, cx: &App, f: AsyncFn) -> Task<R>
2766 where
2767 R: 'static,
2768 AsyncFn: AsyncFnOnce(&mut AsyncWindowContext) -> R + 'static,
2769 {
2770 let handle = self.handle;
2771 cx.spawn(async move |app| {
2772 let mut async_window_cx = AsyncWindowContext::new_context(app.clone(), handle);
2773 f(&mut async_window_cx).await
2774 })
2775 }
2776
2777 #[track_caller]
2781 pub fn spawn_with_priority<AsyncFn, R>(
2782 &self,
2783 priority: Priority,
2784 cx: &App,
2785 f: AsyncFn,
2786 ) -> Task<R>
2787 where
2788 R: 'static,
2789 AsyncFn: AsyncFnOnce(&mut AsyncWindowContext) -> R + 'static,
2790 {
2791 let handle = self.handle;
2792 cx.spawn_with_priority(priority, async move |app| {
2793 let mut async_window_cx = AsyncWindowContext::new_context(app.clone(), handle);
2794 f(&mut async_window_cx).await
2795 })
2796 }
2797
2798 pub fn bounds_changed(&mut self, cx: &mut App) {
2804 self.scale_factor = self.platform_window.scale_factor();
2805 self.viewport_size = self.platform_window.content_size();
2806 self.mouse_position = self.platform_window.mouse_position();
2807
2808 self.refresh();
2809
2810 self.bounds_observers
2811 .clone()
2812 .retain(&(), |callback| callback(self, cx));
2813 }
2814
2815 fn display_changed(handle: AnyWindowHandle, cx: &mut App) {
2816 let moved_to = handle
2817 .update(cx, |_, window, _| {
2818 let display_id = window.platform_window.display().map(|display| display.id());
2819 let moved = display_id != window.display_id;
2820 window.display_id = display_id;
2821 moved.then_some(display_id)
2822 })
2823 .log_err()
2824 .flatten();
2825 let Some(display_id) = moved_to else {
2826 return;
2827 };
2828 if let Some(display_id) = display_id
2832 && !cx.knows_display(display_id)
2833 {
2834 cx.displays_changed();
2835 }
2836 handle
2837 .update(cx, |_, window, cx| window.notify_display_observers(cx))
2838 .log_err();
2839 }
2840
2841 pub(crate) fn notify_display_observers(&mut self, cx: &mut App) {
2842 self.display_observers
2843 .clone()
2844 .retain(&(), |callback| callback(self, cx));
2845 }
2846
2847 pub fn refresh_interval(&self, cx: &App) -> Option<Duration> {
2852 cx.display_refresh_interval(self.display_id?)
2853 }
2854
2855 pub fn observe_window_display(
2860 &self,
2861 mut callback: impl FnMut(&mut Window, &mut App) + 'static,
2862 ) -> Subscription {
2863 let (subscription, activate) = self.display_observers.insert(
2864 (),
2865 Box::new(move |window, cx| {
2866 callback(window, cx);
2867 true
2868 }),
2869 );
2870 activate();
2871 subscription
2872 }
2873
2874 pub fn bounds(&self) -> Bounds<Pixels> {
2876 self.platform_window.bounds()
2877 }
2878
2879 pub fn insets(&self) -> WindowInsets {
2881 self.platform_window.insets()
2882 }
2883
2884 #[cfg(any(test, feature = "test-support"))]
2888 pub fn render_to_image(&self) -> anyhow::Result<image::RgbaImage> {
2889 self.platform_window
2890 .render_to_image(&self.rendered_frame.scene)
2891 }
2892
2893 #[cfg(any(test, feature = "test-support"))]
2898 pub fn painted_quads(&self) -> Vec<Quad> {
2899 self.rendered_frame.scene.quads.clone()
2900 }
2901
2902 #[cfg(any(test, feature = "test-support"))]
2904 pub fn painted_underlines(&self) -> Vec<Underline> {
2905 self.rendered_frame.scene.underlines.clone()
2906 }
2907
2908 pub fn resize(&mut self, size: Size<Pixels>) {
2910 self.platform_window.resize(size);
2911 }
2912
2913 pub fn is_fullscreen(&self) -> bool {
2915 self.platform_window.is_fullscreen()
2916 }
2917
2918 pub fn is_simple_fullscreen(&self) -> bool {
2922 self.platform_window.is_simple_fullscreen()
2923 }
2924
2925 pub(crate) fn appearance_changed(&mut self, cx: &mut App) {
2926 self.appearance = self.platform_window.appearance();
2927
2928 self.appearance_observers
2929 .clone()
2930 .retain(&(), |callback| callback(self, cx));
2931 }
2932
2933 pub(crate) fn button_layout_changed(&mut self, cx: &mut App) {
2934 self.button_layout_observers
2935 .clone()
2936 .retain(&(), |callback| callback(self, cx));
2937 }
2938
2939 pub fn appearance(&self) -> WindowAppearance {
2941 self.appearance
2942 }
2943
2944 pub fn viewport_size(&self) -> Size<Pixels> {
2946 self.viewport_size
2947 }
2948
2949 pub fn visual_viewport_bounds(&self) -> Bounds<Pixels> {
2955 self.platform_window.visual_viewport_bounds()
2956 }
2957
2958 pub fn fully_visible_bounds(&self) -> Bounds<Pixels> {
2963 let insets = self.platform_window.insets().effective();
2964 let viewport = self.viewport_size();
2965 let left = insets.left.max(Pixels::ZERO).min(viewport.width);
2966 let top = insets.top.max(Pixels::ZERO).min(viewport.height);
2967 let right = (viewport.width - insets.right.max(Pixels::ZERO)).max(left);
2968 let bottom = (viewport.height - insets.bottom.max(Pixels::ZERO)).max(top);
2969 let safe_bounds = Bounds::from_corners(point(left, top), point(right, bottom));
2970 let mut visible = safe_bounds.intersect(&self.visual_viewport_bounds());
2971 visible.size.width = visible.size.width.max(Pixels::ZERO);
2972 visible.size.height = visible.size.height.max(Pixels::ZERO);
2973 visible
2974 }
2975
2976 pub fn request_virtual_keyboard(&self) {
2981 self.platform_window.show_soft_keyboard();
2982 }
2983
2984 pub fn dismiss_virtual_keyboard(&self) {
2986 self.platform_window.hide_soft_keyboard();
2987 }
2988
2989 pub fn is_window_active(&self) -> bool {
2991 self.active.get()
2992 }
2993
2994 pub fn is_window_hovered(&self) -> bool {
2998 if cfg!(any(
2999 target_os = "windows",
3000 target_os = "linux",
3001 target_os = "freebsd"
3002 )) {
3003 self.hovered.get()
3004 } else {
3005 self.is_window_active()
3006 }
3007 }
3008
3009 pub fn zoom_window(&self) {
3011 self.platform_window.zoom();
3012 }
3013
3014 pub fn show_window_menu(&self, position: Point<Pixels>) {
3016 self.platform_window.show_window_menu(position)
3017 }
3018
3019 pub fn start_window_move(&self) {
3024 self.platform_window.start_window_move()
3025 }
3026
3027 pub fn set_client_inset(&mut self, inset: Pixels) {
3029 self.client_inset = Some(inset);
3030 self.platform_window.set_client_inset(inset);
3031 }
3032
3033 pub fn client_inset(&self) -> Option<Pixels> {
3035 self.client_inset
3036 }
3037
3038 pub fn window_decorations(&self) -> Decorations {
3040 self.platform_window.window_decorations()
3041 }
3042
3043 pub fn is_resizable(&self) -> bool {
3045 self.is_resizable
3046 }
3047
3048 pub fn is_minimizable(&self) -> bool {
3050 self.is_minimizable
3051 }
3052
3053 pub fn window_controls(&self) -> WindowControls {
3055 self.platform_window.window_controls()
3056 }
3057
3058 pub fn set_window_title(&mut self, title: &str) {
3060 self.platform_window.set_title(title);
3061 self.a11y.set_window_title(title.to_string());
3062 }
3063
3064 #[cfg(target_os = "macos")]
3066 pub fn set_traffic_light_position(&self, position: Point<Pixels>) {
3067 self.platform_window.set_traffic_light_position(position);
3068 }
3069
3070 pub fn set_app_id(&mut self, app_id: &str) {
3072 self.platform_window.set_app_id(app_id);
3073 }
3074
3075 pub fn set_background_appearance(&self, background_appearance: WindowBackgroundAppearance) {
3077 self.platform_window
3078 .set_background_appearance(background_appearance);
3079 }
3080
3081 pub fn set_window_edited(&mut self, edited: bool) {
3083 self.platform_window.set_edited(edited);
3084 }
3085
3086 pub fn set_document_path(&self, path: Option<&std::path::Path>) {
3089 self.platform_window.set_document_path(path);
3090 }
3091
3092 pub fn display(&self, cx: &App) -> Option<Rc<dyn PlatformDisplay>> {
3094 cx.platform
3095 .displays()
3096 .into_iter()
3097 .find(|display| Some(display.id()) == self.display_id)
3098 }
3099
3100 pub fn show_character_palette(&self) {
3102 self.platform_window.show_character_palette();
3103 }
3104
3105 pub fn scale_factor(&self) -> f32 {
3109 self.scale_factor
3110 }
3111
3112 #[cfg(any(test, feature = "test-support"))]
3114 pub fn set_scale_factor(&mut self, scale_factor: f32) {
3115 self.scale_factor = scale_factor;
3116 self.refresh();
3117 }
3118
3119 pub fn rem_size(&self) -> Pixels {
3122 self.rem_size_override_stack
3123 .last()
3124 .copied()
3125 .unwrap_or(self.rem_size)
3126 }
3127
3128 pub fn set_rem_size(&mut self, rem_size: impl Into<Pixels>) {
3131 self.rem_size = rem_size.into();
3132 }
3133
3134 pub fn with_global_id<R>(
3137 &mut self,
3138 element_id: ElementId,
3139 f: impl FnOnce(&GlobalElementId, &mut Self) -> R,
3140 ) -> R {
3141 self.with_id(element_id, |this| {
3142 let global_id = this.element_id_stack.global_id();
3143
3144 f(&global_id, this)
3145 })
3146 }
3147
3148 #[inline]
3150 pub fn with_id<R>(
3151 &mut self,
3152 element_id: impl Into<ElementId>,
3153 f: impl FnOnce(&mut Self) -> R,
3154 ) -> R {
3155 self.element_id_stack.push(element_id.into());
3156 let result = f(self);
3157 self.element_id_stack.pop();
3158 result
3159 }
3160
3161 #[inline]
3167 pub fn with_rem_size<F, R>(&mut self, rem_size: Option<impl Into<Pixels>>, f: F) -> R
3168 where
3169 F: FnOnce(&mut Self) -> R,
3170 {
3171 self.invalidator.debug_assert_paint_or_prepaint();
3172
3173 if let Some(rem_size) = rem_size {
3174 self.rem_size_override_stack.push(rem_size.into());
3175 let result = f(self);
3176 self.rem_size_override_stack.pop();
3177 result
3178 } else {
3179 f(self)
3180 }
3181 }
3182
3183 pub fn line_height(&self) -> Pixels {
3185 self.text_style().line_height_in_pixels(self.rem_size())
3186 }
3187
3188 #[inline]
3190 pub fn pixel_snap(&self, value: Pixels) -> Pixels {
3191 px(round_to_device_pixel(value.0, self.scale_factor()) / self.scale_factor())
3192 }
3193
3194 #[inline]
3196 pub fn pixel_snap_f64(&self, value: f64) -> f64 {
3197 let scale_factor = f64::from(self.scale_factor());
3198 round_half_toward_zero_f64(value * scale_factor) / scale_factor
3199 }
3200
3201 #[inline]
3203 pub fn pixel_snap_bounds(&self, bounds: Bounds<Pixels>) -> Bounds<Pixels> {
3204 bounds.map(|c| self.pixel_snap(c))
3205 }
3206
3207 #[inline]
3209 pub fn pixel_snap_point(&self, position: Point<Pixels>) -> Point<Pixels> {
3210 position.map(|c| self.pixel_snap(c))
3211 }
3212
3213 pub fn underline_bounds(
3215 &self,
3216 origin: Point<Pixels>,
3217 width: Pixels,
3218 style: &UnderlineStyle,
3219 ) -> Bounds<ScaledPixels> {
3220 let scale_factor = self.scale_factor();
3221 let thickness = self.snap_stroke(style.thickness);
3222 let height = if style.wavy {
3223 ScaledPixels(thickness.0 * 3.)
3224 } else {
3225 thickness
3226 };
3227 Bounds {
3228 origin: origin.map(|c| ScaledPixels(round_to_device_pixel(c.0, scale_factor))),
3229 size: size(self.snap_stroke(width), height),
3230 }
3231 }
3232
3233 pub fn paint_underline_with_exclusions(
3235 &mut self,
3236 origin: Point<Pixels>,
3237 width: Pixels,
3238 style: &UnderlineStyle,
3239 exclusions: &[Range<ScaledPixels>],
3240 ) {
3241 self.invalidator.debug_assert_paint();
3242 let underline = self.underline(origin, width, style);
3243 if exclusions.is_empty() {
3244 self.next_frame.scene.insert_primitive(underline);
3245 return;
3246 }
3247
3248 let bounds = underline.bounds.intersect(&underline.content_mask.bounds);
3249 if bounds.is_empty() {
3250 return;
3251 }
3252
3253 let mut exclusions = exclusions
3254 .iter()
3255 .filter_map(|span| {
3256 let start = span.start.max(bounds.left());
3257 let end = span.end.min(bounds.right());
3258 (start < end).then_some(start..end)
3259 })
3260 .collect::<SmallVec<[_; 4]>>();
3261 if exclusions.is_empty() {
3262 self.next_frame.scene.insert_primitive(underline);
3263 return;
3264 }
3265 exclusions.sort_unstable_by_key(|span| span.start);
3266
3267 let mut paint_span = |start, end| {
3268 self.next_frame.scene.insert_primitive(Underline {
3269 content_mask: ContentMask {
3270 bounds: Bounds::from_corners(
3271 point(start, bounds.top()),
3272 point(end, bounds.bottom()),
3273 ),
3274 },
3275 ..underline
3276 });
3277 };
3278 let mut start = bounds.left();
3279 for exclusion in exclusions {
3280 if start < exclusion.start {
3281 paint_span(start, exclusion.start);
3282 }
3283 start = start.max(exclusion.end);
3284 }
3285 if start < bounds.right() {
3286 paint_span(start, bounds.right());
3287 }
3288 }
3289
3290 fn underline(&self, origin: Point<Pixels>, width: Pixels, style: &UnderlineStyle) -> Underline {
3291 Underline {
3292 order: 0,
3293 pad: 0,
3294 bounds: self.underline_bounds(origin, width, style),
3295 content_mask: self.snapped_content_mask(),
3296 color: style
3297 .color
3298 .unwrap_or_default()
3299 .opacity(self.element_opacity()),
3300 thickness: self.snap_stroke(style.thickness),
3301 wavy: style.wavy.into(),
3302 }
3303 }
3304
3305 #[inline]
3306 fn snap_bounds(&self, bounds: Bounds<Pixels>) -> Bounds<ScaledPixels> {
3307 let scale_factor = self.scale_factor();
3308 let left = round_to_device_pixel(bounds.left().0, scale_factor);
3309 let top = round_to_device_pixel(bounds.top().0, scale_factor);
3310 let right = round_to_device_pixel(bounds.right().0, scale_factor).max(left);
3311 let bottom = round_to_device_pixel(bounds.bottom().0, scale_factor).max(top);
3312 Bounds::from_corners(
3313 point(ScaledPixels(left), ScaledPixels(top)),
3314 point(ScaledPixels(right), ScaledPixels(bottom)),
3315 )
3316 }
3317
3318 #[inline]
3320 fn snap_stroke(&self, value: Pixels) -> ScaledPixels {
3321 ScaledPixels(round_stroke_to_device_pixel(value.0, self.scale_factor()))
3322 }
3323
3324 #[inline]
3325 fn snap_border_widths(&self, edges: Edges<Pixels>) -> Edges<ScaledPixels> {
3326 edges.map(|e| self.snap_stroke(*e))
3327 }
3328
3329 #[inline]
3331 fn cover_bounds(&self, bounds: Bounds<Pixels>) -> Bounds<ScaledPixels> {
3332 let scale_factor = self.scale_factor();
3333 let left = floor_to_device_pixel(bounds.left().0, scale_factor);
3334 let top = floor_to_device_pixel(bounds.top().0, scale_factor);
3335 let right = ceil_to_device_pixel(bounds.right().0, scale_factor).max(left);
3336 let bottom = ceil_to_device_pixel(bounds.bottom().0, scale_factor).max(top);
3337 Bounds::from_corners(
3338 point(ScaledPixels(left), ScaledPixels(top)),
3339 point(ScaledPixels(right), ScaledPixels(bottom)),
3340 )
3341 }
3342
3343 #[inline]
3344 fn snapped_content_mask(&self) -> ContentMask<ScaledPixels> {
3345 ContentMask {
3346 bounds: self.cover_bounds(self.content_mask().bounds),
3347 }
3348 }
3349
3350 pub fn prevent_default(&mut self) {
3353 self.default_prevented = true;
3354 }
3355
3356 pub fn default_prevented(&self) -> bool {
3358 self.default_prevented
3359 }
3360
3361 pub fn is_action_available(&self, action: &dyn Action, cx: &App) -> bool {
3363 let node_id =
3364 self.focus_node_id_in_rendered_frame(self.focused(cx).map(|handle| handle.id));
3365 self.rendered_frame
3366 .dispatch_tree
3367 .is_action_available(action, node_id)
3368 }
3369
3370 pub fn is_action_available_in(&self, action: &dyn Action, focus_handle: &FocusHandle) -> bool {
3372 let node_id = self.focus_node_id_in_rendered_frame(Some(focus_handle.id));
3373 self.rendered_frame
3374 .dispatch_tree
3375 .is_action_available(action, node_id)
3376 }
3377
3378 pub fn mouse_position(&self) -> Point<Pixels> {
3380 self.mouse_position
3381 }
3382
3383 pub fn capture_pointer(&mut self, hitbox_id: HitboxId) {
3390 self.captured_hitbox = Some(hitbox_id);
3391 }
3392
3393 pub fn release_pointer(&mut self) {
3395 self.captured_hitbox = None;
3396 }
3397
3398 pub fn captured_hitbox(&self) -> Option<HitboxId> {
3400 self.captured_hitbox
3401 }
3402
3403 pub fn capture_long_press<T: 'static>(&mut self, entity: &Entity<T>) {
3409 self.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.long_press_capture == Some(entity.entity_id())
3415 }
3416
3417 pub fn modifiers(&self) -> Modifiers {
3419 self.modifiers
3420 }
3421
3422 pub fn last_input_was_keyboard(&self) -> bool {
3425 self.last_input_modality == InputModality::Keyboard
3426 }
3427
3428 pub fn last_input_was_touch(&self) -> bool {
3430 self.last_input_modality == InputModality::Touch
3431 }
3432
3433 pub fn capslock(&self) -> Capslock {
3435 self.capslock
3436 }
3437
3438 #[profiling::function]
3441 pub fn draw(&mut self, cx: &mut App) -> ArenaClearNeeded {
3442 #[cfg(feature = "profiler")]
3445 let frame_dirty = self.invalidator.take_frame_dirty();
3446 #[cfg(feature = "profiler")]
3447 self.window_profiler.begin_draw();
3448
3449 let arena_scope = ElementArenaScope::enter(&cx.element_arena);
3452
3453 if self.platform_window.prepare_frame() {
3454 self.refresh();
3455 }
3456 self.invalidate_entities();
3457 cx.entities.clear_accessed();
3458 debug_assert!(self.rendered_entity_stack.is_empty());
3459 self.invalidator.set_dirty(false);
3460 self.requested_autoscroll = None;
3461
3462 if let Some(input_handler) = self.platform_window.take_input_handler() {
3467 if let Some(slot) = self
3468 .rendered_frame
3469 .input_handlers
3470 .iter_mut()
3471 .rev()
3472 .find(|h| h.is_none())
3473 {
3474 *slot = Some(input_handler);
3475 } else {
3476 self.rendered_frame.input_handlers.push(Some(input_handler));
3477 }
3478 }
3479 if !cx.mode.skip_drawing() {
3480 self.draw_roots(cx);
3481 #[cfg(feature = "profiler")]
3482 {
3483 let viewport_size = self.viewport_size;
3484 let scale_factor = self.scale_factor();
3485 self.debug_frame_overlay.paint(
3486 &mut self.next_frame.scene,
3487 viewport_size,
3488 scale_factor,
3489 );
3490 }
3491 }
3492 self.dirty_views.clear();
3493 self.next_frame.window_active = self.active.get();
3494
3495 let focused_text_input = if let Some(mut input_handler) = self
3501 .next_frame
3502 .input_handlers
3503 .iter_mut()
3504 .rev()
3505 .find_map(|h| h.take())
3506 {
3507 let accepts_text_input = input_handler.accepts_text_input(self, cx);
3508 self.platform_window.set_input_handler(input_handler);
3509 self.focus.filter(|_| accepts_text_input)
3510 } else {
3511 None
3512 };
3513 self.apply_text_input_configuration(cx);
3514 let previous = mem::replace(&mut self.focused_text_input, focused_text_input);
3515 if previous.is_some() != focused_text_input.is_some() {
3516 self.platform_window
3517 .text_input_state_changed(if focused_text_input.is_some() {
3518 TextInputStateChange::FocusGained
3519 } else {
3520 TextInputStateChange::FocusLost
3521 });
3522 }
3523
3524 self.layout_engine.as_mut().unwrap().clear();
3525 self.text_system().finish_frame();
3526 self.next_frame.finish(&mut self.rendered_frame);
3527
3528 self.invalidator.set_phase(DrawPhase::Focus);
3529 let previous_focus_path = self.rendered_frame.focus_path();
3530 let previous_window_active = self.rendered_frame.window_active;
3531 mem::swap(&mut self.rendered_frame, &mut self.next_frame);
3532 self.next_frame.clear();
3533 let current_focus_path = self.rendered_frame.focus_path();
3534 let current_window_active = self.rendered_frame.window_active;
3535 let mut focus_before_listeners = self.focus;
3536
3537 if previous_focus_path != current_focus_path
3538 || previous_window_active != current_window_active
3539 {
3540 if !previous_focus_path.is_empty() && current_focus_path.is_empty() {
3541 self.focus_lost_path = previous_focus_path.clone();
3542 self.focus_lost_listeners
3543 .clone()
3544 .retain(&(), |listener| listener(self, cx));
3545 self.focus_lost_path = SmallVec::new();
3546 focus_before_listeners = self.focus;
3551 }
3552
3553 let event = WindowFocusEvent {
3554 previous_focus_path: if previous_window_active {
3555 previous_focus_path
3556 } else {
3557 Default::default()
3558 },
3559 current_focus_path: if current_window_active {
3560 current_focus_path
3561 } else {
3562 Default::default()
3563 },
3564 };
3565 self.focus_listeners
3566 .clone()
3567 .retain(&(), |listener| listener(&event, self, cx));
3568 }
3569
3570 debug_assert!(self.rendered_entity_stack.is_empty());
3571 self.record_entities_accessed(cx);
3572 self.reset_cursor_style(cx);
3573 self.refreshing = false;
3574 self.invalidator.set_phase(DrawPhase::None);
3575 if self.focus != focus_before_listeners {
3580 self.refresh();
3581 }
3582 self.needs_present.set(true);
3583
3584 #[cfg(feature = "profiler")]
3585 {
3586 self.window_profiler
3587 .set_refresh_interval(self.refresh_interval(cx));
3588 let draw_duration = self
3589 .window_profiler
3590 .end_draw(frame_dirty.dirty_at, frame_dirty.invalidations);
3591 self.debug_frame_overlay.record_frame(draw_duration);
3592 }
3593
3594 arena_scope.exit(&cx.element_arena)
3597 }
3598
3599 fn record_entities_accessed(&mut self, cx: &mut App) {
3600 let mut entities_ref = cx.entities.accessed_entities.get_mut();
3601 let mut entities = mem::take(entities_ref.deref_mut());
3602 let handle = self.handle;
3603 cx.record_entities_accessed(
3604 handle,
3605 self.invalidator.clone(),
3607 &entities,
3608 );
3609 let mut entities_ref = cx.entities.accessed_entities.get_mut();
3610 mem::swap(&mut entities, entities_ref.deref_mut());
3611 }
3612
3613 fn invalidate_entities(&mut self) {
3614 let mut views = self.invalidator.take_views();
3615 for entity in views.drain() {
3616 self.mark_view_dirty(entity);
3617 }
3618 self.invalidator.replace_views(views);
3619 }
3620
3621 #[profiling::function]
3622 fn present(&mut self) {
3623 #[cfg(feature = "profiler")]
3624 let _foreground_turn = profiler::journal::foreground_turn();
3625 #[cfg(feature = "profiler")]
3626 let present_start = Instant::now();
3627 self.platform_window.draw(&self.rendered_frame.scene);
3628 #[cfg(feature = "profiler")]
3629 self.window_profiler.record_present(
3630 present_start,
3631 Instant::now(),
3632 self.active.get(),
3633 !self.next_frame_callbacks.borrow().is_empty(),
3634 );
3635 self.needs_present.set(false);
3636 profiling::finish_frame!();
3637 }
3638
3639 #[cfg(all(test, feature = "profiler"))]
3641 pub fn present_if_needed(&mut self) {
3642 if self.needs_present.get() {
3643 self.present();
3644 }
3645 }
3646
3647 #[cfg(feature = "profiler")]
3649 pub fn input_latency_snapshot(&self) -> profiler::InputLatencySnapshot {
3650 self.window_profiler.input_latency_snapshot()
3651 }
3652
3653 #[cfg(feature = "profiler")]
3655 pub fn frame_duration_snapshot(&self) -> profiler::FrameDurationSnapshot {
3656 self.window_profiler.frame_duration_snapshot()
3657 }
3658
3659 #[cfg(feature = "profiler")]
3661 pub fn debug_frame_overlay_mode(&self) -> DebugFrameOverlayMode {
3662 self.debug_frame_overlay.mode()
3663 }
3664
3665 #[cfg(feature = "profiler")]
3667 pub fn set_debug_frame_overlay_mode(&mut self, mode: DebugFrameOverlayMode) {
3668 self.debug_frame_overlay.set_mode(mode);
3669 self.refresh();
3670 }
3671
3672 #[cfg(feature = "profiler")]
3675 pub fn cycle_debug_frame_overlay_mode(&mut self) {
3676 self.set_debug_frame_overlay_mode(self.debug_frame_overlay.mode().next());
3677 }
3678
3679 #[cfg(feature = "profiler")]
3682 pub fn reset_debug_frame_overlay_stats(&mut self) {
3683 self.debug_frame_overlay.reset_stats();
3684 self.refresh();
3685 }
3686
3687 fn draw_roots(&mut self, cx: &mut App) {
3688 self.invalidator.set_phase(DrawPhase::Prepaint);
3689 self.tooltip_bounds.take();
3690
3691 self.a11y.sync_active_flag();
3692 if self.a11y.is_active() {
3693 self.a11y.begin_frame();
3694 }
3695
3696 let _inspector_width: Pixels = rems(30.0).to_pixels(self.rem_size());
3697 let root_size = {
3698 #[cfg(any(feature = "inspector", debug_assertions))]
3699 {
3700 if self.inspector.is_some() {
3701 let mut size = self.viewport_size;
3702 size.width = (size.width - _inspector_width).max(px(0.0));
3703 size
3704 } else {
3705 self.viewport_size
3706 }
3707 }
3708 #[cfg(not(any(feature = "inspector", debug_assertions)))]
3709 {
3710 self.viewport_size
3711 }
3712 };
3713
3714 let scale_factor = self.scale_factor();
3718 #[cfg(feature = "profiler")]
3719 let request_layout_start = Instant::now();
3720 let mut root_element = self.root.as_ref().unwrap().clone().into_any_element();
3721 let root_layout_id = root_element.request_layout(self, cx);
3722 #[cfg(feature = "profiler")]
3723 let prepaint_start = Instant::now();
3724 self.layout_engine
3725 .as_mut()
3726 .unwrap()
3727 .stretch_auto_size_to_fill(root_layout_id, root_size, scale_factor);
3728 root_element.prepaint_as_root(Point::default(), root_size.into(), self, cx);
3729
3730 #[cfg(any(feature = "inspector", debug_assertions))]
3731 let inspector_element = self.prepaint_inspector(_inspector_width, cx);
3732
3733 self.prepaint_deferred_draws(cx);
3734
3735 let mut prompt_element = None;
3736 let mut active_drag_element = None;
3737 let mut tooltip_element = None;
3738 if let Some(prompt) = self.prompt.take() {
3739 let mut element = prompt.view.any_view().into_any_element();
3740 let prompt_layout_id = element.request_layout(self, cx);
3741 self.layout_engine
3742 .as_mut()
3743 .unwrap()
3744 .stretch_auto_size_to_fill(prompt_layout_id, root_size, scale_factor);
3745 element.prepaint_as_root(Point::default(), root_size.into(), self, cx);
3746 prompt_element = Some(element);
3747 self.prompt = Some(prompt);
3748 } else if let Some(active_drag) = cx.active_drag.take() {
3749 let mut element = active_drag.view.clone().into_any_element();
3750 let offset = self.mouse_position() - active_drag.cursor_offset;
3751 element.prepaint_as_root(offset, AvailableSpace::min_size(), self, cx);
3752 active_drag_element = Some(element);
3753 cx.active_drag = Some(active_drag);
3754 } else {
3755 tooltip_element = self.prepaint_tooltip(cx);
3756 }
3757
3758 self.mouse_hit_test = self.next_frame.hit_test(self.mouse_position);
3759
3760 #[cfg(feature = "profiler")]
3762 let paint_start = Instant::now();
3763 self.invalidator.set_phase(DrawPhase::Paint);
3764 root_element.paint(self, cx);
3765
3766 #[cfg(any(feature = "inspector", debug_assertions))]
3767 self.paint_inspector(inspector_element, cx);
3768
3769 self.paint_deferred_draws(cx);
3770
3771 if let Some(mut prompt_element) = prompt_element {
3772 prompt_element.paint(self, cx);
3773 } else if let Some(mut drag_element) = active_drag_element {
3774 drag_element.paint(self, cx);
3775 } else if let Some(mut tooltip_element) = tooltip_element {
3776 tooltip_element.paint(self, cx);
3777 }
3778
3779 #[cfg(any(feature = "inspector", debug_assertions))]
3780 self.paint_inspector_hitbox(cx);
3781
3782 #[cfg(feature = "profiler")]
3783 self.window_profiler
3784 .record_draw_phases(profiler::DrawPhases {
3785 request_layout: prepaint_start.duration_since(request_layout_start),
3786 prepaint: paint_start.duration_since(prepaint_start),
3787 paint: Instant::now().duration_since(paint_start),
3788 });
3789
3790 let a11y_active_start_of_frame = self.a11y.is_active();
3792 self.a11y.sync_active_flag();
3793 let a11y_active_end_of_frame = self.a11y.is_active();
3794
3795 let should_send_a11y_update = a11y_active_start_of_frame && a11y_active_end_of_frame;
3796
3797 if a11y_active_start_of_frame {
3798 let frame_info = crate::window::a11y::debug::FrameDebugInfo {
3801 viewport_size: self.viewport_size,
3802 scale_factor: self.scale_factor,
3803 tab_stop_count: self.next_frame.tab_stops.tab_stop_count(),
3804 };
3805 let tree_update = self.a11y.end_frame(frame_info);
3807
3808 if should_send_a11y_update {
3809 log::debug!(
3810 "Sending a11y tree update: {} nodes",
3811 tree_update.nodes.len()
3812 );
3813 self.platform_window.a11y_tree_update(tree_update);
3814 }
3815 }
3816 }
3817
3818 fn prepaint_tooltip(&mut self, cx: &mut App) -> Option<AnyElement> {
3819 for tooltip_request_index in (0..self.next_frame.tooltip_requests.len()).rev() {
3821 let Some(Some(tooltip_request)) = self
3822 .next_frame
3823 .tooltip_requests
3824 .get(tooltip_request_index)
3825 .cloned()
3826 else {
3827 log::error!("Unexpectedly absent TooltipRequest");
3828 continue;
3829 };
3830 let mut element = tooltip_request.tooltip.view.clone().into_any_element();
3831 let mouse_position = tooltip_request.tooltip.mouse_position;
3832 let tooltip_size = element.layout_as_root(AvailableSpace::min_size(), self, cx);
3833
3834 let mut tooltip_bounds =
3835 Bounds::new(mouse_position + point(px(1.), px(1.)), tooltip_size);
3836 let window_bounds = Bounds {
3837 origin: Point::default(),
3838 size: self.viewport_size(),
3839 };
3840
3841 if tooltip_bounds.right() > window_bounds.right() {
3842 let new_x = mouse_position.x - tooltip_bounds.size.width - px(1.);
3843 if new_x >= Pixels::ZERO {
3844 tooltip_bounds.origin.x = new_x;
3845 } else {
3846 tooltip_bounds.origin.x = cmp::max(
3847 Pixels::ZERO,
3848 tooltip_bounds.origin.x - tooltip_bounds.right() - window_bounds.right(),
3849 );
3850 }
3851 }
3852
3853 if tooltip_bounds.bottom() > window_bounds.bottom() {
3854 let new_y = mouse_position.y - tooltip_bounds.size.height - px(1.);
3855 if new_y >= Pixels::ZERO {
3856 tooltip_bounds.origin.y = new_y;
3857 } else {
3858 tooltip_bounds.origin.y = cmp::max(
3859 Pixels::ZERO,
3860 tooltip_bounds.origin.y - tooltip_bounds.bottom() - window_bounds.bottom(),
3861 );
3862 }
3863 }
3864
3865 let is_visible =
3869 (tooltip_request.tooltip.check_visible_and_update)(tooltip_bounds, self, cx);
3870 if !is_visible {
3871 continue;
3872 }
3873
3874 self.with_absolute_element_offset(tooltip_bounds.origin, |window| {
3875 element.prepaint(window, cx)
3876 });
3877
3878 self.tooltip_bounds = Some(TooltipBounds {
3879 id: tooltip_request.id,
3880 bounds: tooltip_bounds,
3881 });
3882 return Some(element);
3883 }
3884 None
3885 }
3886
3887 fn prepaint_deferred_draws(&mut self, cx: &mut App) {
3888 assert_eq!(self.element_id_stack.len(), 0);
3889
3890 let mut round_start = 0;
3901 let mut depth = 0;
3902 loop {
3903 let round_end = self.next_frame.deferred_draws.len();
3904 if round_start == round_end {
3905 break;
3906 }
3907 assert!(depth < 10, "Exceeded maximum (10) deferred depth");
3909 depth += 1;
3910
3911 let mut traversal_order = (round_start..round_end).collect::<SmallVec<[usize; 8]>>();
3913 traversal_order.sort_by_key(|ix| self.next_frame.deferred_draws[*ix].priority);
3914
3915 for deferred_draw_ix in traversal_order {
3916 let (element, parent_node, current_view, rem_size, absolute_offset, prepaint_range) = {
3917 let deferred_draw = &mut self.next_frame.deferred_draws[deferred_draw_ix];
3918 self.element_id_stack
3919 .clone_from(&deferred_draw.element_id_stack);
3920 self.text_style_stack
3921 .clone_from(&deferred_draw.text_style_stack);
3922 (
3923 deferred_draw.element.take(),
3924 deferred_draw.parent_node,
3925 deferred_draw.current_view,
3926 deferred_draw.rem_size,
3927 deferred_draw.absolute_offset,
3928 deferred_draw.prepaint_range.clone(),
3929 )
3930 };
3931 self.next_frame.dispatch_tree.set_active_node(parent_node);
3932
3933 let prepaint_start = self.prepaint_index();
3934 if let Some(mut element) = element {
3935 self.with_rendered_view(current_view, |window| {
3936 window.with_rem_size(Some(rem_size), |window| {
3937 window.with_absolute_element_offset(absolute_offset, |window| {
3938 element.prepaint(window, cx);
3939 });
3940 });
3941 });
3942 self.next_frame.deferred_draws[deferred_draw_ix].element = Some(element);
3943 } else {
3944 self.reuse_prepaint(prepaint_range);
3945 }
3946 let prepaint_end = self.prepaint_index();
3947 self.next_frame.deferred_draws[deferred_draw_ix].prepaint_range =
3948 prepaint_start..prepaint_end;
3949 }
3950
3951 self.element_id_stack.clear();
3952 self.text_style_stack.clear();
3953 round_start = round_end;
3954 }
3955 }
3956
3957 fn paint_deferred_draws(&mut self, cx: &mut App) {
3958 assert_eq!(self.element_id_stack.len(), 0);
3959
3960 if self.next_frame.deferred_draws.len() == 0 {
3963 return;
3964 }
3965
3966 let traversal_order = self.deferred_draw_traversal_order();
3967 let mut deferred_draws = mem::take(&mut self.next_frame.deferred_draws);
3968 for deferred_draw_ix in traversal_order {
3969 let mut deferred_draw = &mut deferred_draws[deferred_draw_ix];
3970 self.element_id_stack
3971 .clone_from(&deferred_draw.element_id_stack);
3972 self.next_frame
3973 .dispatch_tree
3974 .set_active_node(deferred_draw.parent_node);
3975
3976 let paint_start = self.paint_index();
3977 let content_mask = deferred_draw.content_mask;
3978 if let Some(element) = deferred_draw.element.as_mut() {
3979 self.with_rendered_view(deferred_draw.current_view, |window| {
3980 window.with_content_mask(content_mask, |window| {
3981 window.with_rem_size(Some(deferred_draw.rem_size), |window| {
3982 element.paint(window, cx);
3983 });
3984 })
3985 })
3986 } else {
3987 self.reuse_paint(deferred_draw.paint_range.clone());
3988 }
3989 let paint_end = self.paint_index();
3990 deferred_draw.paint_range = paint_start..paint_end;
3991 }
3992 self.next_frame.deferred_draws = deferred_draws;
3993 self.element_id_stack.clear();
3994 }
3995
3996 fn deferred_draw_traversal_order(&mut self) -> SmallVec<[usize; 8]> {
3997 let deferred_count = self.next_frame.deferred_draws.len();
3998 let mut sorted_indices = (0..deferred_count).collect::<SmallVec<[_; 8]>>();
3999 sorted_indices.sort_by_key(|ix| self.next_frame.deferred_draws[*ix].priority);
4000 sorted_indices
4001 }
4002
4003 pub(crate) fn prepaint_index(&self) -> PrepaintStateIndex {
4004 PrepaintStateIndex {
4005 hitboxes_index: self.next_frame.hitboxes.len(),
4006 tooltips_index: self.next_frame.tooltip_requests.len(),
4007 deferred_draws_index: self.next_frame.deferred_draws.len(),
4008 dispatch_tree_index: self.next_frame.dispatch_tree.len(),
4009 accessed_element_states_index: self.next_frame.accessed_element_states.len(),
4010 line_layout_index: self.text_system.layout_index(),
4011 }
4012 }
4013
4014 pub(crate) fn reuse_prepaint(&mut self, range: Range<PrepaintStateIndex>) {
4015 self.next_frame.hitboxes.extend(
4016 self.rendered_frame.hitboxes[range.start.hitboxes_index..range.end.hitboxes_index]
4017 .iter()
4018 .cloned(),
4019 );
4020 self.next_frame.tooltip_requests.extend(
4021 self.rendered_frame.tooltip_requests
4022 [range.start.tooltips_index..range.end.tooltips_index]
4023 .iter_mut()
4024 .map(|request| request.take()),
4025 );
4026 self.next_frame.accessed_element_states.extend(
4027 self.rendered_frame.accessed_element_states[range.start.accessed_element_states_index
4028 ..range.end.accessed_element_states_index]
4029 .iter()
4030 .map(|(id, type_id)| (id.clone(), *type_id)),
4031 );
4032 self.text_system
4033 .reuse_layouts(range.start.line_layout_index..range.end.line_layout_index);
4034
4035 let reused_subtree = self.next_frame.dispatch_tree.reuse_subtree(
4036 range.start.dispatch_tree_index..range.end.dispatch_tree_index,
4037 &mut self.rendered_frame.dispatch_tree,
4038 self.focus,
4039 );
4040
4041 if reused_subtree.contains_focus() {
4042 self.next_frame.focus = self.focus;
4043 }
4044
4045 self.next_frame.deferred_draws.extend(
4046 self.rendered_frame.deferred_draws
4047 [range.start.deferred_draws_index..range.end.deferred_draws_index]
4048 .iter()
4049 .map(|deferred_draw| DeferredDraw {
4050 current_view: deferred_draw.current_view,
4051 parent_node: reused_subtree.refresh_node_id(deferred_draw.parent_node),
4052 element_id_stack: deferred_draw.element_id_stack.clone(),
4053 text_style_stack: deferred_draw.text_style_stack.clone(),
4054 content_mask: deferred_draw.content_mask,
4055 rem_size: deferred_draw.rem_size,
4056 priority: deferred_draw.priority,
4057 element: None,
4058 absolute_offset: deferred_draw.absolute_offset,
4059 prepaint_range: deferred_draw.prepaint_range.clone(),
4060 paint_range: deferred_draw.paint_range.clone(),
4061 }),
4062 );
4063 }
4064
4065 pub(crate) fn paint_index(&self) -> PaintIndex {
4066 PaintIndex {
4067 scene_index: self.next_frame.scene.len(),
4068 #[cfg(any(test, feature = "test-support"))]
4069 debug_bounds_index: self.next_frame.debug_bounds_records.len(),
4070 mouse_listeners_index: self.next_frame.mouse_listeners.len(),
4071 input_handlers_index: self.next_frame.input_handlers.len(),
4072 cursor_styles_index: self.next_frame.cursor_styles.len(),
4073 accessed_element_states_index: self.next_frame.accessed_element_states.len(),
4074 tab_handle_index: self.next_frame.tab_stops.paint_index(),
4075 line_layout_index: self.text_system.layout_index(),
4076 }
4077 }
4078
4079 pub(crate) fn reuse_paint(&mut self, range: Range<PaintIndex>) {
4080 #[cfg(any(test, feature = "test-support"))]
4082 for (selector, bounds) in &self.rendered_frame.debug_bounds_records
4083 [range.start.debug_bounds_index..range.end.debug_bounds_index]
4084 {
4085 self.next_frame
4086 .record_debug_bounds(selector.clone(), *bounds);
4087 }
4088 self.next_frame.cursor_styles.extend(
4089 self.rendered_frame.cursor_styles
4090 [range.start.cursor_styles_index..range.end.cursor_styles_index]
4091 .iter()
4092 .cloned(),
4093 );
4094 self.next_frame.input_handlers.extend(
4095 self.rendered_frame.input_handlers
4096 [range.start.input_handlers_index..range.end.input_handlers_index]
4097 .iter_mut()
4098 .map(|handler| handler.take()),
4099 );
4100 self.next_frame.mouse_listeners.extend(
4101 self.rendered_frame.mouse_listeners
4102 [range.start.mouse_listeners_index..range.end.mouse_listeners_index]
4103 .iter_mut()
4104 .map(|listener| listener.take()),
4105 );
4106 self.next_frame.accessed_element_states.extend(
4107 self.rendered_frame.accessed_element_states[range.start.accessed_element_states_index
4108 ..range.end.accessed_element_states_index]
4109 .iter()
4110 .map(|(id, type_id)| (id.clone(), *type_id)),
4111 );
4112 self.next_frame.tab_stops.replay(
4113 &self.rendered_frame.tab_stops.insertion_history
4114 [range.start.tab_handle_index..range.end.tab_handle_index],
4115 );
4116
4117 self.text_system
4118 .reuse_layouts(range.start.line_layout_index..range.end.line_layout_index);
4119 self.next_frame.scene.replay(
4120 range.start.scene_index..range.end.scene_index,
4121 &self.rendered_frame.scene,
4122 );
4123 }
4124
4125 pub fn with_text_style<F, R>(&mut self, style: Option<TextStyleRefinement>, f: F) -> R
4129 where
4130 F: FnOnce(&mut Self) -> R,
4131 {
4132 self.invalidator.debug_assert_paint_or_prepaint();
4133 if let Some(style) = style {
4134 self.text_style_stack.push(style);
4135 let result = f(self);
4136 self.text_style_stack.pop();
4137 result
4138 } else {
4139 f(self)
4140 }
4141 }
4142
4143 pub fn set_cursor_style(&mut self, style: CursorStyle, hitbox: &Hitbox) {
4146 self.invalidator.debug_assert_paint();
4147 self.next_frame.cursor_styles.push(CursorStyleRequest {
4148 hitbox_id: Some(hitbox.id),
4149 style,
4150 });
4151 }
4152
4153 pub fn set_window_cursor_style(&mut self, style: CursorStyle) {
4158 self.invalidator.debug_assert_paint();
4159 self.next_frame.cursor_styles.push(CursorStyleRequest {
4160 hitbox_id: None,
4161 style,
4162 })
4163 }
4164
4165 pub fn set_tooltip(&mut self, tooltip: AnyTooltip) -> TooltipId {
4168 self.invalidator.debug_assert_prepaint();
4169 let id = TooltipId(post_inc(&mut self.next_tooltip_id.0));
4170 self.next_frame
4171 .tooltip_requests
4172 .push(Some(TooltipRequest { id, tooltip }));
4173 id
4174 }
4175
4176 #[inline]
4181 pub fn with_content_mask<R>(
4182 &mut self,
4183 mask: Option<ContentMask<Pixels>>,
4184 f: impl FnOnce(&mut Self) -> R,
4185 ) -> R {
4186 self.invalidator.debug_assert_paint_or_prepaint();
4187 if let Some(mask) = mask {
4188 let mask = mask.intersect(&self.content_mask());
4189 self.content_mask_stack.push(mask);
4190 let result = f(self);
4191 self.content_mask_stack.pop();
4192 result
4193 } else {
4194 f(self)
4195 }
4196 }
4197
4198 pub fn with_element_offset<R>(
4201 &mut self,
4202 offset: Point<Pixels>,
4203 f: impl FnOnce(&mut Self) -> R,
4204 ) -> R {
4205 self.invalidator.debug_assert_prepaint();
4206
4207 if offset.is_zero() {
4208 return f(self);
4209 };
4210
4211 let abs_offset = self.element_offset() + offset;
4212 self.with_absolute_element_offset(abs_offset, f)
4213 }
4214
4215 pub fn with_absolute_element_offset<R>(
4219 &mut self,
4220 offset: Point<Pixels>,
4221 f: impl FnOnce(&mut Self) -> R,
4222 ) -> R {
4223 self.invalidator.debug_assert_prepaint();
4224 self.element_offset_stack.push(offset);
4225 let result = f(self);
4226 self.element_offset_stack.pop();
4227 result
4228 }
4229
4230 pub(crate) fn with_element_opacity<R>(
4231 &mut self,
4232 opacity: Option<f32>,
4233 f: impl FnOnce(&mut Self) -> R,
4234 ) -> R {
4235 self.invalidator.debug_assert_paint_or_prepaint();
4236
4237 let Some(opacity) = opacity else {
4238 return f(self);
4239 };
4240
4241 let previous_opacity = self.element_opacity;
4242 self.element_opacity = previous_opacity * opacity;
4243 let result = f(self);
4244 self.element_opacity = previous_opacity;
4245 result
4246 }
4247
4248 pub fn transact<T, U>(&mut self, f: impl FnOnce(&mut Self) -> Result<T, U>) -> Result<T, U> {
4254 self.invalidator.debug_assert_prepaint();
4255 let index = self.prepaint_index();
4256 let result = f(self);
4257 if result.is_err() {
4258 self.next_frame.hitboxes.truncate(index.hitboxes_index);
4259 self.next_frame
4260 .tooltip_requests
4261 .truncate(index.tooltips_index);
4262 self.next_frame
4263 .deferred_draws
4264 .truncate(index.deferred_draws_index);
4265 self.next_frame
4266 .dispatch_tree
4267 .truncate(index.dispatch_tree_index);
4268 self.next_frame
4269 .accessed_element_states
4270 .truncate(index.accessed_element_states_index);
4271 self.text_system.truncate_layouts(index.line_layout_index);
4272 }
4273 result
4274 }
4275
4276 pub fn request_autoscroll(&mut self, bounds: Bounds<Pixels>) {
4282 self.invalidator.debug_assert_prepaint();
4283 self.requested_autoscroll = Some(bounds);
4284 }
4285
4286 pub fn take_autoscroll(&mut self) -> Option<Bounds<Pixels>> {
4289 self.invalidator.debug_assert_prepaint();
4290 self.requested_autoscroll.take()
4291 }
4292
4293 pub fn use_asset<A: Asset>(&mut self, source: &A::Source, cx: &mut App) -> Option<A::Output> {
4299 cx.asset_entry::<A>(source).use_by(self.current_view())
4300 }
4301
4302 pub fn get_asset<A: Asset>(&mut self, source: &A::Source, cx: &mut App) -> Option<A::Output> {
4308 cx.fetch_asset::<A>(source)
4309 }
4310 pub fn element_offset(&self) -> Point<Pixels> {
4313 self.invalidator.debug_assert_prepaint();
4314 self.element_offset_stack
4315 .last()
4316 .copied()
4317 .unwrap_or_default()
4318 }
4319
4320 #[inline]
4323 pub(crate) fn element_opacity(&self) -> f32 {
4324 self.invalidator.debug_assert_paint_or_prepaint();
4325 self.element_opacity
4326 }
4327
4328 pub fn content_mask(&self) -> ContentMask<Pixels> {
4330 self.invalidator.debug_assert_paint_or_prepaint();
4331 self.content_mask_stack
4332 .last()
4333 .cloned()
4334 .unwrap_or_else(|| ContentMask {
4335 bounds: Bounds {
4336 origin: Point::default(),
4337 size: self.viewport_size,
4338 },
4339 })
4340 }
4341
4342 pub fn with_element_namespace<R>(
4345 &mut self,
4346 element_id: impl Into<ElementId>,
4347 f: impl FnOnce(&mut Self) -> R,
4348 ) -> R {
4349 self.element_id_stack.push(element_id.into());
4350 let result = f(self);
4351 self.element_id_stack.pop();
4352 result
4353 }
4354
4355 pub fn use_keyed_state<S: 'static>(
4357 &mut self,
4358 key: impl Into<ElementId>,
4359 cx: &mut App,
4360 init: impl FnOnce(&mut Self, &mut Context<S>) -> S,
4361 ) -> Entity<S> {
4362 let current_view = self.current_view();
4363 self.with_global_id(key.into(), |global_id, window| {
4364 window.with_element_state(global_id, |state: Option<Entity<S>>, window| {
4365 if let Some(state) = state {
4366 (state.clone(), state)
4367 } else {
4368 let new_state = cx.new(|cx| init(window, cx));
4369 Self::observe_keyed_state(&new_state, current_view, cx);
4370 (new_state.clone(), new_state)
4371 }
4372 })
4373 })
4374 }
4375
4376 #[track_caller]
4382 pub fn use_state<S: 'static>(
4383 &mut self,
4384 cx: &mut App,
4385 init: impl FnOnce(&mut Self, &mut Context<S>) -> S,
4386 ) -> Entity<S> {
4387 self.use_keyed_state(
4388 ElementId::CodeLocation(*core::panic::Location::caller()),
4389 cx,
4390 init,
4391 )
4392 }
4393
4394 #[inline(always)]
4399 pub fn with_element_state<S, R>(
4400 &mut self,
4401 global_id: &GlobalElementId,
4402 f: impl FnOnce(Option<S>, &mut Self) -> (R, S),
4403 ) -> R
4404 where
4405 S: 'static,
4406 {
4407 self.invalidator.debug_assert_paint_or_prepaint();
4408
4409 let (key, state) = self.take_element_state(global_id, TypeId::of::<S>());
4410
4411 if let Some(any) = state {
4412 let ElementStateBox {
4413 inner,
4414 #[cfg(debug_assertions)]
4415 type_name,
4416 } = any;
4417 let mut state_box = inner
4419 .downcast::<Option<S>>()
4420 .map_err(|_| {
4421 #[cfg(debug_assertions)]
4422 {
4423 anyhow::anyhow!(
4424 "invalid element state type for id, requested {:?}, actual: {:?}",
4425 std::any::type_name::<S>(),
4426 type_name
4427 )
4428 }
4429
4430 #[cfg(not(debug_assertions))]
4431 {
4432 anyhow::anyhow!(
4433 "invalid element state type for id, requested {:?}",
4434 std::any::type_name::<S>(),
4435 )
4436 }
4437 })
4438 .unwrap();
4439
4440 let state = state_box.take().expect(
4441 "reentrant call to with_element_state for the same state type and element id",
4442 );
4443 let (result, state) = f(Some(state), self);
4444 state_box.replace(state);
4445 self.insert_element_state(
4446 key,
4447 ElementStateBox {
4448 inner: state_box,
4449 #[cfg(debug_assertions)]
4450 type_name,
4451 },
4452 );
4453 result
4454 } else {
4455 let (result, state) = f(None, self);
4456 self.insert_element_state(
4457 key,
4458 ElementStateBox {
4459 inner: Box::new(Some(state)),
4460 #[cfg(debug_assertions)]
4461 type_name: std::any::type_name::<S>(),
4462 },
4463 );
4464 result
4465 }
4466 }
4467
4468 pub fn with_optional_element_state<S, R>(
4475 &mut self,
4476 global_id: Option<&GlobalElementId>,
4477 f: impl FnOnce(Option<Option<S>>, &mut Self) -> (R, Option<S>),
4478 ) -> R
4479 where
4480 S: 'static,
4481 {
4482 self.invalidator.debug_assert_paint_or_prepaint();
4483
4484 if let Some(global_id) = global_id {
4485 self.with_element_state(global_id, |state, cx| {
4486 let (result, state) = f(Some(state), cx);
4487 let state =
4488 state.expect("you must return some state when you pass some element id");
4489 (result, state)
4490 })
4491 } else {
4492 let (result, state) = f(None, self);
4493 debug_assert!(
4494 state.is_none(),
4495 "you must not return an element state when passing None for the global id"
4496 );
4497 result
4498 }
4499 }
4500
4501 #[inline]
4503 pub fn with_tab_group<R>(&mut self, index: Option<isize>, f: impl FnOnce(&mut Self) -> R) -> R {
4504 if let Some(index) = index {
4505 self.next_frame.tab_stops.begin_group(index);
4506 let result = f(self);
4507 self.next_frame.tab_stops.end_group();
4508 result
4509 } else {
4510 f(self)
4511 }
4512 }
4513
4514 pub fn defer_draw(
4523 &mut self,
4524 element: AnyElement,
4525 absolute_offset: Point<Pixels>,
4526 priority: usize,
4527 content_mask: Option<ContentMask<Pixels>>,
4528 ) {
4529 self.invalidator.debug_assert_prepaint();
4530 let parent_node = self.next_frame.dispatch_tree.active_node_id().unwrap();
4531 self.next_frame.deferred_draws.push(DeferredDraw {
4532 current_view: self.current_view(),
4533 parent_node,
4534 element_id_stack: self.element_id_stack.clone(),
4535 text_style_stack: self.text_style_stack.clone(),
4536 content_mask,
4537 rem_size: self.rem_size(),
4538 priority,
4539 element: Some(element),
4540 absolute_offset,
4541 prepaint_range: PrepaintStateIndex::default()..PrepaintStateIndex::default(),
4542 paint_range: PaintIndex::default()..PaintIndex::default(),
4543 });
4544 }
4545
4546 pub fn paint_layer<R>(&mut self, bounds: Bounds<Pixels>, f: impl FnOnce(&mut Self) -> R) -> R {
4552 self.invalidator.debug_assert_paint();
4553
4554 let content_mask = self.content_mask();
4555 let clipped_bounds = bounds.intersect(&content_mask.bounds);
4556 if !clipped_bounds.is_empty() {
4557 self.next_frame
4558 .scene
4559 .push_layer(self.cover_bounds(clipped_bounds));
4560 }
4561
4562 let result = f(self);
4563
4564 if !clipped_bounds.is_empty() {
4565 self.next_frame.scene.pop_layer();
4566 }
4567
4568 result
4569 }
4570
4571 pub fn paint_drop_shadows(
4577 &mut self,
4578 bounds: Bounds<Pixels>,
4579 corner_radii: Corners<Pixels>,
4580 shadows: &[BoxShadow],
4581 ) {
4582 self.invalidator.debug_assert_paint();
4583
4584 let scale_factor = self.scale_factor();
4585 let content_mask = self.snapped_content_mask();
4586 let opacity = self.element_opacity();
4587 let element_bounds = self.cover_bounds(bounds);
4588 let element_corner_radii = corner_radii.scale(scale_factor);
4589 for shadow in shadows {
4590 if shadow.inset {
4591 continue;
4592 }
4593 let shadow_bounds = (bounds + shadow.offset).dilate(shadow.spread_radius);
4594 self.next_frame.scene.insert_primitive(Shadow {
4595 order: 0,
4596 blur_radius: shadow.blur_radius.scale(scale_factor),
4597 bounds: self.cover_bounds(shadow_bounds),
4598 content_mask,
4599 corner_radii: corner_radii.scale(scale_factor),
4600 color: shadow.color.opacity(opacity),
4601 element_bounds,
4602 element_corner_radii,
4603 inset: 0,
4604 pad: 0,
4605 });
4606 }
4607 }
4608
4609 pub fn paint_inset_shadows(
4613 &mut self,
4614 bounds: Bounds<Pixels>,
4615 corner_radii: Corners<Pixels>,
4616 shadows: &[BoxShadow],
4617 ) {
4618 self.invalidator.debug_assert_paint();
4619
4620 let scale_factor = self.scale_factor();
4621 let content_mask = self.snapped_content_mask();
4622 let opacity = self.element_opacity();
4623 let element_bounds = self.cover_bounds(bounds);
4624 let element_corner_radii = corner_radii.scale(scale_factor);
4625 for shadow in shadows {
4626 if !shadow.inset {
4627 continue;
4628 }
4629 let hole = (bounds + shadow.offset).dilate(-shadow.spread_radius);
4630 let zero = Pixels::ZERO;
4633 let hole_corner_radii = Corners {
4634 top_left: (corner_radii.top_left - shadow.spread_radius).max(zero),
4635 top_right: (corner_radii.top_right - shadow.spread_radius).max(zero),
4636 bottom_right: (corner_radii.bottom_right - shadow.spread_radius).max(zero),
4637 bottom_left: (corner_radii.bottom_left - shadow.spread_radius).max(zero),
4638 };
4639 self.next_frame.scene.insert_primitive(Shadow {
4640 order: 0,
4641 blur_radius: shadow.blur_radius.scale(scale_factor),
4642 bounds: self.cover_bounds(hole),
4643 content_mask,
4644 corner_radii: hole_corner_radii.scale(scale_factor),
4645 color: shadow.color.opacity(opacity),
4646 element_bounds,
4647 element_corner_radii,
4648 inset: 1,
4649 pad: 0,
4650 });
4651 }
4652 }
4653
4654 fn largest_border_interior(quad: &Quad) -> Bounds<ScaledPixels> {
4655 let radii = &quad.corner_radii;
4656 let widths = &quad.border_widths;
4657 let edge_radii = Edges {
4658 top: radii.top_left.max(radii.top_right),
4659 right: radii.top_right.max(radii.bottom_right),
4660 bottom: radii.bottom_left.max(radii.bottom_right),
4661 left: radii.top_left.max(radii.bottom_left),
4662 };
4663
4664 let antialias_inset = point(ScaledPixels(1.0), ScaledPixels(1.0));
4665 let inset_bounds = |top_left_inset, bottom_right_inset| {
4666 Bounds::from_corners(
4667 quad.bounds.origin + top_left_inset + antialias_inset,
4668 quad.bounds.bottom_right() - bottom_right_inset - antialias_inset,
4669 )
4670 };
4671
4672 let horizontal_band = inset_bounds(
4675 point(widths.left, widths.top.max(edge_radii.top)),
4676 point(widths.right, widths.bottom.max(edge_radii.bottom)),
4677 );
4678 let vertical_band = inset_bounds(
4679 point(widths.left.max(edge_radii.left), widths.top),
4680 point(widths.right.max(edge_radii.right), widths.bottom),
4681 );
4682
4683 let area = |bounds: &Bounds<ScaledPixels>| {
4684 bounds.size.width.0.max(0.) * bounds.size.height.0.max(0.)
4685 };
4686 if area(&horizontal_band) >= area(&vertical_band) {
4687 horizontal_band
4688 } else {
4689 vertical_band
4690 }
4691 }
4692
4693 pub fn paint_quad(&mut self, quad: PaintQuad) {
4703 self.invalidator.debug_assert_paint();
4704
4705 let opacity = self.element_opacity();
4706 let snapped_bounds = self.snap_bounds(quad.bounds);
4707 let snapped_border_widths = self.snap_border_widths(quad.border_widths);
4708 let quad = Quad {
4709 order: 0,
4710 bounds: snapped_bounds,
4711 content_mask: self.snapped_content_mask(),
4712 background: quad.background.opacity(opacity),
4713 border_color: quad.border_color.opacity(opacity),
4714 corner_radii: quad.corner_radii.scale(self.scale_factor()),
4715 border_widths: snapped_border_widths,
4716 border_style: quad.border_style,
4717 };
4718
4719 if !quad.background.is_transparent() {
4720 self.next_frame.scene.insert_primitive(quad);
4721 return;
4722 }
4723
4724 let outer_bounds = quad.bounds;
4727 let inner_bounds = Self::largest_border_interior(&quad);
4728
4729 if inner_bounds.is_empty() {
4730 self.next_frame.scene.insert_primitive(quad);
4731 return;
4732 }
4733
4734 let strips = [
4735 Bounds::from_corners(
4737 outer_bounds.origin,
4738 point(outer_bounds.right(), inner_bounds.top()),
4739 ),
4740 Bounds::from_corners(
4742 point(outer_bounds.left(), inner_bounds.bottom()),
4743 outer_bounds.bottom_right(),
4744 ),
4745 Bounds::from_corners(
4747 point(outer_bounds.left(), inner_bounds.top()),
4748 inner_bounds.bottom_left(),
4749 ),
4750 Bounds::from_corners(
4752 inner_bounds.top_right(),
4753 point(outer_bounds.right(), inner_bounds.bottom()),
4754 ),
4755 ];
4756
4757 for strip in strips {
4758 let content_mask_bounds = quad.content_mask.bounds.intersect(&strip);
4759 if !content_mask_bounds.is_empty() {
4760 self.next_frame.scene.insert_primitive(Quad {
4761 content_mask: ContentMask {
4762 bounds: content_mask_bounds,
4763 },
4764 ..quad
4765 });
4766 }
4767 }
4768 }
4769
4770 pub fn paint_path(&mut self, mut path: Path<Pixels>, color: impl Into<Background>) {
4774 self.invalidator.debug_assert_paint();
4775
4776 let scale_factor = self.scale_factor();
4777 let content_mask = self.content_mask();
4778 let opacity = self.element_opacity();
4779 path.content_mask = content_mask;
4780 let color: Background = color.into();
4781 path.color = color.opacity(opacity);
4782 self.next_frame
4783 .scene
4784 .insert_primitive(path.scale(scale_factor));
4785 }
4786
4787 pub fn paint_underline(
4791 &mut self,
4792 origin: Point<Pixels>,
4793 width: Pixels,
4794 style: &UnderlineStyle,
4795 ) {
4796 self.invalidator.debug_assert_paint();
4797 let underline = self.underline(origin, width, style);
4798 self.next_frame.scene.insert_primitive(underline);
4799 }
4800
4801 pub fn paint_strikethrough(
4805 &mut self,
4806 origin: Point<Pixels>,
4807 width: Pixels,
4808 style: &StrikethroughStyle,
4809 ) {
4810 self.invalidator.debug_assert_paint();
4811
4812 let scale_factor = self.scale_factor();
4813 let height = style.thickness;
4814 let bounds = Bounds {
4815 origin: origin.map(|c| ScaledPixels(round_to_device_pixel(c.0, scale_factor))),
4816 size: size(self.snap_stroke(width), self.snap_stroke(height)),
4817 };
4818 let opacity = self.element_opacity();
4819
4820 self.next_frame.scene.insert_primitive(Underline {
4821 order: 0,
4822 pad: 0,
4823 bounds,
4824 content_mask: self.snapped_content_mask(),
4825 thickness: self.snap_stroke(style.thickness),
4826 color: style.color.unwrap_or_default().opacity(opacity),
4827 wavy: false.into(),
4828 });
4829 }
4830
4831 pub fn paint_glyph(
4840 &mut self,
4841 origin: Point<Pixels>,
4842 font_id: FontId,
4843 glyph_id: GlyphId,
4844 font_size: Pixels,
4845 color: Hsla,
4846 ) -> Result<()> {
4847 self.invalidator.debug_assert_paint();
4848
4849 let element_opacity = self.element_opacity();
4850 let scale_factor = self.scale_factor();
4851 let glyph_origin = origin.scale(scale_factor);
4852
4853 let quantized_origin = Point::new(
4854 round_half_toward_zero(glyph_origin.x.0 * SUBPIXEL_VARIANTS_X as f32)
4855 / SUBPIXEL_VARIANTS_X as f32,
4856 round_half_toward_zero(glyph_origin.y.0 * SUBPIXEL_VARIANTS_Y as f32)
4857 / SUBPIXEL_VARIANTS_Y as f32,
4858 );
4859 let subpixel_variant = Point::new(
4860 (quantized_origin.x.fract() * SUBPIXEL_VARIANTS_X as f32) as u8,
4861 (quantized_origin.y.fract() * SUBPIXEL_VARIANTS_Y as f32) as u8,
4862 );
4863 let integer_origin = quantized_origin.map(|c| ScaledPixels(c.trunc()));
4864 let subpixel_rendering = self.should_use_subpixel_rendering(font_id, font_size);
4865 let dilation = self.text_system().glyph_dilation_for_color(color);
4866 let params = RenderGlyphParams {
4867 font_id,
4868 glyph_id,
4869 font_size,
4870 subpixel_variant,
4871 scale_factor,
4872 is_emoji: false,
4873 subpixel_rendering,
4874 dilation,
4875 };
4876
4877 let raster_bounds = self.text_system().raster_bounds(¶ms)?;
4878 if !raster_bounds.is_zero() {
4879 let tile = self
4880 .sprite_atlas
4881 .get_or_insert_with(params.clone().into(), &mut || {
4882 let (size, bytes) = self.text_system().rasterize_glyph(¶ms)?;
4883 Ok(Some((size, Cow::Owned(bytes))))
4884 })?
4885 .expect("Callback above only errors or returns Some");
4886 let bounds = Bounds {
4887 origin: integer_origin + raster_bounds.origin.map(Into::into),
4888 size: tile.bounds.size.map(Into::into),
4889 };
4890 let content_mask = self.snapped_content_mask();
4891
4892 if subpixel_rendering {
4893 self.next_frame.scene.insert_primitive(SubpixelSprite {
4894 order: 0,
4895 pad: 0,
4896 bounds,
4897 content_mask,
4898 color: color.opacity(element_opacity),
4899 tile,
4900 transformation: TransformationMatrix::unit(),
4901 });
4902 } else {
4903 self.next_frame.scene.insert_primitive(MonochromeSprite {
4904 order: 0,
4905 pad: 0,
4906 bounds,
4907 content_mask,
4908 color: color.opacity(element_opacity),
4909 tile,
4910 transformation: TransformationMatrix::unit(),
4911 });
4912 }
4913 }
4914 Ok(())
4915 }
4916
4917 fn should_use_subpixel_rendering(&self, font_id: FontId, font_size: Pixels) -> bool {
4918 if self.platform_window.background_appearance() != WindowBackgroundAppearance::Opaque {
4919 return false;
4920 }
4921
4922 if !self.platform_window.is_subpixel_rendering_supported() {
4923 return false;
4924 }
4925
4926 let mode = match self.text_rendering_mode.get() {
4927 TextRenderingMode::PlatformDefault => self
4928 .text_system()
4929 .recommended_rendering_mode(font_id, font_size),
4930 mode => mode,
4931 };
4932
4933 mode == TextRenderingMode::Subpixel
4934 }
4935
4936 pub fn paint_emoji(
4945 &mut self,
4946 origin: Point<Pixels>,
4947 font_id: FontId,
4948 glyph_id: GlyphId,
4949 font_size: Pixels,
4950 ) -> Result<()> {
4951 self.invalidator.debug_assert_paint();
4952
4953 let scale_factor = self.scale_factor();
4954 let glyph_origin = origin.scale(scale_factor);
4955 let integer_origin = glyph_origin.map(|c| ScaledPixels(round_half_toward_zero(c.0)));
4956 let params = RenderGlyphParams {
4957 font_id,
4958 glyph_id,
4959 font_size,
4960 subpixel_variant: Default::default(),
4961 scale_factor,
4962 is_emoji: true,
4963 subpixel_rendering: false,
4964 dilation: 0,
4965 };
4966
4967 let raster_bounds = self.text_system().raster_bounds(¶ms)?;
4968 if !raster_bounds.is_zero() {
4969 let tile = self
4970 .sprite_atlas
4971 .get_or_insert_with(params.clone().into(), &mut || {
4972 let (size, bytes) = self.text_system().rasterize_glyph(¶ms)?;
4973 Ok(Some((size, Cow::Owned(bytes))))
4974 })?
4975 .expect("Callback above only errors or returns Some");
4976
4977 let bounds = Bounds {
4978 origin: integer_origin + raster_bounds.origin.map(Into::into),
4979 size: tile.bounds.size.map(Into::into),
4980 };
4981 let content_mask = self.snapped_content_mask();
4982 let opacity = self.element_opacity();
4983
4984 self.next_frame.scene.insert_primitive(PolychromeSprite {
4985 order: 0,
4986 pad: 0,
4987 grayscale: false.into(),
4988 bounds,
4989 corner_radii: Default::default(),
4990 content_mask,
4991 tile,
4992 opacity,
4993 });
4994 }
4995 Ok(())
4996 }
4997
4998 pub fn paint_svg(
5002 &mut self,
5003 bounds: Bounds<Pixels>,
5004 path: SharedString,
5005 mut data: Option<&[u8]>,
5006 transformation: TransformationMatrix,
5007 color: Hsla,
5008 cx: &App,
5009 ) -> Result<()> {
5010 self.invalidator.debug_assert_paint();
5011
5012 let element_opacity = self.element_opacity();
5013 let bounds = self.snap_bounds(bounds);
5014
5015 let params = RenderSvgParams {
5016 path,
5017 size: bounds.size.map(|pixels| {
5018 DevicePixels::from((pixels.0 * SMOOTH_SVG_SCALE_FACTOR).ceil() as i32)
5019 }),
5020 };
5021
5022 let Some(tile) =
5023 self.sprite_atlas
5024 .get_or_insert_with(params.clone().into(), &mut || {
5025 let Some((size, bytes)) = cx.svg_renderer.render_alpha_mask(¶ms, data)?
5026 else {
5027 return Ok(None);
5028 };
5029 Ok(Some((size, Cow::Owned(bytes))))
5030 })?
5031 else {
5032 return Ok(());
5033 };
5034 let content_mask = self.snapped_content_mask();
5035 let svg_bounds = Bounds {
5036 origin: bounds.center()
5037 - Point::new(
5038 ScaledPixels(tile.bounds.size.width.0 as f32 / SMOOTH_SVG_SCALE_FACTOR / 2.),
5039 ScaledPixels(tile.bounds.size.height.0 as f32 / SMOOTH_SVG_SCALE_FACTOR / 2.),
5040 ),
5041 size: tile
5042 .bounds
5043 .size
5044 .map(|value| ScaledPixels(value.0 as f32 / SMOOTH_SVG_SCALE_FACTOR)),
5045 };
5046 let final_bounds = svg_bounds
5047 .map_origin(|value| ScaledPixels(round_half_toward_zero(value.0)))
5048 .map_size(|size| size.ceil());
5049
5050 self.next_frame.scene.insert_primitive(MonochromeSprite {
5051 order: 0,
5052 pad: 0,
5053 bounds: final_bounds,
5054 content_mask,
5055 color: color.opacity(element_opacity),
5056 tile,
5057 transformation,
5058 });
5059
5060 Ok(())
5061 }
5062
5063 pub fn paint_image(
5072 &mut self,
5073 bounds: Bounds<Pixels>,
5074 image_bounds: Bounds<Pixels>,
5075 corner_radii: Corners<Pixels>,
5076 data: Arc<RenderImage>,
5077 frame_index: usize,
5078 grayscale: bool,
5079 ) -> Result<()> {
5080 self.invalidator.debug_assert_paint();
5081
5082 let visible_bounds = bounds.intersect(&image_bounds);
5083 if visible_bounds.size.width <= Pixels::ZERO || visible_bounds.size.height <= Pixels::ZERO {
5084 return Ok(());
5085 }
5086 if image_bounds.size.width <= Pixels::ZERO || image_bounds.size.height <= Pixels::ZERO {
5087 return Ok(());
5088 }
5089
5090 let params = RenderImageParams {
5091 image_id: data.id,
5092 frame_index,
5093 };
5094
5095 let tile = self
5096 .sprite_atlas
5097 .get_or_insert_with(params.into(), &mut || {
5098 Ok(Some((
5099 data.size(frame_index),
5100 Cow::Borrowed(
5101 data.as_bytes(frame_index)
5102 .expect("It's the caller's job to pass a valid frame index"),
5103 ),
5104 )))
5105 })?
5106 .expect("Callback above only returns Some");
5107
5108 let visible_bounds_snapped = self.snap_bounds(visible_bounds);
5109
5110 let sub_tile = if visible_bounds == image_bounds {
5111 tile
5112 } else {
5113 let x_offset_ratio =
5114 (visible_bounds.origin.x - image_bounds.origin.x) / image_bounds.size.width;
5115 let y_offset_ratio =
5116 (visible_bounds.origin.y - image_bounds.origin.y) / image_bounds.size.height;
5117 let width_ratio = visible_bounds.size.width / image_bounds.size.width;
5118 let height_ratio = visible_bounds.size.height / image_bounds.size.height;
5119
5120 let tile_origin_x = tile.bounds.origin.x.0;
5121 let tile_origin_y = tile.bounds.origin.y.0;
5122 let tile_width = tile.bounds.size.width.0;
5123 let tile_height = tile.bounds.size.height.0;
5124
5125 let sub_origin_x = tile_origin_x + (x_offset_ratio * tile_width as f32).round() as i32;
5126 let sub_origin_y = tile_origin_y + (y_offset_ratio * tile_height as f32).round() as i32;
5127 let sub_width = (width_ratio * tile_width as f32).round() as i32;
5128 let sub_height = (height_ratio * tile_height as f32).round() as i32;
5129
5130 let max_x = tile_origin_x + tile_width;
5131 let max_y = tile_origin_y + tile_height;
5132
5133 let clamped_origin_x = sub_origin_x.clamp(tile_origin_x, max_x);
5134 let clamped_origin_y = sub_origin_y.clamp(tile_origin_y, max_y);
5135 let clamped_width = sub_width.min(max_x - clamped_origin_x).max(0);
5136 let clamped_height = sub_height.min(max_y - clamped_origin_y).max(0);
5137
5138 AtlasTile {
5139 bounds: Bounds {
5140 origin: point(
5141 DevicePixels(clamped_origin_x),
5142 DevicePixels(clamped_origin_y),
5143 ),
5144 size: size(DevicePixels(clamped_width), DevicePixels(clamped_height)),
5145 },
5146 ..tile
5147 }
5148 };
5149
5150 let content_mask = self.snapped_content_mask();
5151 let corner_radii = corner_radii
5152 .clamp_radii_for_quad_size(visible_bounds.size)
5153 .scale(self.scale_factor());
5154 let opacity = self.element_opacity();
5155
5156 self.next_frame.scene.insert_primitive(PolychromeSprite {
5157 order: 0,
5158 pad: 0,
5159 grayscale: grayscale.into(),
5160 bounds: visible_bounds_snapped,
5161 content_mask,
5162 corner_radii,
5163 tile: sub_tile,
5164 opacity,
5165 });
5166 Ok(())
5167 }
5168
5169 #[cfg(any(target_os = "macos", target_os = "ios"))]
5173 pub fn paint_surface(
5174 &mut self,
5175 bounds: Bounds<Pixels>,
5176 image_buffer: CFRetained<CVPixelBuffer>,
5177 ) {
5178 use crate::PaintSurface;
5179
5180 self.invalidator.debug_assert_paint();
5181
5182 let bounds = self.snap_bounds(bounds);
5183 let content_mask = self.snapped_content_mask();
5184 self.next_frame.scene.insert_primitive(PaintSurface {
5185 order: 0,
5186 bounds,
5187 content_mask,
5188 image_buffer,
5189 });
5190 }
5191
5192 pub fn drop_image(&mut self, data: Arc<RenderImage>) -> Result<()> {
5194 for frame_index in 0..data.frame_count() {
5195 let params = RenderImageParams {
5196 image_id: data.id,
5197 frame_index,
5198 };
5199
5200 self.sprite_atlas.remove(¶ms.clone().into());
5201 }
5202
5203 Ok(())
5204 }
5205
5206 #[cfg(any(test, feature = "test-support"))]
5208 pub fn has_image_atlas_entry(&self, data: &RenderImage) -> bool {
5209 data.frame_count() > 0
5210 && (0..data.frame_count()).all(|frame_index| {
5211 self.sprite_atlas.contains(
5212 &RenderImageParams {
5213 image_id: data.id,
5214 frame_index,
5215 }
5216 .into(),
5217 )
5218 })
5219 }
5220
5221 #[must_use]
5227 pub fn request_layout(
5228 &mut self,
5229 style: Style,
5230 children: impl IntoIterator<Item = LayoutId>,
5231 cx: &mut App,
5232 ) -> LayoutId {
5233 self.invalidator.debug_assert_prepaint();
5234
5235 cx.layout_id_buffer.clear();
5236 cx.layout_id_buffer.extend(children);
5237 let rem_size = self.rem_size();
5238 let scale_factor = self.scale_factor();
5239
5240 self.layout_engine.as_mut().unwrap().request_layout(
5241 style,
5242 rem_size,
5243 scale_factor,
5244 &cx.layout_id_buffer,
5245 )
5246 }
5247
5248 pub fn request_measured_layout<F>(&mut self, style: Style, measure: F) -> LayoutId
5257 where
5258 F: Fn(Size<Option<Pixels>>, Size<AvailableSpace>, &mut Window, &mut App) -> Size<Pixels>
5259 + 'static,
5260 {
5261 self.invalidator.debug_assert_prepaint();
5262
5263 let rem_size = self.rem_size();
5264 let scale_factor = self.scale_factor();
5265 self.layout_engine
5266 .as_mut()
5267 .unwrap()
5268 .request_measured_layout(style, rem_size, scale_factor, measure)
5269 }
5270
5271 pub fn compute_layout(
5277 &mut self,
5278 layout_id: LayoutId,
5279 available_space: Size<AvailableSpace>,
5280 cx: &mut App,
5281 ) {
5282 self.invalidator.debug_assert_prepaint();
5283
5284 let mut layout_engine = self.layout_engine.take().unwrap();
5285 layout_engine.compute_layout(layout_id, available_space, self, cx);
5286 self.layout_engine = Some(layout_engine);
5287 }
5288
5289 pub fn layout_bounds(&mut self, layout_id: LayoutId) -> Bounds<Pixels> {
5294 self.invalidator.debug_assert_prepaint();
5295
5296 let scale_factor = self.scale_factor();
5297 let mut bounds = self
5298 .layout_engine
5299 .as_mut()
5300 .unwrap()
5301 .layout_bounds(layout_id, scale_factor)
5302 .map(Into::into);
5303 let snapped_offset = self.pixel_snap_point(self.element_offset());
5304 bounds.origin += snapped_offset;
5305 bounds
5306 }
5307
5308 pub fn insert_hitbox(&mut self, bounds: Bounds<Pixels>, behavior: HitboxBehavior) -> Hitbox {
5314 self.invalidator.debug_assert_prepaint();
5315
5316 let content_mask = self.content_mask();
5317 let mut id = self.next_hitbox_id;
5318 self.next_hitbox_id = self.next_hitbox_id.next();
5319 let hitbox = Hitbox {
5320 id,
5321 bounds,
5322 content_mask,
5323 behavior,
5324 };
5325 self.next_frame.hitboxes.push(hitbox.clone());
5326 hitbox
5327 }
5328
5329 pub fn insert_window_control_hitbox(&mut self, area: WindowControlArea, hitbox: Hitbox) {
5333 self.invalidator.debug_assert_paint();
5334 self.next_frame.window_control_hitboxes.push((area, hitbox));
5335 }
5336
5337 pub fn set_key_context(&mut self, context: KeyContext) {
5342 self.invalidator.debug_assert_paint();
5343 self.next_frame.dispatch_tree.set_key_context(context);
5344 }
5345
5346 pub fn set_focus_handle(&mut self, focus_handle: &FocusHandle, _: &App) {
5351 self.invalidator.debug_assert_prepaint();
5352 if focus_handle.is_focused(self) {
5353 self.next_frame.focus = Some(focus_handle.id);
5354 }
5355 self.next_frame.dispatch_tree.set_focus_id(focus_handle.id);
5356 }
5357
5358 pub fn set_view_id(&mut self, view_id: EntityId) {
5364 self.invalidator.debug_assert_prepaint();
5365 self.next_frame.dispatch_tree.set_view_id(view_id);
5366 }
5367
5368 pub fn current_view(&self) -> EntityId {
5370 self.invalidator.debug_assert_paint_or_prepaint();
5371 self.rendered_entity_stack.last().copied().unwrap()
5372 }
5373
5374 #[inline]
5375 pub(crate) fn with_rendered_view<R>(
5376 &mut self,
5377 id: EntityId,
5378 f: impl FnOnce(&mut Self) -> R,
5379 ) -> R {
5380 self.rendered_entity_stack.push(id);
5381 let result = f(self);
5382 self.rendered_entity_stack.pop();
5383 result
5384 }
5385
5386 pub fn with_image_cache<F, R>(&mut self, image_cache: Option<AnyImageCache>, f: F) -> R
5388 where
5389 F: FnOnce(&mut Self) -> R,
5390 {
5391 if let Some(image_cache) = image_cache {
5392 self.image_cache_stack.push(image_cache);
5393 let result = f(self);
5394 self.image_cache_stack.pop();
5395 result
5396 } else {
5397 f(self)
5398 }
5399 }
5400
5401 pub fn handle_input(
5410 &mut self,
5411 focus_handle: &FocusHandle,
5412 input_handler: impl InputHandler,
5413 cx: &App,
5414 ) {
5415 self.invalidator.debug_assert_paint();
5416
5417 if focus_handle.is_focused(self) {
5418 let cx = self.to_async(cx);
5419 self.next_frame.input_handlers.push(Some(
5420 PlatformInputHandler::new(cx, Box::new(input_handler)).with_focus(focus_handle.id),
5421 ));
5422 }
5423 }
5424
5425 pub fn notify_text_input_changed(&self, focus_handle: &FocusHandle) {
5430 if self.focused_text_input == Some(focus_handle.id) && focus_handle.is_focused(self) {
5431 self.platform_window
5432 .text_input_state_changed(TextInputStateChange::ContentChanged);
5433 }
5434 }
5435
5436 pub fn notify_text_selection_changed(&self, focus_handle: &FocusHandle) {
5441 if self.focused_text_input == Some(focus_handle.id) && focus_handle.is_focused(self) {
5442 self.platform_window
5443 .text_input_state_changed(TextInputStateChange::SelectionChanged);
5444 }
5445 }
5446
5447 fn apply_text_input_configuration(&mut self, cx: &mut App) {
5452 let configuration = match self.platform_window.take_input_handler() {
5453 Some(mut input_handler) => {
5454 let configuration = input_handler.text_input_configuration(self, cx);
5455 self.platform_window.set_input_handler(input_handler);
5456 configuration
5457 }
5458 None => TextInputConfiguration::default(),
5459 };
5460 if self.last_text_input_configuration.as_ref() != Some(&configuration) {
5461 self.platform_window
5462 .set_text_input_configuration(configuration.clone());
5463 self.last_text_input_configuration = Some(configuration);
5464 }
5465 }
5466
5467 pub fn on_mouse_event<Event: MouseEvent>(
5473 &mut self,
5474 mut listener: impl FnMut(&Event, DispatchPhase, &mut Window, &mut App) + 'static,
5475 ) {
5476 self.invalidator.debug_assert_paint();
5477
5478 self.next_frame.mouse_listeners.push(Some(Box::new(
5479 move |event: &dyn Any, phase: DispatchPhase, window: &mut Window, cx: &mut App| {
5480 if let Some(event) = event.downcast_ref() {
5481 listener(event, phase, window, cx)
5482 }
5483 },
5484 )));
5485 }
5486
5487 pub fn on_key_event<Event: KeyEvent>(
5496 &mut self,
5497 listener: impl Fn(&Event, DispatchPhase, &mut Window, &mut App) + 'static,
5498 ) {
5499 self.invalidator.debug_assert_paint();
5500
5501 self.next_frame.dispatch_tree.on_key_event(Rc::new(
5502 move |event: &dyn Any, phase, window: &mut Window, cx: &mut App| {
5503 if let Some(event) = event.downcast_ref::<Event>() {
5504 listener(event, phase, window, cx)
5505 }
5506 },
5507 ));
5508 }
5509
5510 pub fn on_modifiers_changed(
5517 &mut self,
5518 listener: impl Fn(&ModifiersChangedEvent, &mut Window, &mut App) + 'static,
5519 ) {
5520 self.invalidator.debug_assert_paint();
5521
5522 self.next_frame.dispatch_tree.on_modifiers_changed(Rc::new(
5523 move |event: &ModifiersChangedEvent, window: &mut Window, cx: &mut App| {
5524 listener(event, window, cx)
5525 },
5526 ));
5527 }
5528
5529 pub fn on_focus_in(
5533 &mut self,
5534 handle: &FocusHandle,
5535 cx: &mut App,
5536 mut listener: impl FnMut(&mut Window, &mut App) + 'static,
5537 ) -> Subscription {
5538 let focus_id = handle.id;
5539 let (subscription, activate) =
5540 self.new_focus_listener(Box::new(move |event, window, cx| {
5541 if event.is_focus_in(focus_id) {
5542 listener(window, cx);
5543 }
5544 true
5545 }));
5546 cx.defer(move |_| activate());
5547 subscription
5548 }
5549
5550 pub fn on_focus_out(
5553 &mut self,
5554 handle: &FocusHandle,
5555 cx: &mut App,
5556 mut listener: impl FnMut(FocusOutEvent, &mut Window, &mut App) + 'static,
5557 ) -> Subscription {
5558 let focus_id = handle.id;
5559 let (subscription, activate) =
5560 self.new_focus_listener(Box::new(move |event, window, cx| {
5561 if let Some(blurred_id) = event.previous_focus_path.last().copied()
5562 && event.is_focus_out(focus_id)
5563 {
5564 let event = FocusOutEvent {
5565 blurred: WeakFocusHandle {
5566 id: blurred_id,
5567 handles: Arc::downgrade(&cx.focus_handles),
5568 },
5569 };
5570 listener(event, window, cx)
5571 }
5572 true
5573 }));
5574 cx.defer(move |_| activate());
5575 subscription
5576 }
5577
5578 fn reset_cursor_style(&self, cx: &mut App) {
5579 if self.is_window_hovered() {
5581 let style = self
5582 .rendered_frame
5583 .cursor_style(self)
5584 .unwrap_or(CursorStyle::Arrow);
5585 cx.platform.set_cursor_style(style);
5586 }
5587 }
5588
5589 pub fn dispatch_keystroke(&mut self, keystroke: Keystroke, cx: &mut App) -> bool {
5592 let keystroke = keystroke.with_simulated_ime();
5593 let result = self.dispatch_event(
5594 PlatformInput::KeyDown(KeyDownEvent {
5595 keystroke: keystroke.clone(),
5596 is_held: false,
5597 prefer_character_input: false,
5598 }),
5599 cx,
5600 );
5601 if !result.propagate {
5602 return true;
5603 }
5604
5605 if let Some(input) = keystroke.key_char
5606 && let Some(mut input_handler) = self.platform_window.take_input_handler()
5607 {
5608 input_handler.dispatch_input(&input, self, cx);
5609 self.platform_window.set_input_handler(input_handler);
5610 return true;
5611 }
5612
5613 false
5614 }
5615
5616 pub fn keystroke_text_for(&self, action: &dyn Action, cx: &App) -> String {
5619 self.highest_precedence_binding_for_action(action)
5620 .map(|binding| {
5621 binding
5622 .keystrokes()
5623 .iter()
5624 .map(|keystroke| keystroke.display(cx.platform_info().os).to_string())
5625 .collect::<Vec<_>>()
5626 .join(" ")
5627 })
5628 .unwrap_or_else(|| action.name().to_string())
5629 }
5630
5631 #[profiling::function]
5633 pub fn dispatch_event(&mut self, event: PlatformInput, cx: &mut App) -> DispatchEventResult {
5634 #[cfg(feature = "profiler")]
5635 self.window_profiler.begin_input(event.kind_name());
5636 let update_count_before = self.invalidator.update_count();
5637 let old_modality = self.last_input_modality;
5641 self.last_input_modality = match &event {
5642 PlatformInput::KeyDown(_) => InputModality::Keyboard,
5643 PlatformInput::MouseMove(_) | PlatformInput::MouseDown(_) => InputModality::Mouse,
5644 PlatformInput::Touch(_) => InputModality::Touch,
5645 _ => self.last_input_modality,
5646 };
5647 if self.last_input_modality != old_modality {
5648 self.refresh();
5649 }
5650
5651 cx.propagate_event = true;
5653 self.default_prevented = false;
5655
5656 let event = match event {
5657 PlatformInput::MouseMove(mouse_move) => {
5660 self.mouse_position = mouse_move.position;
5661 self.modifiers = mouse_move.modifiers;
5662 PlatformInput::MouseMove(mouse_move)
5663 }
5664 PlatformInput::MouseDown(mouse_down) => {
5665 self.mouse_position = mouse_down.position;
5666 self.modifiers = mouse_down.modifiers;
5667 PlatformInput::MouseDown(mouse_down)
5668 }
5669 PlatformInput::MouseUp(mouse_up) => {
5670 self.mouse_position = mouse_up.position;
5671 self.modifiers = mouse_up.modifiers;
5672 PlatformInput::MouseUp(mouse_up)
5673 }
5674 PlatformInput::MousePressure(mouse_pressure) => {
5675 PlatformInput::MousePressure(mouse_pressure)
5676 }
5677 PlatformInput::MouseExited(mouse_exited) => {
5678 self.modifiers = mouse_exited.modifiers;
5679 PlatformInput::MouseExited(mouse_exited)
5680 }
5681 PlatformInput::ModifiersChanged(modifiers_changed) => {
5682 self.modifiers = modifiers_changed.modifiers;
5683 self.capslock = modifiers_changed.capslock;
5684 PlatformInput::ModifiersChanged(modifiers_changed)
5685 }
5686 PlatformInput::Scroll(scroll_wheel) => {
5687 self.mouse_position = scroll_wheel.position;
5688 self.modifiers = scroll_wheel.modifiers;
5689 PlatformInput::Scroll(scroll_wheel)
5690 }
5691 PlatformInput::Pinch(pinch) => {
5692 self.mouse_position = pinch.position;
5693 self.modifiers = pinch.modifiers;
5694 PlatformInput::Pinch(pinch)
5695 }
5696 PlatformInput::FileDrop(file_drop) => match file_drop {
5699 FileDropEvent::Entered { position, paths } => {
5700 self.mouse_position = position;
5701 let source_window = self.handle.window_id();
5702 if !cx.restore_platform_drag(source_window) && cx.active_drag.is_none() {
5703 cx.active_drag = Some(AnyDrag {
5704 value: Arc::new(paths.clone()),
5705 view: cx.new(|_| paths).into(),
5706 cursor_offset: position,
5707 cursor_style: None,
5708 external_payload_source: None,
5709 });
5710 }
5711 PlatformInput::MouseMove(MouseMoveEvent {
5712 position,
5713 pressed_button: Some(MouseButton::Left),
5714 modifiers: Modifiers::default(),
5715 })
5716 }
5717 FileDropEvent::Pending { position } => {
5718 self.mouse_position = position;
5719 PlatformInput::MouseMove(MouseMoveEvent {
5720 position,
5721 pressed_button: Some(MouseButton::Left),
5722 modifiers: Modifiers::default(),
5723 })
5724 }
5725 FileDropEvent::Submit { position } => {
5726 cx.activate(true);
5727 self.mouse_position = position;
5728 PlatformInput::MouseUp(MouseUpEvent {
5729 button: MouseButton::Left,
5730 position,
5731 modifiers: Modifiers::default(),
5732 click_count: 1,
5733 })
5734 }
5735 FileDropEvent::Exited => {
5736 if !cx.hand_restored_drag_to_platform(self.handle.window_id()) {
5737 cx.active_drag.take();
5738 }
5739 self.refresh();
5740 PlatformInput::FileDrop(FileDropEvent::Exited)
5741 }
5742 FileDropEvent::Ended => {
5743 cx.end_platform_drag(self.handle.window_id());
5744 self.refresh();
5745 PlatformInput::FileDrop(FileDropEvent::Ended)
5746 }
5747 },
5748 PlatformInput::Touch(touch) => PlatformInput::Touch(touch),
5749 PlatformInput::LongPress(long_press) => {
5750 self.mouse_position = if long_press.phase == crate::TouchPhase::Started {
5751 long_press.start_position
5752 } else {
5753 long_press.position
5754 };
5755 if long_press.phase == crate::TouchPhase::Started {
5756 self.long_press_capture = None;
5757 }
5758 PlatformInput::LongPress(long_press)
5759 }
5760 PlatformInput::TouchDrag(touch_drag) => {
5761 self.mouse_position = touch_drag.start_position;
5762 PlatformInput::TouchDrag(touch_drag)
5763 }
5764 PlatformInput::BackGesture(back) => {
5765 self.mouse_position = back.start_position;
5766 PlatformInput::BackGesture(back)
5767 }
5768 PlatformInput::KeyDown(_) | PlatformInput::KeyUp(_) => event,
5769 };
5770
5771 if let Some(any_mouse_event) = event.mouse_event() {
5772 self.dispatch_mouse_event(any_mouse_event, cx);
5773 } else if let Some(any_key_event) = event.keyboard_event() {
5774 self.dispatch_key_event(any_key_event, cx);
5775 } else if let Some(touch_event) = event.touch_event() {
5776 self.dispatch_touch_event(touch_event, cx);
5777 }
5778 if let PlatformInput::LongPress(long_press) = &event {
5779 match long_press.phase {
5780 crate::TouchPhase::Started if !self.default_prevented => {
5781 self.long_press_capture = None;
5782 }
5783 crate::TouchPhase::Ended | crate::TouchPhase::Cancelled => {
5784 self.long_press_capture = None;
5785 }
5786 crate::TouchPhase::Started | crate::TouchPhase::Moved => {}
5787 }
5788 }
5789
5790 self.promote_external_drag_to_platform(&event, cx);
5793
5794 let caused_invalidation = self.invalidator.update_count() > update_count_before;
5795 if caused_invalidation {
5796 self.input_rate_tracker.borrow_mut().record_input();
5797 }
5798 #[cfg(feature = "profiler")]
5799 self.window_profiler.end_input(caused_invalidation);
5800
5801 DispatchEventResult {
5802 propagate: cx.propagate_event,
5803 default_prevented: self.default_prevented,
5804 }
5805 }
5806
5807 fn promote_external_drag_to_platform(&mut self, event: &PlatformInput, cx: &mut App) {
5808 let PlatformInput::MouseMove(mouse_move) = event else {
5809 return;
5810 };
5811 if mouse_move.pressed_button != Some(MouseButton::Left) {
5812 return;
5813 }
5814 if Bounds::new(Point::default(), self.viewport_size).contains(&mouse_move.position) {
5815 return;
5816 }
5817 if !self.platform_window.can_start_external_drag() {
5818 return;
5819 }
5820 let Some(payload_source) = cx
5821 .active_drag
5822 .as_mut()
5823 .and_then(|drag| drag.external_payload_source.take())
5824 else {
5825 return;
5826 };
5827 let Some(payload) = payload_source(self, cx) else {
5828 return;
5829 };
5830 if self.platform_window.start_external_drag(&payload)
5831 && cx.hand_active_drag_to_platform(self.handle.window_id())
5832 {
5833 self.refresh();
5834 }
5835 }
5836
5837 pub fn touch_prediction_enabled(&self) -> bool {
5841 self.touch_prediction_enabled
5842 }
5843
5844 pub fn set_touch_prediction_enabled(&mut self, enabled: bool) {
5848 self.touch_prediction_enabled = enabled;
5849 }
5850
5851 fn dispatch_touch_event(&mut self, event: &TouchEvent, cx: &mut App) {
5855 let mut event = event.clone();
5856 if !self.touch_prediction_enabled {
5857 event.predicted_position = None;
5858 }
5859 let recognized_gestures = self.touch_gestures.handle_event(&event);
5860 if event.phase == crate::TouchPhase::Started
5861 && let Some(touch_drag) = self.touch_gestures.offer_touch_drag(event.id)
5862 {
5863 self.dispatch_recognized_touch_gesture(touch_drag, cx);
5864 }
5865 if event.phase == crate::TouchPhase::Started
5866 && self.touch_gestures.pending_long_press().is_some()
5867 {
5868 self.long_press_capture = None;
5869 }
5870 let mut tapped = false;
5871 for gesture in recognized_gestures {
5872 tapped |= matches!(gesture, RecognizedTouchGesture::Tap { .. });
5873 self.dispatch_recognized_touch_gesture(gesture, cx);
5874 }
5875 if event.phase == crate::TouchPhase::Started {
5876 self.schedule_long_press_timer(cx);
5877 } else if self.touch_gestures.pending_long_press().is_none() {
5878 self.long_press_timer.take();
5879 }
5880 if tapped && self.invalidator.is_dirty() {
5886 self.draw(cx).clear(cx);
5887 }
5888 if self.touch_gestures.has_momentum() {
5889 self.schedule_touch_momentum_tick();
5890 }
5891 }
5892
5893 fn dispatch_recognized_touch_gesture(&mut self, gesture: RecognizedTouchGesture, cx: &mut App) {
5894 match gesture {
5895 RecognizedTouchGesture::Scroll(scroll_wheel) => {
5896 self.mouse_position = scroll_wheel.position;
5897 cx.propagate_event = true;
5898 self.dispatch_mouse_event(&scroll_wheel, cx);
5899 }
5900 RecognizedTouchGesture::Tap { down, up } => {
5901 self.mouse_position = up.position;
5902 cx.propagate_event = true;
5903 self.dispatch_mouse_event(&down, cx);
5904 cx.propagate_event = true;
5905 self.dispatch_mouse_event(&up, cx);
5906 }
5907 RecognizedTouchGesture::TouchDrag(touch_drag) => {
5908 self.mouse_position = touch_drag.start_position;
5909 cx.propagate_event = true;
5910 self.default_prevented = false;
5911 let started = touch_drag.phase == crate::TouchPhase::Started;
5912 self.dispatch_mouse_event(&touch_drag, cx);
5913 if started {
5914 self.touch_gestures
5915 .resolve_touch_drag(self.default_prevented);
5916 }
5917 }
5918 RecognizedTouchGesture::LongPress(long_press) => {
5919 self.mouse_position = if long_press.phase == crate::TouchPhase::Started {
5920 long_press.start_position
5921 } else {
5922 long_press.position
5923 };
5924 cx.propagate_event = true;
5925 self.default_prevented = false;
5926 let started = long_press.phase == crate::TouchPhase::Started;
5927 let ended = matches!(
5928 long_press.phase,
5929 crate::TouchPhase::Ended | crate::TouchPhase::Cancelled
5930 );
5931 self.dispatch_mouse_event(&long_press, cx);
5932 if started {
5933 let claimed = self.default_prevented;
5934 self.touch_gestures.resolve_long_press(claimed);
5935 if !claimed {
5936 self.long_press_capture = None;
5937 }
5938 }
5939 if ended {
5940 self.long_press_capture = None;
5941 }
5942 }
5943 }
5944 }
5945
5946 fn schedule_long_press_timer(&mut self, cx: &mut App) {
5947 self.long_press_timer.take();
5948 let Some((touch_id, duration)) = self.touch_gestures.pending_long_press() else {
5949 return;
5950 };
5951 self.long_press_timer = Some(self.spawn(cx, async move |cx| {
5952 cx.background_executor.timer(duration).await;
5953 cx.update(move |window, cx| {
5954 window.long_press_timer.take();
5955 if let Some(gesture) = window.touch_gestures.offer_long_press(touch_id) {
5956 window.dispatch_recognized_touch_gesture(gesture, cx);
5957 }
5958 })
5959 .log_err();
5960 }));
5961 }
5962
5963 fn schedule_touch_momentum_tick(&mut self) {
5964 self.on_next_frame(|window, cx| {
5965 if let Some(gesture) = window.touch_gestures.tick_momentum() {
5966 window.dispatch_recognized_touch_gesture(gesture, cx);
5967 }
5968 if window.touch_gestures.has_momentum() {
5969 window.schedule_touch_momentum_tick();
5970 }
5971 });
5972 }
5973
5974 fn dispatch_mouse_event(&mut self, event: &dyn Any, cx: &mut App) {
5975 let hit_test = self.rendered_frame.hit_test(self.mouse_position());
5976 if hit_test != self.mouse_hit_test {
5977 self.mouse_hit_test = hit_test;
5978 self.reset_cursor_style(cx);
5979 }
5980
5981 #[cfg(any(feature = "inspector", debug_assertions))]
5982 if self.is_inspector_picking(cx) {
5983 self.handle_inspector_mouse_event(event, cx);
5984 return;
5986 }
5987
5988 let mut mouse_listeners = mem::take(&mut self.rendered_frame.mouse_listeners);
5989
5990 for listener in &mut mouse_listeners {
5993 let listener = listener.as_mut().unwrap();
5994 listener(event, DispatchPhase::Capture, self, cx);
5995 if !cx.propagate_event {
5996 break;
5997 }
5998 }
5999
6000 if cx.propagate_event {
6002 for listener in mouse_listeners.iter_mut().rev() {
6003 let listener = listener.as_mut().unwrap();
6004 listener(event, DispatchPhase::Bubble, self, cx);
6005 if !cx.propagate_event {
6006 break;
6007 }
6008 }
6009 }
6010
6011 self.rendered_frame.mouse_listeners = mouse_listeners;
6012
6013 if cx.has_active_drag() {
6014 if event.is::<MouseMoveEvent>() {
6015 self.refresh();
6018 } else if event.is::<MouseUpEvent>() {
6019 cx.active_drag = None;
6022 self.refresh();
6023 }
6024 }
6025
6026 if event.is::<MouseUpEvent>() && self.captured_hitbox.is_some() {
6028 self.captured_hitbox = None;
6029 }
6030 }
6031
6032 fn input_preference(&mut self, event: &dyn Any, cx: &mut App) -> InputPreference {
6035 let prefer_character_input = event
6036 .downcast_ref::<KeyDownEvent>()
6037 .is_some_and(|key_down_event| key_down_event.prefer_character_input);
6038 if !prefer_character_input {
6039 return InputPreference::KeyBindings;
6040 }
6041 let Some(mut input_handler) = self.platform_window.take_input_handler() else {
6042 return InputPreference::KeyBindings;
6043 };
6044 let accepts_text_input = input_handler.accepts_text_input(self, cx);
6045 self.platform_window.set_input_handler(input_handler);
6046 if accepts_text_input {
6047 InputPreference::CharacterInput
6048 } else {
6049 InputPreference::KeyBindings
6050 }
6051 }
6052
6053 fn dispatch_key_event(&mut self, event: &dyn Any, cx: &mut App) {
6054 if self.invalidator.is_dirty() {
6055 self.draw(cx).clear(cx);
6056 }
6057
6058 let node_id = self.focus_node_id_in_rendered_frame(self.focus);
6059 let dispatch_path = self.rendered_frame.dispatch_tree.dispatch_path(node_id);
6060
6061 let mut keystroke: Option<Keystroke> = None;
6062
6063 if let Some(event) = event.downcast_ref::<ModifiersChangedEvent>() {
6064 if event.modifiers.number_of_modifiers() == 0
6065 && self.pending_modifier.modifiers.number_of_modifiers() == 1
6066 && !self.pending_modifier.saw_other_input
6067 {
6068 let key = match self.pending_modifier.modifiers {
6069 modifiers if modifiers.shift => Some("shift"),
6070 modifiers if modifiers.control => Some("control"),
6071 modifiers if modifiers.alt => Some("alt"),
6072 modifiers if modifiers.platform => Some("platform"),
6073 modifiers if modifiers.function => Some("function"),
6074 _ => None,
6075 };
6076 if let Some(key) = key {
6077 keystroke = Some(Keystroke {
6078 key: key.to_string(),
6079 key_char: None,
6080 modifiers: Modifiers::default(),
6081 });
6082 }
6083 }
6084
6085 if self.pending_modifier.modifiers.number_of_modifiers() == 0
6086 && event.modifiers.number_of_modifiers() == 1
6087 {
6088 self.pending_modifier.saw_other_input = false
6089 } else if event.modifiers.number_of_modifiers() > 1 {
6090 self.pending_modifier.saw_other_input = true
6091 }
6092 self.pending_modifier.modifiers = event.modifiers
6093 } else if let Some(key_down_event) = event.downcast_ref::<KeyDownEvent>() {
6094 self.pending_modifier.saw_other_input = true;
6095 keystroke = Some(key_down_event.keystroke.clone());
6096 if key_down_event.keystroke.key_char.is_some()
6097 && matches!(
6098 cx.cursor_hide_mode,
6099 CursorHideMode::OnTyping | CursorHideMode::OnTypingAndAction
6100 )
6101 {
6102 cx.platform.hide_cursor_until_mouse_moves();
6103 }
6104 }
6105
6106 let Some(keystroke) = keystroke else {
6107 self.finish_dispatch_key_event(
6108 event,
6109 None,
6110 InputPreference::KeyBindings,
6111 dispatch_path,
6112 self.context_stack(),
6113 cx,
6114 );
6115 return;
6116 };
6117
6118 let input_preference = self.input_preference(event, cx);
6119
6120 cx.propagate_event = true;
6121 self.dispatch_keystroke_interceptors(
6122 &keystroke,
6123 input_preference,
6124 self.context_stack(),
6125 cx,
6126 );
6127 if !cx.propagate_event {
6128 self.finish_dispatch_key_event(
6129 event,
6130 Some(&keystroke),
6131 input_preference,
6132 dispatch_path,
6133 self.context_stack(),
6134 cx,
6135 );
6136 return;
6137 }
6138
6139 let mut currently_pending = self.pending_input.take().unwrap_or_default();
6140 if currently_pending.focus.is_some() && currently_pending.focus != self.focus {
6141 currently_pending = PendingInput::default();
6142 }
6143
6144 let match_result = self.rendered_frame.dispatch_tree.dispatch_key(
6145 currently_pending.keystrokes,
6146 keystroke.clone(),
6147 &dispatch_path,
6148 );
6149
6150 if !match_result.to_replay.is_empty() {
6151 self.replay_pending_input(match_result.to_replay, cx);
6152 cx.propagate_event = true;
6153 }
6154
6155 if !match_result.pending.is_empty() {
6156 let previous_timeout = currently_pending.timeout.take();
6157 currently_pending.keystrokes = match_result.pending;
6158 currently_pending.focus = self.focus;
6159
6160 let text_input_requires_timeout = event
6161 .downcast_ref::<KeyDownEvent>()
6162 .filter(|key_down| key_down.keystroke.key_char.is_some())
6163 .and_then(|_| self.platform_window.take_input_handler())
6164 .map_or(false, |mut input_handler| {
6165 let accepts = input_handler.accepts_text_input(self, cx);
6166 self.platform_window.set_input_handler(input_handler);
6167 accepts
6168 });
6169
6170 let needs_timeout = previous_timeout.is_some()
6171 || match_result.pending_has_binding
6172 || text_input_requires_timeout;
6173 currently_pending.timeout = if needs_timeout {
6174 match previous_timeout {
6175 Some(mut timeout) if timeout.is_paused() => {
6176 timeout.reset_duration(PENDING_INPUT_TIMEOUT);
6177 Some(timeout)
6178 }
6179 previous_timeout => {
6180 drop(previous_timeout);
6181 Some(self.new_pending_input_timeout(PENDING_INPUT_TIMEOUT, cx))
6182 }
6183 }
6184 } else {
6185 None
6186 };
6187 self.pending_input = Some(currently_pending);
6188 self.pending_input_changed(cx);
6189 cx.propagate_event = false;
6190 return;
6191 }
6192
6193 let input_preference = self.input_preference(event, cx);
6195 if input_preference == InputPreference::KeyBindings {
6196 for binding in match_result.bindings {
6197 self.dispatch_action_on_node(node_id, binding.action.as_ref(), cx);
6198 if !cx.propagate_event {
6199 self.dispatch_keystroke_observers(
6200 &keystroke,
6201 input_preference,
6202 Some(binding.action.as_ref()),
6203 match_result.context_stack,
6204 cx,
6205 );
6206 self.pending_input_changed(cx);
6207 return;
6208 }
6209 }
6210 }
6211
6212 self.finish_dispatch_key_event(
6213 event,
6214 Some(&keystroke),
6215 input_preference,
6216 dispatch_path,
6217 match_result.context_stack,
6218 cx,
6219 );
6220 self.pending_input_changed(cx);
6221 }
6222
6223 fn new_pending_input_timeout(&self, duration: Duration, cx: &App) -> PendingInputTimeout {
6224 let (started_at, task) = self.start_pending_input_timeout(duration, cx);
6225 PendingInputTimeout {
6226 duration,
6227 remaining: duration,
6228 state: PendingInputTimeoutState::Running { started_at, task },
6229 }
6230 }
6231
6232 fn start_pending_input_timeout(&self, remaining: Duration, cx: &App) -> (Instant, Task<()>) {
6233 let started_at = cx.background_executor().now();
6234 let task = self.spawn(cx, async move |cx| {
6235 cx.background_executor.timer(remaining).await;
6236 cx.update(move |window, cx| {
6237 let Some(currently_pending) = window
6238 .pending_input
6239 .take()
6240 .filter(|pending| pending.focus == window.focus)
6241 else {
6242 return;
6243 };
6244
6245 let node_id = window.focus_node_id_in_rendered_frame(window.focus);
6246 let dispatch_path = window.rendered_frame.dispatch_tree.dispatch_path(node_id);
6247
6248 let to_replay = window
6249 .rendered_frame
6250 .dispatch_tree
6251 .flush_dispatch(currently_pending.keystrokes, &dispatch_path);
6252
6253 window.pending_input_changed(cx);
6254 window.replay_pending_input(to_replay, cx)
6255 })
6256 .log_err();
6257 });
6258 (started_at, task)
6259 }
6260
6261 fn finish_dispatch_key_event(
6262 &mut self,
6263 event: &dyn Any,
6264 recognized_keystroke: Option<&Keystroke>,
6265 input_preference: InputPreference,
6266 dispatch_path: SmallVec<[DispatchNodeId; 32]>,
6267 context_stack: Vec<KeyContext>,
6268 cx: &mut App,
6269 ) {
6270 self.dispatch_key_down_up_event(event, &dispatch_path, cx);
6271 if !cx.propagate_event {
6272 return;
6273 }
6274
6275 self.dispatch_modifiers_changed_event(event, &dispatch_path, cx);
6276 if !cx.propagate_event {
6277 return;
6278 }
6279
6280 if let Some(keystroke) = recognized_keystroke {
6281 self.dispatch_keystroke_observers(keystroke, input_preference, None, context_stack, cx);
6282 }
6283 }
6284
6285 pub(crate) fn pending_input_changed(&mut self, cx: &mut App) {
6286 self.pending_input_observers
6287 .clone()
6288 .retain(&(), |callback| callback(self, cx));
6289 }
6290
6291 fn defer_pending_input_changed(&self, cx: &mut App) {
6292 let window_handle = self.handle;
6295 cx.defer(move |cx| {
6296 window_handle
6297 .update(cx, |_, window, cx| {
6298 window.pending_input_changed(cx);
6299 })
6300 .ok();
6301 });
6302 }
6303
6304 fn dispatch_key_down_up_event(
6305 &mut self,
6306 event: &dyn Any,
6307 dispatch_path: &SmallVec<[DispatchNodeId; 32]>,
6308 cx: &mut App,
6309 ) {
6310 for node_id in dispatch_path {
6312 let node = self.rendered_frame.dispatch_tree.node(*node_id);
6313
6314 for key_listener in node.key_listeners.clone() {
6315 key_listener(event, DispatchPhase::Capture, self, cx);
6316 if !cx.propagate_event {
6317 return;
6318 }
6319 }
6320 }
6321
6322 for node_id in dispatch_path.iter().rev() {
6324 let node = self.rendered_frame.dispatch_tree.node(*node_id);
6326 for key_listener in node.key_listeners.clone() {
6327 key_listener(event, DispatchPhase::Bubble, self, cx);
6328 if !cx.propagate_event {
6329 return;
6330 }
6331 }
6332 }
6333 }
6334
6335 fn dispatch_modifiers_changed_event(
6336 &mut self,
6337 event: &dyn Any,
6338 dispatch_path: &SmallVec<[DispatchNodeId; 32]>,
6339 cx: &mut App,
6340 ) {
6341 let Some(event) = event.downcast_ref::<ModifiersChangedEvent>() else {
6342 return;
6343 };
6344 for node_id in dispatch_path.iter().rev() {
6345 let node = self.rendered_frame.dispatch_tree.node(*node_id);
6346 for listener in node.modifiers_changed_listeners.clone() {
6347 listener(event, self, cx);
6348 if !cx.propagate_event {
6349 return;
6350 }
6351 }
6352 }
6353 }
6354
6355 pub fn has_pending_keystrokes(&self) -> bool {
6357 self.pending_input().is_some()
6358 }
6359
6360 #[cfg(test)]
6361 pub(crate) fn pending_input_is_none(&self) -> bool {
6362 self.pending_input.is_none()
6363 }
6364
6365 pub(crate) fn clear_pending_keystrokes(&mut self, cx: &mut App) {
6366 if self.pending_input.take().is_some() {
6367 self.defer_pending_input_changed(cx);
6368 }
6369 }
6370
6371 pub fn pending_input(&self) -> Option<PendingInputStatus<'_>> {
6374 self.pending_input
6375 .as_ref()
6376 .filter(|pending_input| pending_input.focus == self.focus)
6377 .map(|pending_input| PendingInputStatus {
6378 keystrokes: pending_input.keystrokes.as_slice(),
6379 timeout: pending_input
6380 .timeout
6381 .as_ref()
6382 .map(PendingInputTimeout::status),
6383 })
6384 }
6385
6386 pub fn set_pending_input_timeout_paused<T: 'static>(
6391 &mut self,
6392 owner: &Entity<T>,
6393 paused: bool,
6394 cx: &mut App,
6395 ) -> bool {
6396 let owner_id = owner.entity_id();
6397 if !paused {
6398 return self.resume_pending_input_timeout(owner_id, cx);
6399 }
6400
6401 let timeout = self
6402 .pending_input
6403 .as_ref()
6404 .filter(|pending_input| pending_input.focus == self.focus)
6405 .and_then(|pending_input| pending_input.timeout.as_ref());
6406 let Some(timeout) = timeout else {
6407 return false;
6408 };
6409 if timeout.is_paused() {
6410 return false;
6411 }
6412
6413 let release_subscription = self.observe_release(owner, cx, move |_, window, cx| {
6414 window.resume_pending_input_timeout(owner_id, cx);
6415 });
6416 let now = cx.background_executor().now();
6417 let changed = self
6418 .pending_input
6419 .as_mut()
6420 .filter(|pending_input| pending_input.focus == self.focus)
6421 .and_then(|pending_input| pending_input.timeout.as_mut())
6422 .is_some_and(|timeout| {
6423 timeout.pause(
6424 PendingInputTimeoutPause {
6425 owner_id,
6426 _release_subscription: release_subscription,
6427 },
6428 now,
6429 )
6430 });
6431
6432 if changed {
6433 self.defer_pending_input_changed(cx);
6434 }
6435 changed
6436 }
6437
6438 fn resume_pending_input_timeout(&mut self, owner_id: EntityId, cx: &mut App) -> bool {
6439 let Some(remaining) = self
6440 .pending_input
6441 .as_ref()
6442 .and_then(|pending_input| pending_input.timeout.as_ref())
6443 .filter(|timeout| timeout.pause_owner_id() == Some(owner_id))
6444 .map(|timeout| timeout.remaining)
6445 else {
6446 return false;
6447 };
6448
6449 let (started_at, task) = self.start_pending_input_timeout(remaining, cx);
6450 let changed = self
6451 .pending_input
6452 .as_mut()
6453 .and_then(|pending_input| pending_input.timeout.as_mut())
6454 .is_some_and(|timeout| timeout.resume(owner_id, started_at, task));
6455
6456 if changed {
6457 self.defer_pending_input_changed(cx);
6458 }
6459 changed
6460 }
6461
6462 pub fn pending_input_keystrokes(&self) -> Option<&[Keystroke]> {
6464 self.pending_input()
6465 .map(|pending_input| pending_input.keystrokes())
6466 }
6467
6468 fn replay_pending_input(&mut self, replays: SmallVec<[Replay; 1]>, cx: &mut App) {
6469 let node_id = self.focus_node_id_in_rendered_frame(self.focus);
6470 let dispatch_path = self.rendered_frame.dispatch_tree.dispatch_path(node_id);
6471
6472 'replay: for replay in replays {
6473 let event = KeyDownEvent {
6474 keystroke: replay.keystroke.clone(),
6475 is_held: false,
6476 prefer_character_input: true,
6477 };
6478
6479 cx.propagate_event = true;
6480 for binding in replay.bindings {
6481 self.dispatch_action_on_node(node_id, binding.action.as_ref(), cx);
6482 if !cx.propagate_event {
6483 self.dispatch_keystroke_observers(
6484 &replay.keystroke,
6485 InputPreference::KeyBindings,
6486 Some(binding.action.as_ref()),
6487 Vec::default(),
6488 cx,
6489 );
6490 continue 'replay;
6491 }
6492 }
6493
6494 self.dispatch_key_down_up_event(&event, &dispatch_path, cx);
6495 if !cx.propagate_event {
6496 continue 'replay;
6497 }
6498 if let Some(input) = replay.keystroke.key_char.as_ref().cloned()
6499 && let Some(mut input_handler) = self.platform_window.take_input_handler()
6500 {
6501 input_handler.dispatch_input(&input, self, cx);
6502 self.platform_window.set_input_handler(input_handler)
6503 }
6504 }
6505 }
6506
6507 fn focus_node_id_in_rendered_frame(&self, focus_id: Option<FocusId>) -> DispatchNodeId {
6508 focus_id
6509 .and_then(|focus_id| {
6510 self.rendered_frame
6511 .dispatch_tree
6512 .focusable_node_id(focus_id)
6513 })
6514 .unwrap_or_else(|| self.rendered_frame.dispatch_tree.root_node_id())
6515 }
6516
6517 fn dispatch_action_on_node(
6518 &mut self,
6519 node_id: DispatchNodeId,
6520 action: &dyn Action,
6521 cx: &mut App,
6522 ) {
6523 self.dispatch_action_on_node_inner(node_id, action, cx);
6524
6525 if !cx.propagate_event
6526 && cx.cursor_hide_mode == CursorHideMode::OnTypingAndAction
6527 && self.last_input_was_keyboard()
6528 {
6529 cx.platform.hide_cursor_until_mouse_moves();
6530 }
6531 }
6532
6533 fn dispatch_action_on_node_inner(
6534 &mut self,
6535 node_id: DispatchNodeId,
6536 action: &dyn Action,
6537 cx: &mut App,
6538 ) {
6539 let dispatch_path = self.rendered_frame.dispatch_tree.dispatch_path(node_id);
6540
6541 cx.propagate_event = true;
6543 if let Some(mut global_listeners) = cx
6544 .global_action_listeners
6545 .remove(&action.as_any().type_id())
6546 {
6547 for listener in &global_listeners {
6548 #[cfg(feature = "profiler")]
6549 self.window_profiler.begin_action_handler(action, cx);
6550 listener(action.as_any(), DispatchPhase::Capture, cx);
6551 #[cfg(feature = "profiler")]
6552 self.window_profiler.end_action_handler();
6553 if !cx.propagate_event {
6554 break;
6555 }
6556 }
6557
6558 global_listeners.extend(
6559 cx.global_action_listeners
6560 .remove(&action.as_any().type_id())
6561 .unwrap_or_default(),
6562 );
6563
6564 cx.global_action_listeners
6565 .insert(action.as_any().type_id(), global_listeners);
6566 }
6567
6568 if !cx.propagate_event {
6569 return;
6570 }
6571
6572 for node_id in &dispatch_path {
6574 let node = self.rendered_frame.dispatch_tree.node(*node_id);
6575 for DispatchActionListener {
6576 action_type,
6577 listener,
6578 } in node.action_listeners.clone()
6579 {
6580 let any_action = action.as_any();
6581 if action_type == any_action.type_id() {
6582 #[cfg(feature = "profiler")]
6583 self.window_profiler.begin_action_handler(action, cx);
6584 listener(any_action, DispatchPhase::Capture, self, cx);
6585 #[cfg(feature = "profiler")]
6586 self.window_profiler.end_action_handler();
6587
6588 if !cx.propagate_event {
6589 return;
6590 }
6591 }
6592 }
6593 }
6594
6595 for node_id in dispatch_path.iter().rev() {
6597 let node = self.rendered_frame.dispatch_tree.node(*node_id);
6598 for DispatchActionListener {
6599 action_type,
6600 listener,
6601 } in node.action_listeners.clone()
6602 {
6603 let any_action = action.as_any();
6604 if action_type == any_action.type_id() {
6605 cx.propagate_event = false; #[cfg(feature = "profiler")]
6607 self.window_profiler.begin_action_handler(action, cx);
6608 listener(any_action, DispatchPhase::Bubble, self, cx);
6609 #[cfg(feature = "profiler")]
6610 self.window_profiler.end_action_handler();
6611
6612 if !cx.propagate_event {
6613 return;
6614 }
6615 }
6616 }
6617 }
6618
6619 if let Some(mut global_listeners) = cx
6621 .global_action_listeners
6622 .remove(&action.as_any().type_id())
6623 {
6624 for listener in global_listeners.iter().rev() {
6625 cx.propagate_event = false; #[cfg(feature = "profiler")]
6628 self.window_profiler.begin_action_handler(action, cx);
6629 listener(action.as_any(), DispatchPhase::Bubble, cx);
6630 #[cfg(feature = "profiler")]
6631 self.window_profiler.end_action_handler();
6632 if !cx.propagate_event {
6633 break;
6634 }
6635 }
6636
6637 global_listeners.extend(
6638 cx.global_action_listeners
6639 .remove(&action.as_any().type_id())
6640 .unwrap_or_default(),
6641 );
6642
6643 cx.global_action_listeners
6644 .insert(action.as_any().type_id(), global_listeners);
6645 }
6646 }
6647
6648 pub fn observe_global<G: Global>(
6651 &mut self,
6652 cx: &mut App,
6653 f: impl Fn(&mut Window, &mut App) + 'static,
6654 ) -> Subscription {
6655 let window_handle = self.handle;
6656 let (subscription, activate) = cx.global_observers.insert(
6657 TypeId::of::<G>(),
6658 Box::new(move |cx| {
6659 window_handle
6660 .update(cx, |_, window, cx| f(window, cx))
6661 .is_ok()
6662 }),
6663 );
6664 cx.defer(move |_| activate());
6665 subscription
6666 }
6667
6668 pub fn activate_window(&self) {
6670 self.platform_window.activate();
6671 }
6672
6673 pub fn request_attention(&self) {
6675 self.platform_window.request_attention();
6676 }
6677
6678 pub fn minimize_window(&self) {
6680 self.platform_window.minimize();
6681 }
6682
6683 pub fn toggle_fullscreen(&self) {
6685 self.platform_window.toggle_fullscreen();
6686 }
6687
6688 pub fn toggle_simple_fullscreen(&self) {
6693 self.platform_window.toggle_simple_fullscreen();
6694 }
6695
6696 pub fn invalidate_character_coordinates(&self) {
6698 self.on_next_frame(|window, cx| {
6699 if let Some(mut input_handler) = window.platform_window.take_input_handler() {
6700 if let Some(bounds) = input_handler.selected_bounds(window, cx) {
6701 window.platform_window.update_ime_position(bounds);
6702 }
6703 window.platform_window.set_input_handler(input_handler);
6704 }
6705 });
6706 }
6707
6708 pub fn prompt<T>(
6712 &mut self,
6713 level: PromptLevel,
6714 message: &str,
6715 detail: Option<&str>,
6716 answers: &[T],
6717 cx: &mut App,
6718 ) -> oneshot::Receiver<usize>
6719 where
6720 T: Clone + Into<PromptButton>,
6721 {
6722 let prompt_builder = cx.prompt_builder.take();
6723 let Some(prompt_builder) = prompt_builder else {
6724 unreachable!("Re-entrant window prompting is not supported by GPUI");
6725 };
6726
6727 let answers = answers
6728 .iter()
6729 .map(|answer| answer.clone().into())
6730 .collect::<Vec<_>>();
6731
6732 let receiver = match &prompt_builder {
6733 PromptBuilder::Default => self
6734 .platform_window
6735 .prompt(level, message, detail, &answers)
6736 .unwrap_or_else(|| {
6737 self.build_custom_prompt(&prompt_builder, level, message, detail, &answers, cx)
6738 }),
6739 PromptBuilder::Custom(_) => {
6740 self.build_custom_prompt(&prompt_builder, level, message, detail, &answers, cx)
6741 }
6742 };
6743
6744 cx.prompt_builder = Some(prompt_builder);
6745
6746 receiver
6747 }
6748
6749 fn build_custom_prompt(
6750 &mut self,
6751 prompt_builder: &PromptBuilder,
6752 level: PromptLevel,
6753 message: &str,
6754 detail: Option<&str>,
6755 answers: &[PromptButton],
6756 cx: &mut App,
6757 ) -> oneshot::Receiver<usize> {
6758 let (sender, receiver) = oneshot::channel();
6759 let handle = PromptHandle::new(sender);
6760 let handle = (prompt_builder)(level, message, detail, answers, handle, self, cx);
6761 self.prompt = Some(handle);
6762 receiver
6763 }
6764
6765 pub fn has_active_prompt(&self) -> bool {
6770 self.prompt.is_some()
6771 }
6772
6773 pub fn context_stack(&self) -> Vec<KeyContext> {
6775 let node_id = self.focus_node_id_in_rendered_frame(self.focus);
6776 let dispatch_tree = &self.rendered_frame.dispatch_tree;
6777 dispatch_tree
6778 .dispatch_path(node_id)
6779 .iter()
6780 .filter_map(move |&node_id| dispatch_tree.node(node_id).context.clone())
6781 .collect()
6782 }
6783
6784 pub fn available_actions(&self, cx: &App) -> Vec<Box<dyn Action>> {
6786 let node_id = self.focus_node_id_in_rendered_frame(self.focus);
6787 let mut actions = self.rendered_frame.dispatch_tree.available_actions(node_id);
6788 for action_type in cx.global_action_listeners.keys() {
6789 if let Err(ix) = actions.binary_search_by_key(action_type, |a| a.as_any().type_id()) {
6790 let action = cx.actions.build_action_type(action_type).ok();
6791 if let Some(action) = action {
6792 actions.insert(ix, action);
6793 }
6794 }
6795 }
6796 actions
6797 }
6798
6799 pub fn bindings_for_action(&self, action: &dyn Action) -> Vec<KeyBinding> {
6802 self.rendered_frame
6803 .dispatch_tree
6804 .bindings_for_action(action, &self.rendered_frame.dispatch_tree.context_stack)
6805 }
6806
6807 pub fn highest_precedence_binding_for_action(&self, action: &dyn Action) -> Option<KeyBinding> {
6810 self.rendered_frame
6811 .dispatch_tree
6812 .highest_precedence_binding_for_action(
6813 action,
6814 &self.rendered_frame.dispatch_tree.context_stack,
6815 )
6816 }
6817
6818 pub fn bindings_for_action_in_context(
6820 &self,
6821 action: &dyn Action,
6822 context: KeyContext,
6823 ) -> Vec<KeyBinding> {
6824 let dispatch_tree = &self.rendered_frame.dispatch_tree;
6825 dispatch_tree.bindings_for_action(action, &[context])
6826 }
6827
6828 pub fn highest_precedence_binding_for_action_in_context(
6831 &self,
6832 action: &dyn Action,
6833 context: KeyContext,
6834 ) -> Option<KeyBinding> {
6835 let dispatch_tree = &self.rendered_frame.dispatch_tree;
6836 dispatch_tree.highest_precedence_binding_for_action(action, &[context])
6837 }
6838
6839 pub fn bindings_for_action_in(
6843 &self,
6844 action: &dyn Action,
6845 focus_handle: &FocusHandle,
6846 ) -> Vec<KeyBinding> {
6847 let dispatch_tree = &self.rendered_frame.dispatch_tree;
6848 let Some(context_stack) = self.context_stack_for_focus_handle(focus_handle) else {
6849 return vec![];
6850 };
6851 dispatch_tree.bindings_for_action(action, &context_stack)
6852 }
6853
6854 pub fn highest_precedence_binding_for_action_in(
6858 &self,
6859 action: &dyn Action,
6860 focus_handle: &FocusHandle,
6861 ) -> Option<KeyBinding> {
6862 let dispatch_tree = &self.rendered_frame.dispatch_tree;
6863 let context_stack = self.context_stack_for_focus_handle(focus_handle)?;
6864 dispatch_tree.highest_precedence_binding_for_action(action, &context_stack)
6865 }
6866
6867 pub fn possible_bindings_for_input(&self, input: &[Keystroke]) -> Vec<KeyBinding> {
6869 self.rendered_frame
6870 .dispatch_tree
6871 .possible_next_bindings_for_input(input, &self.context_stack())
6872 }
6873
6874 fn context_stack_for_focus_handle(
6875 &self,
6876 focus_handle: &FocusHandle,
6877 ) -> Option<Vec<KeyContext>> {
6878 let dispatch_tree = &self.rendered_frame.dispatch_tree;
6879 let node_id = dispatch_tree.focusable_node_id(focus_handle.id)?;
6880 let context_stack: Vec<_> = dispatch_tree
6881 .dispatch_path(node_id)
6882 .into_iter()
6883 .filter_map(|node_id| dispatch_tree.node(node_id).context.clone())
6884 .collect();
6885 Some(context_stack)
6886 }
6887
6888 pub fn listener_for<T: 'static, E>(
6890 &self,
6891 view: &Entity<T>,
6892 f: impl Fn(&mut T, &E, &mut Window, &mut Context<T>) + 'static,
6893 ) -> impl Fn(&E, &mut Window, &mut App) + 'static {
6894 let view = view.downgrade();
6895 move |e: &E, window: &mut Window, cx: &mut App| {
6896 view.update(cx, |view, cx| f(view, e, window, cx)).ok();
6897 }
6898 }
6899
6900 pub fn handler_for<E: 'static, Callback: Fn(&mut E, &mut Window, &mut Context<E>) + 'static>(
6902 &self,
6903 entity: &Entity<E>,
6904 f: Callback,
6905 ) -> impl Fn(&mut Window, &mut App) + 'static {
6906 let entity = entity.downgrade();
6907 move |window: &mut Window, cx: &mut App| {
6908 entity.update(cx, |entity, cx| f(entity, window, cx)).ok();
6909 }
6910 }
6911
6912 pub fn on_window_should_close(
6915 &self,
6916 cx: &App,
6917 f: impl Fn(&mut Window, &mut App) -> bool + 'static,
6918 ) {
6919 let mut cx = self.to_async(cx);
6920 self.platform_window.on_should_close(Box::new(move || {
6921 cx.update(|window, cx| f(window, cx)).unwrap_or(true)
6922 }))
6923 }
6924
6925 pub fn on_action(
6934 &mut self,
6935 action_type: TypeId,
6936 listener: impl Fn(&dyn Any, DispatchPhase, &mut Window, &mut App) + 'static,
6937 ) {
6938 self.invalidator.debug_assert_paint();
6939
6940 self.next_frame
6941 .dispatch_tree
6942 .on_action(action_type, Rc::new(listener));
6943 }
6944
6945 pub fn on_action_when(
6954 &mut self,
6955 condition: bool,
6956 action_type: TypeId,
6957 listener: impl Fn(&dyn Any, DispatchPhase, &mut Window, &mut App) + 'static,
6958 ) {
6959 self.invalidator.debug_assert_paint();
6960
6961 if condition {
6962 self.next_frame
6963 .dispatch_tree
6964 .on_action(action_type, Rc::new(listener));
6965 }
6966 }
6967
6968 pub fn gpu_specs(&self) -> Option<GpuSpecs> {
6971 self.platform_window.gpu_specs()
6972 }
6973
6974 pub fn titlebar_double_click(&self) {
6977 self.platform_window
6978 .titlebar_double_click(self.is_resizable, self.is_minimizable);
6979 }
6980
6981 pub fn window_title(&self) -> String {
6984 self.platform_window.get_title()
6985 }
6986
6987 pub fn tabbed_windows(&self) -> Option<Vec<SystemWindowTab>> {
6990 self.platform_window.tabbed_windows()
6991 }
6992
6993 pub fn tab_bar_visible(&self) -> bool {
6996 self.platform_window.tab_bar_visible()
6997 }
6998
6999 pub fn merge_all_windows(&self) {
7002 self.platform_window.merge_all_windows()
7003 }
7004
7005 pub fn move_tab_to_new_window(&self) {
7008 self.platform_window.move_tab_to_new_window()
7009 }
7010
7011 pub fn toggle_window_tab_overview(&self) {
7014 self.platform_window.toggle_window_tab_overview()
7015 }
7016
7017 pub fn set_tabbing_identifier(&self, tabbing_identifier: Option<String>) {
7020 self.platform_window
7021 .set_tabbing_identifier(tabbing_identifier)
7022 }
7023
7024 pub fn play_system_bell(&self) {
7027 self.platform_window.play_system_bell()
7028 }
7029
7030 pub fn is_a11y_enabled(&self) -> bool {
7037 self.a11y.is_enabled()
7038 }
7039
7040 pub fn is_a11y_active(&self) -> bool {
7051 self.a11y.is_active()
7052 }
7053
7054 pub fn debug_a11y_tree_json(&self) -> Option<String> {
7056 self.a11y.debug_tree_json()
7057 }
7058
7059 pub fn on_a11y_action(
7065 &mut self,
7066 node_id: accesskit::NodeId,
7067 action: accesskit::Action,
7068 listener: impl FnMut(Option<&accesskit::ActionData>, &mut Window, &mut App) + 'static,
7069 ) {
7070 self.a11y
7071 .action_listeners
7072 .entry(node_id)
7073 .or_default()
7074 .push((action, Box::new(listener)));
7075 }
7076
7077 #[cfg(not(target_family = "wasm"))]
7078 pub(crate) fn handle_a11y_action(&mut self, request: accesskit::ActionRequest, cx: &mut App) {
7079 if let Some(mut listeners) = self.a11y.action_listeners.remove(&request.target_node) {
7082 let extra_data = request.data.as_ref();
7083 let mut matched = false;
7084 for (action, listener) in &mut listeners {
7085 if *action == request.action {
7086 listener(extra_data, self, cx);
7087 matched = true;
7088 }
7089 }
7090 self.a11y
7091 .action_listeners
7092 .insert(request.target_node, listeners);
7093 if matched {
7094 return;
7095 }
7096 }
7097
7098 match request.action {
7100 accesskit::Action::Click => {
7101 if let Some(bounds) = self.a11y.node_bounds.get(&request.target_node).copied() {
7102 let center = bounds.center();
7103 let mouse_down = PlatformInput::MouseDown(crate::MouseDownEvent {
7104 button: MouseButton::Left,
7105 position: center,
7106 modifiers: Modifiers::default(),
7107 click_count: 1,
7108 first_mouse: false,
7109 });
7110 let mouse_up = PlatformInput::MouseUp(MouseUpEvent {
7111 button: MouseButton::Left,
7112 position: center,
7113 modifiers: Modifiers::default(),
7114 click_count: 1,
7115 });
7116 self.dispatch_event(mouse_down, cx);
7117 self.dispatch_event(mouse_up, cx);
7118 }
7119 }
7120 accesskit::Action::Focus => {
7121 if let Some(focus_id) = self.a11y.focus_ids.get(&request.target_node).copied()
7122 && let Some(handle) = FocusHandle::for_id(focus_id, &cx.focus_handles)
7123 {
7124 self.focus(&handle, cx);
7125 }
7126 }
7127 accesskit::Action::Blur => {
7128 self.blur(cx);
7129 }
7130 _ => {
7131 log::debug!(
7132 "Unhandled a11y action: {:?} on {:?}",
7133 request.action,
7134 request.target_node
7135 );
7136 }
7137 }
7138 }
7139
7140 #[cfg(any(feature = "inspector", debug_assertions))]
7142 pub fn toggle_inspector(&mut self, cx: &mut App) {
7143 self.inspector = match self.inspector {
7144 None => Some(cx.new(|_| Inspector::new())),
7145 Some(_) => {
7146 self.rendered_frame.next_inspector_instance_ids = FxHashMap::default();
7147 self.rendered_frame.inspector_hitboxes = FxHashMap::default();
7148 self.next_frame.next_inspector_instance_ids = FxHashMap::default();
7149 self.next_frame.inspector_hitboxes = FxHashMap::default();
7150 None
7151 }
7152 };
7153 self.refresh();
7154 }
7155
7156 pub fn is_inspector_picking(&self, _cx: &App) -> bool {
7158 #[cfg(any(feature = "inspector", debug_assertions))]
7159 {
7160 if let Some(inspector) = &self.inspector {
7161 return inspector.read(_cx).is_picking();
7162 }
7163 }
7164 false
7165 }
7166
7167 #[cfg(any(feature = "inspector", debug_assertions))]
7169 pub fn with_inspector_state<T: 'static, R>(
7170 &mut self,
7171 inspector_id: Option<&crate::InspectorElementId>,
7172 cx: &mut App,
7173 f: impl FnOnce(&mut Option<T>, &mut Self) -> R,
7174 ) -> Option<R> {
7175 let inspector_id = inspector_id?;
7176 let inspector = self.inspector.as_ref()?;
7177 if inspector.read(cx).active_element_id() != Some(inspector_id) {
7178 return None;
7179 }
7180 let inspector = inspector.clone();
7181 Some(inspector.update(cx, |inspector, _cx| {
7182 inspector.with_active_element_state(self, f)
7183 }))
7184 }
7185
7186 #[cfg(any(feature = "inspector", debug_assertions))]
7187 pub(crate) fn inspector_enabled(&self) -> bool {
7188 self.inspector.is_some()
7189 }
7190
7191 #[cfg(any(feature = "inspector", debug_assertions))]
7192 pub(crate) fn build_inspector_element_id(
7193 &mut self,
7194 path: crate::InspectorElementPath,
7195 ) -> crate::InspectorElementId {
7196 self.invalidator.debug_assert_paint_or_prepaint();
7197 let path = Rc::new(path);
7198 let next_instance_id = self
7199 .next_frame
7200 .next_inspector_instance_ids
7201 .entry(path.clone())
7202 .or_insert(0);
7203 let instance_id = *next_instance_id;
7204 *next_instance_id += 1;
7205 crate::InspectorElementId { path, instance_id }
7206 }
7207
7208 #[cfg(any(feature = "inspector", debug_assertions))]
7209 fn prepaint_inspector(&mut self, inspector_width: Pixels, cx: &mut App) -> Option<AnyElement> {
7210 if let Some(inspector) = self.inspector.take() {
7211 let mut inspector_element = AnyView::from(inspector.clone()).into_any_element();
7212 inspector_element.prepaint_as_root(
7213 point(self.viewport_size.width - inspector_width, px(0.0)),
7214 size(inspector_width, self.viewport_size.height).into(),
7215 self,
7216 cx,
7217 );
7218 self.inspector = Some(inspector);
7219 Some(inspector_element)
7220 } else {
7221 None
7222 }
7223 }
7224
7225 #[cfg(any(feature = "inspector", debug_assertions))]
7226 fn paint_inspector(&mut self, mut inspector_element: Option<AnyElement>, cx: &mut App) {
7227 if let Some(mut inspector_element) = inspector_element {
7228 inspector_element.paint(self, cx);
7229 };
7230 }
7231
7232 #[cfg(any(feature = "inspector", debug_assertions))]
7235 pub fn insert_inspector_hitbox(
7236 &mut self,
7237 hitbox_id: HitboxId,
7238 inspector_id: Option<&crate::InspectorElementId>,
7239 cx: &App,
7240 ) {
7241 self.invalidator.debug_assert_paint_or_prepaint();
7242 if !self.is_inspector_picking(cx) {
7243 return;
7244 }
7245 if let Some(inspector_id) = inspector_id {
7246 self.next_frame
7247 .inspector_hitboxes
7248 .insert(hitbox_id, inspector_id.clone());
7249 }
7250 }
7251
7252 #[cfg(any(feature = "inspector", debug_assertions))]
7253 fn paint_inspector_hitbox(&mut self, cx: &App) {
7254 if let Some(inspector) = self.inspector.as_ref() {
7255 let inspector = inspector.read(cx);
7256 if let Some((hitbox_id, _)) = self.hovered_inspector_hitbox(inspector, &self.next_frame)
7257 && let Some(hitbox) = self
7258 .next_frame
7259 .hitboxes
7260 .iter()
7261 .find(|hitbox| hitbox.id == hitbox_id)
7262 {
7263 self.paint_quad(crate::fill(hitbox.bounds, crate::rgba(0x61afef4d)));
7264 }
7265 }
7266 }
7267
7268 #[cfg(any(feature = "inspector", debug_assertions))]
7269 fn handle_inspector_mouse_event(&mut self, event: &dyn Any, cx: &mut App) {
7270 let Some(inspector) = self.inspector.clone() else {
7271 return;
7272 };
7273 if event.downcast_ref::<MouseMoveEvent>().is_some() {
7274 inspector.update(cx, |inspector, _cx| {
7275 if let Some((_, inspector_id)) =
7276 self.hovered_inspector_hitbox(inspector, &self.rendered_frame)
7277 {
7278 inspector.hover(inspector_id, self);
7279 }
7280 });
7281 } else if event.downcast_ref::<crate::MouseDownEvent>().is_some() {
7282 inspector.update(cx, |inspector, _cx| {
7283 if let Some((_, inspector_id)) =
7284 self.hovered_inspector_hitbox(inspector, &self.rendered_frame)
7285 {
7286 inspector.select(inspector_id, self);
7287 }
7288 });
7289 } else if let Some(event) = event.downcast_ref::<crate::ScrollEvent>() {
7290 const SCROLL_LINES: f32 = 3.0;
7292 const SCROLL_PIXELS_PER_LAYER: f32 = 36.0;
7293 let delta_y = event
7294 .delta
7295 .pixel_delta(px(SCROLL_PIXELS_PER_LAYER / SCROLL_LINES))
7296 .y;
7297 if let Some(inspector) = self.inspector.clone() {
7298 inspector.update(cx, |inspector, _cx| {
7299 if let Some(depth) = inspector.pick_depth.as_mut() {
7300 *depth += f32::from(delta_y) / SCROLL_PIXELS_PER_LAYER;
7301 let max_depth = self.mouse_hit_test.ids.len() as f32 - 0.5;
7302 if *depth < 0.0 {
7303 *depth = 0.0;
7304 } else if *depth > max_depth {
7305 *depth = max_depth;
7306 }
7307 if let Some((_, inspector_id)) =
7308 self.hovered_inspector_hitbox(inspector, &self.rendered_frame)
7309 {
7310 inspector.set_active_element_id(inspector_id, self);
7311 }
7312 }
7313 });
7314 }
7315 }
7316 }
7317
7318 #[cfg(any(feature = "inspector", debug_assertions))]
7319 fn hovered_inspector_hitbox(
7320 &self,
7321 inspector: &Inspector,
7322 frame: &Frame,
7323 ) -> Option<(HitboxId, crate::InspectorElementId)> {
7324 if let Some(pick_depth) = inspector.pick_depth {
7325 let depth = (pick_depth as i64).try_into().unwrap_or(0);
7326 let max_skipped = self.mouse_hit_test.ids.len().saturating_sub(1);
7327 let skip_count = (depth as usize).min(max_skipped);
7328 for hitbox_id in self.mouse_hit_test.ids.iter().skip(skip_count) {
7329 if let Some(inspector_id) = frame.inspector_hitboxes.get(hitbox_id) {
7330 return Some((*hitbox_id, inspector_id.clone()));
7331 }
7332 }
7333 }
7334 None
7335 }
7336
7337 #[cfg(any(test, feature = "test-support"))]
7340 pub fn set_modifiers(&mut self, modifiers: Modifiers) {
7341 self.modifiers = modifiers;
7342 }
7343
7344 #[cfg(any(test, feature = "test-support"))]
7348 pub fn simulate_mouse_move(&mut self, position: Point<Pixels>, cx: &mut App) {
7349 let event = PlatformInput::MouseMove(MouseMoveEvent {
7350 position,
7351 modifiers: self.modifiers,
7352 pressed_button: None,
7353 });
7354 let _ = self.dispatch_event(event, cx);
7355 }
7356
7357 #[inline(never)]
7358 fn take_element_state(
7359 &mut self,
7360 global_id: &GlobalElementId,
7361 state_type: TypeId,
7362 ) -> ((GlobalElementId, TypeId), Option<ElementStateBox>) {
7363 let key = (global_id.clone(), state_type);
7364 self.next_frame.accessed_element_states.push(key.clone());
7365 let state = self
7366 .next_frame
7367 .element_states
7368 .remove(&key)
7369 .or_else(|| self.rendered_frame.element_states.remove(&key));
7370 (key, state)
7371 }
7372
7373 #[inline(never)]
7374 fn insert_element_state(
7375 &mut self,
7376 key: (GlobalElementId, TypeId),
7377 state: ElementStateBox,
7378 ) -> Option<ElementStateBox> {
7379 self.next_frame.element_states.insert(key, state)
7380 }
7381
7382 #[inline(never)]
7383 fn observe_keyed_state<S: 'static>(state: &Entity<S>, current_view: EntityId, cx: &mut App) {
7384 cx.observe(state, move |_, cx| {
7385 cx.notify(current_view);
7386 })
7387 .detach();
7388 }
7389}
7390
7391slotmap::new_key_type! {
7393 pub struct WindowId;
7395}
7396
7397impl WindowId {
7398 pub fn as_u64(&self) -> u64 {
7400 self.0.as_ffi()
7401 }
7402}
7403
7404impl From<u64> for WindowId {
7405 fn from(value: u64) -> Self {
7406 WindowId(slotmap::KeyData::from_ffi(value))
7407 }
7408}
7409
7410#[derive(Deref, DerefMut)]
7413pub struct WindowHandle<V> {
7414 #[deref]
7415 #[deref_mut]
7416 pub(crate) any_handle: AnyWindowHandle,
7417 state_type: PhantomData<fn(V) -> V>,
7418}
7419
7420impl<V> Debug for WindowHandle<V> {
7421 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
7422 f.debug_struct("WindowHandle")
7423 .field("any_handle", &self.any_handle.id.as_u64())
7424 .finish()
7425 }
7426}
7427
7428impl<V: 'static + Render> WindowHandle<V> {
7429 pub fn new(id: WindowId) -> Self {
7432 WindowHandle {
7433 any_handle: AnyWindowHandle {
7434 id,
7435 state_type: TypeId::of::<V>(),
7436 root_entity_type_name: std::any::type_name::<V>(),
7437 },
7438 state_type: PhantomData,
7439 }
7440 }
7441
7442 #[cfg(any(test, feature = "test-support"))]
7446 pub fn root<C>(&self, cx: &mut C) -> Result<Entity<V>>
7447 where
7448 C: AppContext,
7449 {
7450 cx.update_window(self.any_handle, |root_view, _, _| {
7451 root_view
7452 .downcast::<V>()
7453 .map_err(|_| anyhow!("the type of the window's root view has changed"))
7454 })?
7455 }
7456
7457 pub fn update<C, R>(
7461 &self,
7462 cx: &mut C,
7463 update: impl FnOnce(&mut V, &mut Window, &mut Context<V>) -> R,
7464 ) -> Result<R>
7465 where
7466 C: AppContext,
7467 {
7468 cx.update_window(self.any_handle, |root_view, window, cx| {
7469 let view = root_view
7470 .downcast::<V>()
7471 .map_err(|_| anyhow!("the type of the window's root view has changed"))?;
7472
7473 Ok(view.update(cx, |view, cx| update(view, window, cx)))
7474 })?
7475 }
7476
7477 pub fn read<'a>(&self, cx: &'a App) -> Result<&'a V> {
7481 let x = cx
7482 .windows
7483 .get(self.id)
7484 .and_then(|window| {
7485 window
7486 .as_deref()
7487 .and_then(|window| window.root.clone())
7488 .map(|root_view| root_view.downcast::<V>())
7489 })
7490 .context("window not found")?
7491 .map_err(|_| anyhow!("the type of the window's root view has changed"))?;
7492
7493 Ok(x.read(cx))
7494 }
7495
7496 pub fn read_with<C, R>(&self, cx: &C, read_with: impl FnOnce(&V, &App) -> R) -> Result<R>
7500 where
7501 C: AppContext,
7502 {
7503 cx.read_window(self, |root_view, cx| read_with(root_view.read(cx), cx))
7504 }
7505
7506 pub fn entity<C>(&self, cx: &C) -> Result<Entity<V>>
7510 where
7511 C: AppContext,
7512 {
7513 cx.read_window(self, |root_view, _cx| root_view)
7514 }
7515
7516 pub fn is_active(&self, cx: &mut App) -> Option<bool> {
7521 cx.update_window(self.any_handle, |_, window, _| window.is_window_active())
7522 .ok()
7523 }
7524}
7525
7526impl<V> Copy for WindowHandle<V> {}
7527
7528impl<V> Clone for WindowHandle<V> {
7529 fn clone(&self) -> Self {
7530 *self
7531 }
7532}
7533
7534impl<V> PartialEq for WindowHandle<V> {
7535 fn eq(&self, other: &Self) -> bool {
7536 self.any_handle == other.any_handle
7537 }
7538}
7539
7540impl<V> Eq for WindowHandle<V> {}
7541
7542impl<V> Hash for WindowHandle<V> {
7543 fn hash<H: Hasher>(&self, state: &mut H) {
7544 self.any_handle.hash(state);
7545 }
7546}
7547
7548impl<V: 'static> From<WindowHandle<V>> for AnyWindowHandle {
7549 fn from(val: WindowHandle<V>) -> Self {
7550 val.any_handle
7551 }
7552}
7553
7554#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
7556pub struct AnyWindowHandle {
7557 pub(crate) id: WindowId,
7558 state_type: TypeId,
7559 root_entity_type_name: &'static str,
7560}
7561
7562impl AnyWindowHandle {
7563 pub fn window_id(&self) -> WindowId {
7565 self.id
7566 }
7567
7568 pub fn root_entity_type_name(&self) -> &'static str {
7570 self.root_entity_type_name
7571 }
7572
7573 pub fn downcast<T: 'static>(&self) -> Option<WindowHandle<T>> {
7576 if TypeId::of::<T>() == self.state_type {
7577 Some(WindowHandle {
7578 any_handle: *self,
7579 state_type: PhantomData,
7580 })
7581 } else {
7582 None
7583 }
7584 }
7585
7586 pub fn update<C, R>(
7590 self,
7591 cx: &mut C,
7592 update: impl FnOnce(AnyView, &mut Window, &mut App) -> R,
7593 ) -> Result<R>
7594 where
7595 C: AppContext,
7596 {
7597 cx.update_window(self, update)
7598 }
7599
7600 pub fn read<T, C, R>(self, cx: &C, read: impl FnOnce(Entity<T>, &App) -> R) -> Result<R>
7604 where
7605 C: AppContext,
7606 T: 'static,
7607 {
7608 let view = self
7609 .downcast::<T>()
7610 .context("the type of the window's root view has changed")?;
7611
7612 cx.read_window(&view, read)
7613 }
7614}
7615
7616impl HasWindowHandle for Window {
7617 fn window_handle(&self) -> Result<raw_window_handle::WindowHandle<'_>, HandleError> {
7618 self.platform_window.window_handle()
7619 }
7620}
7621
7622impl HasDisplayHandle for Window {
7623 fn display_handle(
7624 &self,
7625 ) -> std::result::Result<raw_window_handle::DisplayHandle<'_>, HandleError> {
7626 self.platform_window.display_handle()
7627 }
7628}
7629
7630#[derive(Clone, Debug, Eq, PartialEq, Hash)]
7635pub enum ElementId {
7636 View(EntityId),
7638 Integer(u64),
7640 Name(SharedString),
7642 Uuid(Uuid),
7644 FocusHandle(FocusId),
7646 NamedInteger(SharedString, u64),
7648 Path(Arc<std::path::Path>),
7650 CodeLocation(core::panic::Location<'static>),
7652 NamedChild(Arc<ElementId>, SharedString),
7654 OpaqueId([u8; 20]),
7656}
7657
7658impl ElementId {
7659 pub fn named_usize(name: impl Into<SharedString>, integer: usize) -> ElementId {
7661 Self::NamedInteger(name.into(), integer as u64)
7662 }
7663}
7664
7665impl Display for ElementId {
7666 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
7667 match self {
7668 ElementId::View(entity_id) => write!(f, "view-{}", entity_id)?,
7669 ElementId::Integer(ix) => write!(f, "{}", ix)?,
7670 ElementId::Name(name) => write!(f, "{}", name)?,
7671 ElementId::FocusHandle(_) => write!(f, "FocusHandle")?,
7672 ElementId::NamedInteger(s, i) => write!(f, "{}-{}", s, i)?,
7673 ElementId::Uuid(uuid) => write!(f, "{}", uuid)?,
7674 ElementId::Path(path) => write!(f, "{}", path.display())?,
7675 ElementId::CodeLocation(location) => write!(f, "{}", location)?,
7676 ElementId::NamedChild(id, name) => write!(f, "{}-{}", id, name)?,
7677 ElementId::OpaqueId(opaque_id) => write!(f, "{:x?}", opaque_id)?,
7678 }
7679
7680 Ok(())
7681 }
7682}
7683
7684impl TryInto<SharedString> for ElementId {
7685 type Error = anyhow::Error;
7686
7687 fn try_into(self) -> anyhow::Result<SharedString> {
7688 if let ElementId::Name(name) = self {
7689 Ok(name)
7690 } else {
7691 anyhow::bail!("element id is not string")
7692 }
7693 }
7694}
7695
7696impl From<u64> for ElementId {
7697 fn from(id: u64) -> Self {
7698 ElementId::Integer(id)
7699 }
7700}
7701
7702impl From<usize> for ElementId {
7703 fn from(id: usize) -> Self {
7704 ElementId::Integer(id as u64)
7705 }
7706}
7707
7708impl From<i32> for ElementId {
7709 fn from(id: i32) -> Self {
7710 Self::Integer(id as u64)
7711 }
7712}
7713
7714impl From<SharedString> for ElementId {
7715 fn from(name: SharedString) -> Self {
7716 ElementId::Name(name)
7717 }
7718}
7719
7720impl From<String> for ElementId {
7721 fn from(name: String) -> Self {
7722 ElementId::Name(name.into())
7723 }
7724}
7725
7726impl From<Arc<str>> for ElementId {
7727 fn from(name: Arc<str>) -> Self {
7728 ElementId::Name(name.into())
7729 }
7730}
7731
7732impl From<Arc<std::path::Path>> for ElementId {
7733 fn from(path: Arc<std::path::Path>) -> Self {
7734 ElementId::Path(path)
7735 }
7736}
7737
7738impl From<&'static str> for ElementId {
7739 fn from(name: &'static str) -> Self {
7740 ElementId::Name(SharedString::new_static(name))
7741 }
7742}
7743
7744impl<'a> From<&'a FocusHandle> for ElementId {
7745 fn from(handle: &'a FocusHandle) -> Self {
7746 ElementId::FocusHandle(handle.id)
7747 }
7748}
7749
7750impl From<(&'static str, EntityId)> for ElementId {
7751 fn from((name, id): (&'static str, EntityId)) -> Self {
7752 ElementId::NamedInteger(SharedString::new_static(name), id.as_u64())
7753 }
7754}
7755
7756impl From<(&'static str, usize)> for ElementId {
7757 fn from((name, id): (&'static str, usize)) -> Self {
7758 ElementId::NamedInteger(SharedString::new_static(name), id as u64)
7759 }
7760}
7761
7762impl From<(SharedString, usize)> for ElementId {
7763 fn from((name, id): (SharedString, usize)) -> Self {
7764 ElementId::NamedInteger(name, id as u64)
7765 }
7766}
7767
7768impl From<(&'static str, u64)> for ElementId {
7769 fn from((name, id): (&'static str, u64)) -> Self {
7770 ElementId::NamedInteger(SharedString::new_static(name), id)
7771 }
7772}
7773
7774impl From<Uuid> for ElementId {
7775 fn from(value: Uuid) -> Self {
7776 Self::Uuid(value)
7777 }
7778}
7779
7780impl From<(&'static str, u32)> for ElementId {
7781 fn from((name, id): (&'static str, u32)) -> Self {
7782 ElementId::NamedInteger(SharedString::new_static(name), u64::from(id))
7783 }
7784}
7785
7786impl<T: Into<SharedString>> From<(ElementId, T)> for ElementId {
7787 fn from((id, name): (ElementId, T)) -> Self {
7788 ElementId::NamedChild(Arc::new(id), name.into())
7789 }
7790}
7791
7792impl From<&'static core::panic::Location<'static>> for ElementId {
7793 fn from(location: &'static core::panic::Location<'static>) -> Self {
7794 ElementId::CodeLocation(*location)
7795 }
7796}
7797
7798impl From<[u8; 20]> for ElementId {
7799 fn from(opaque_id: [u8; 20]) -> Self {
7800 ElementId::OpaqueId(opaque_id)
7801 }
7802}
7803
7804#[derive(Clone)]
7807pub struct PaintQuad {
7808 pub bounds: Bounds<Pixels>,
7810 pub corner_radii: Corners<Pixels>,
7812 pub background: Background,
7814 pub border_widths: Edges<Pixels>,
7816 pub border_color: Hsla,
7818 pub border_style: BorderStyle,
7820}
7821
7822impl PaintQuad {
7823 pub fn corner_radii(self, corner_radii: impl Into<Corners<Pixels>>) -> Self {
7825 PaintQuad {
7826 corner_radii: corner_radii.into(),
7827 ..self
7828 }
7829 }
7830
7831 pub fn border_widths(self, border_widths: impl Into<Edges<Pixels>>) -> Self {
7833 PaintQuad {
7834 border_widths: border_widths.into(),
7835 ..self
7836 }
7837 }
7838
7839 pub fn border_color(self, border_color: impl Into<Hsla>) -> Self {
7841 PaintQuad {
7842 border_color: border_color.into(),
7843 ..self
7844 }
7845 }
7846
7847 pub fn background(self, background: impl Into<Background>) -> Self {
7849 PaintQuad {
7850 background: background.into(),
7851 ..self
7852 }
7853 }
7854}
7855
7856pub fn quad(
7858 bounds: Bounds<Pixels>,
7859 corner_radii: impl Into<Corners<Pixels>>,
7860 background: impl Into<Background>,
7861 border_widths: impl Into<Edges<Pixels>>,
7862 border_color: impl Into<Hsla>,
7863 border_style: BorderStyle,
7864) -> PaintQuad {
7865 PaintQuad {
7866 bounds,
7867 corner_radii: corner_radii.into(),
7868 background: background.into(),
7869 border_widths: border_widths.into(),
7870 border_color: border_color.into(),
7871 border_style,
7872 }
7873}
7874
7875pub fn fill(bounds: impl Into<Bounds<Pixels>>, background: impl Into<Background>) -> PaintQuad {
7877 PaintQuad {
7878 bounds: bounds.into(),
7879 corner_radii: (0.).into(),
7880 background: background.into(),
7881 border_widths: (0.).into(),
7882 border_color: transparent_black(),
7883 border_style: BorderStyle::default(),
7884 }
7885}
7886
7887pub fn outline(
7889 bounds: impl Into<Bounds<Pixels>>,
7890 border_color: impl Into<Hsla>,
7891 border_style: BorderStyle,
7892) -> PaintQuad {
7893 PaintQuad {
7894 bounds: bounds.into(),
7895 corner_radii: (0.).into(),
7896 background: transparent_black().into(),
7897 border_widths: (1.).into(),
7898 border_color: border_color.into(),
7899 border_style,
7900 }
7901}
7902
7903#[inline(never)]
7904fn with_element_arena_erased(callback: &mut dyn FnMut(&mut Arena)) -> Result<(), AccessError> {
7905 if let Some(arena_pointer) = CURRENT_ELEMENT_ARENA.try_with(Cell::get)? {
7906 let arena_cell = unsafe { &*arena_pointer };
7909 callback(&mut arena_cell.borrow_mut());
7910 Ok(())
7911 } else {
7912 ELEMENT_ARENA.try_with(|arena| callback(&mut arena.borrow_mut()))
7913 }
7914}
7915
7916#[cfg(test)]
7917mod tests {
7918 use std::{
7919 cell::{Cell, RefCell},
7920 path::PathBuf,
7921 rc::Rc,
7922 time::Duration,
7923 };
7924
7925 use crate::{
7926 AnyWindowHandle, AppContext as _, BackGestureEvent, BackGesturePhase, Bounds, ContentMask,
7927 Context, DispatchPhase, DragMoveEvent, Empty, ExternalDragPayload, ExternalPaths,
7928 FileDragPaths, FileDropEvent, FocusHandle, InputEvent as _, InteractiveElement as _,
7929 IntoElement, KeyDownEvent, Keystroke, LongPressEvent, MouseButton, MouseDownEvent,
7930 MouseMoveEvent, ParentElement, Pixels, PlatformInput, Point, Render, RequestFrameOptions,
7931 ScaledPixels, StatefulInteractiveElement as _, Styled, TestAppContext, TouchDragEvent,
7932 TouchEvent, TouchId, TouchPhase, Underline, UnderlineStyle, Window, WindowAppearance,
7933 WindowOptions, canvas, div, hsla, point, px, size,
7934 };
7935
7936 #[gpui::test]
7937 async fn test_focus_handle_release(cx: &mut TestAppContext) {
7938 let (handle, survivor) = cx.update(|cx| (cx.focus_handle(), cx.focus_handle()));
7939 let handle_id = handle.id;
7940 let weak_handle = handle.downgrade();
7941 let retained = handle.clone();
7942 drop(handle);
7943
7944 cx.update(|_| {});
7945 cx.read(|cx| {
7946 let handles = cx.focus_handles.read();
7947 assert_eq!(handles.handles.len(), 2);
7948 assert!(handles.dropped_handles.is_empty());
7949 });
7950 assert_eq!(weak_handle.upgrade().as_ref(), Some(&retained));
7951
7952 cx.background_spawn(async move { drop(retained) }).await;
7953 assert_eq!(weak_handle.upgrade(), None);
7954 cx.read(|cx| {
7955 assert_eq!(cx.focus_handles.read().dropped_handles, [handle_id]);
7956 });
7957 cx.update(|_| {});
7958 cx.read(|cx| {
7959 let handles = cx.focus_handles.read();
7960 assert_eq!(handles.handles.keys().collect::<Vec<_>>(), [survivor.id]);
7961 assert!(handles.dropped_handles.is_empty());
7962 });
7963
7964 let replacements = cx.update(|cx| [cx.focus_handle(), cx.focus_handle()]);
7965 assert_eq!(weak_handle.upgrade(), None);
7966 cx.update(|cx| {
7967 drop(replacements);
7968 cx.defer(move |_| drop(survivor));
7969 });
7970 cx.read(|cx| {
7971 let handles = cx.focus_handles.read();
7972 assert_eq!(handles.handles.len(), 0);
7973 assert!(handles.dropped_handles.is_empty());
7974 });
7975 }
7976
7977 #[gpui::test]
7978 fn test_dropped_focus_handle_blurs_only_its_windows(cx: &mut TestAppContext) {
7979 let windows = [
7980 cx.add_window(|_, _| EmptyView),
7981 cx.add_window(|_, _| EmptyView),
7982 cx.add_window(|_, _| EmptyView),
7983 cx.add_window(|_, _| EmptyView),
7984 cx.add_window(|_, _| EmptyView),
7985 ];
7986 let (handle, other_handle, survivor) =
7987 cx.update(|cx| (cx.focus_handle(), cx.focus_handle(), cx.focus_handle()));
7988 for window in &windows[..2] {
7989 window
7990 .update(cx, |_, window, cx| window.focus(&handle, cx))
7991 .expect("window exists");
7992 }
7993 windows[2]
7994 .update(cx, |_, window, cx| window.focus(&other_handle, cx))
7995 .expect("window exists");
7996 windows[3]
7997 .update(cx, |_, window, cx| window.focus(&survivor, cx))
7998 .expect("window exists");
7999
8000 cx.update(|cx| {
8001 for _ in 0..1_000 {
8002 drop(cx.focus_handle());
8003 }
8004 drop((handle, other_handle));
8005 });
8006 for window in &windows[..3] {
8007 window
8008 .update(cx, |_, window, _| assert_eq!(window.focus, None))
8009 .expect("window exists");
8010 }
8011 windows[3]
8012 .update(cx, |_, window, cx| {
8013 assert_eq!(window.focused(cx).as_ref(), Some(&survivor));
8014 assert_eq!(window.focus_generation, 1);
8015 })
8016 .expect("window exists");
8017 windows[4]
8018 .update(cx, |_, window, _| {
8019 assert_eq!(window.focus, None);
8020 assert_eq!(window.focus_generation, 0);
8021 })
8022 .expect("window exists");
8023 }
8024
8025 #[cfg(feature = "profiler")]
8026 #[gpui::test]
8027 fn test_frame_requests_and_skips_are_journaled(cx: &mut TestAppContext) {
8028 use crate::FrameRequestSource;
8029 use crate::profiler::journal::{
8030 self, ForegroundJournalEntry, FrameSkipReason, IntervalBoundary,
8031 };
8032 use scheduler::Instant;
8033
8034 cx.app.borrow_mut().mode = crate::app::GpuiMode::Production;
8035 let window = cx.add_window(|_, _| EmptyView);
8036 let platform_window = cx.test_window(window.into());
8037 platform_window.simulate_frame_request(RequestFrameOptions::default());
8038 let (journal, _guard) = journal::install_test_foreground_journal(64, 4);
8039 let mut collector = journal.collector();
8040
8041 for (signal_at, source) in [
8042 (Some(Instant::now()), FrameRequestSource::NativeCallback),
8043 (Some(Instant::now()), FrameRequestSource::LocalSchedule),
8044 (None, FrameRequestSource::NativeCallback),
8045 ] {
8046 platform_window.simulate_frame_request(RequestFrameOptions {
8047 signal_at,
8048 signal_source: source,
8049 require_presentation: true,
8050 ..Default::default()
8051 });
8052 let entries = collector.collect_unseen().entries;
8053 let signal_index = entries
8054 .iter()
8055 .position(|entry| {
8056 matches!(
8057 entry,
8058 ForegroundJournalEntry::PlatformSignal(signal)
8059 if signal.window_id == window.window_id()
8060 && signal.signal_at == signal_at
8061 && signal.source == source
8062 && signal_at.is_none_or(|at| signal.handled_at >= at)
8063 )
8064 })
8065 .expect("frame request metadata");
8066 let skip_index = entries
8067 .iter()
8068 .position(|entry| {
8069 matches!(
8070 entry,
8071 ForegroundJournalEntry::Boundary(IntervalBoundary::FrameSkipped(skipped))
8072 if skipped.window_id == window.window_id()
8073 && skipped.reason == FrameSkipReason::NoRenderNeeded
8074 )
8075 })
8076 .expect("completed no-render boundary");
8077 assert!(signal_index < skip_index);
8078 }
8079 }
8080
8081 #[cfg(feature = "profiler")]
8082 #[gpui::test]
8083 fn test_frame_demand_survives_throttling(cx: &mut TestAppContext) {
8084 use crate::profiler::journal::{
8085 self, ForegroundJournalEntry, FrameSkipReason, IntervalBoundary,
8086 };
8087 use scheduler::Instant;
8088
8089 cx.app.borrow_mut().mode = crate::app::GpuiMode::Production;
8091 let (journal, _guard) = journal::install_test_foreground_journal(256, 4);
8092 let mut collector = journal.collector();
8093 for initially_dirty in [true, false] {
8094 let window = cx
8096 .app
8097 .borrow_mut()
8098 .open_window(
8099 WindowOptions {
8100 inactive_frame_interval: Some(Duration::from_secs(3600)),
8101 ..Default::default()
8102 },
8103 |_, cx| cx.new(|_| EmptyView),
8104 )
8105 .expect("open inactive test window");
8106 let platform_window = cx.test_window(window.into());
8107 platform_window.simulate_active_status_change(false);
8108 platform_window.simulate_frame_request(RequestFrameOptions::default());
8109 let callback_ran = Rc::new(Cell::new(false));
8110 let draws_before = window
8111 .update(cx, |_, window, _| {
8112 let draws_before = window
8113 .frame_duration_snapshot()
8114 .draw_duration_histogram
8115 .len();
8116 if initially_dirty {
8117 window.refresh();
8118 }
8119 window.on_next_frame({
8120 let callback_ran = callback_ran.clone();
8121 move |window, _| {
8122 callback_ran.set(true);
8123 window.refresh();
8124 }
8125 });
8126 draws_before
8127 })
8128 .expect("schedule throttled frame");
8129 let input_at = Instant::now();
8131 journal::record_input(journal::InputTiming {
8132 kind: "test",
8133 start: input_at,
8134 end: input_at,
8135 caused_invalidation: false,
8136 });
8137 collector.collect_unseen();
8138 platform_window.simulate_frame_request(RequestFrameOptions {
8139 signal_at: Some(Instant::now()),
8140 ..Default::default()
8141 });
8142 window
8143 .update(cx, |_, window, _| {
8144 assert_eq!(
8145 window
8146 .frame_duration_snapshot()
8147 .draw_duration_histogram
8148 .len(),
8149 draws_before,
8150 );
8151 })
8152 .expect("inspect deferred frame");
8153 assert!(!callback_ran.get());
8154 assert!(collector.collect_unseen().entries.iter().any(|entry| {
8155 matches!(
8156 entry,
8157 ForegroundJournalEntry::Boundary(IntervalBoundary::FrameSkipped(skipped))
8158 if skipped.window_id == window.window_id()
8159 && skipped.reason == FrameSkipReason::InactiveFrameRateLimit
8160 )
8161 }));
8162 platform_window.simulate_frame_request(RequestFrameOptions {
8163 signal_at: Some(Instant::now()),
8164 require_presentation: true,
8165 ..Default::default()
8166 });
8167 window
8168 .update(cx, |_, window, _| {
8169 assert_eq!(
8170 window
8171 .frame_duration_snapshot()
8172 .draw_duration_histogram
8173 .len(),
8174 draws_before + 1,
8175 );
8176 })
8177 .expect("inspect presented frame");
8178 assert!(callback_ran.get());
8179 }
8180 }
8181
8182 #[gpui::test]
8186 fn test_window_visibility(cx: &mut TestAppContext) {
8187 use crate::WindowVisibility;
8188
8189 let window = cx.add_window(|_, _| EmptyView);
8190 let observed = Rc::new(RefCell::new(Vec::new()));
8191 let _subscription = window
8192 .update(cx, {
8193 let observed = observed.clone();
8194 move |_, window, _| {
8195 assert_eq!(window.visibility(), WindowVisibility::Visible);
8196 assert!(window.is_visible());
8197 window.observe_window_visibility(move |visibility, window, _| {
8198 assert_eq!(window.visibility(), visibility);
8199 observed.borrow_mut().push(visibility);
8200 })
8201 }
8202 })
8203 .unwrap();
8204 let test_window = cx.test_window(window.into());
8205 let frame_wake_count = test_window.frame_wake_count();
8206
8207 test_window.simulate_visibility_change(WindowVisibility::Hidden);
8208 assert_eq!(*observed.borrow(), [WindowVisibility::Hidden]);
8209 window
8210 .update(cx, |_, window, _| assert!(!window.is_visible()))
8211 .unwrap();
8212
8213 test_window.simulate_visibility_change(WindowVisibility::Hidden);
8215 assert_eq!(observed.borrow().len(), 1);
8216
8217 test_window.simulate_visibility_change(WindowVisibility::Visible);
8218 assert_eq!(
8219 *observed.borrow(),
8220 [WindowVisibility::Hidden, WindowVisibility::Visible]
8221 );
8222 window
8223 .update(cx, |_, window, _| assert!(window.is_visible()))
8224 .unwrap();
8225 assert_eq!(test_window.frame_wake_count(), frame_wake_count);
8226 }
8227
8228 #[gpui::test]
8231 fn test_display_tracking(cx: &mut TestAppContext) {
8232 use crate::{DisplayChanges, DisplayEvent, DisplayId, Subscription};
8233
8234 let sixty_hertz = Duration::from_secs(1) / 60;
8235 let one_hundred_twenty_hertz = Duration::from_secs(1) / 120;
8236 let one_hundred_forty_four_hertz = Duration::from_secs(1) / 144;
8237
8238 let display_events = Rc::new(RefCell::new(Vec::new()));
8239 let _display_subscription = cx.update({
8240 let display_events = display_events.clone();
8241 move |cx| cx.observe_displays(move |event, _| display_events.borrow_mut().push(event))
8242 });
8243
8244 let window = cx.add_window(|window, cx| DisplayTracker {
8245 refresh_intervals: Vec::new(),
8246 _subscription: cx.observe_window_display(
8247 window,
8248 |tracker: &mut DisplayTracker, window, cx| {
8249 tracker.refresh_intervals.push(window.refresh_interval(cx));
8250 },
8251 ),
8252 });
8253 let window_notifications = Rc::new(RefCell::new(Vec::new()));
8254 let _window_subscription = window
8255 .update(cx, {
8256 let window_notifications = window_notifications.clone();
8257 move |_, window, cx| {
8258 assert_eq!(window.refresh_interval(cx), Some(sixty_hertz));
8259 window.observe_window_display(move |window, cx| {
8260 window_notifications
8261 .borrow_mut()
8262 .push((window.display_id, window.refresh_interval(cx)));
8263 })
8264 }
8265 })
8266 .unwrap();
8267 let test_window = cx.test_window(window.into());
8268
8269 cx.test_platform()
8274 .connect_display(DisplayId(2), Some(one_hundred_twenty_hertz));
8275 test_window.simulate_move_to_display(DisplayId(2));
8276 assert_eq!(
8277 window_notifications.take(),
8278 [(Some(DisplayId(2)), Some(one_hundred_twenty_hertz))]
8279 );
8280 assert_eq!(display_events.take(), [DisplayEvent::Added(DisplayId(2))]);
8281 cx.simulate_display_refresh_interval_change(DisplayId(2), Some(one_hundred_twenty_hertz));
8282 assert!(window_notifications.borrow().is_empty());
8283
8284 test_window.simulate_move_to_display(DisplayId(2));
8286 assert!(window_notifications.borrow().is_empty());
8287
8288 cx.simulate_display_refresh_interval_change(
8289 DisplayId(2),
8290 Some(one_hundred_forty_four_hertz),
8291 );
8292 assert_eq!(
8293 window_notifications.take(),
8294 [(Some(DisplayId(2)), Some(one_hundred_forty_four_hertz))]
8295 );
8296
8297 cx.simulate_display_refresh_interval_change(DisplayId(1), Some(one_hundred_twenty_hertz));
8299 cx.simulate_display_removed(DisplayId(1));
8300 assert!(window_notifications.borrow().is_empty());
8301
8302 assert_eq!(
8303 display_events.take(),
8304 [
8305 DisplayEvent::Changed {
8306 id: DisplayId(2),
8307 changes: DisplayChanges::REFRESH_INTERVAL,
8308 },
8309 DisplayEvent::Changed {
8310 id: DisplayId(1),
8311 changes: DisplayChanges::REFRESH_INTERVAL,
8312 },
8313 DisplayEvent::Removed(DisplayId(1)),
8314 ]
8315 );
8316 window
8317 .update(cx, |tracker, _, _| {
8318 assert_eq!(
8319 tracker.refresh_intervals,
8320 [
8321 Some(one_hundred_twenty_hertz),
8322 Some(one_hundred_forty_four_hertz)
8323 ]
8324 );
8325 })
8326 .unwrap();
8327
8328 struct DisplayTracker {
8329 refresh_intervals: Vec<Option<Duration>>,
8330 _subscription: Subscription,
8331 }
8332
8333 impl Render for DisplayTracker {
8334 fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
8335 Empty
8336 }
8337 }
8338 }
8339
8340 #[gpui::test]
8341 fn test_fully_visible_bounds_preserve_layout_viewport(cx: &mut TestAppContext) {
8342 let window = cx.add_window(|_, _| EmptyView);
8343 let mut platform_window = cx.test_window(window.into());
8344 platform_window.simulate_resize(size(px(400.), px(800.)));
8345 window
8346 .update(cx, |_, window, _| {
8347 assert_eq!(
8348 window.visual_viewport_bounds(),
8349 Bounds::new(Point::default(), size(px(400.), px(800.)))
8350 );
8351 assert_eq!(
8352 window.fully_visible_bounds(),
8353 window.visual_viewport_bounds()
8354 );
8355 })
8356 .unwrap();
8357
8358 platform_window.simulate_frame_request(RequestFrameOptions::default());
8359 let wakes = platform_window.frame_wake_count();
8360 let visual_bounds = Bounds::new(point(px(10.), px(40.)), size(px(380.), px(460.)));
8361 platform_window.simulate_visual_viewport_change(visual_bounds);
8362 assert!(platform_window.frame_wake_count() > wakes);
8363 platform_window.simulate_frame_request(RequestFrameOptions::default());
8364 let wakes = platform_window.frame_wake_count();
8365 let insets = crate::WindowInsets {
8366 safe_area: crate::Edges {
8367 top: px(60.),
8368 right: px(20.),
8369 bottom: px(30.),
8370 left: px(-10.),
8371 },
8372 ime: crate::Edges {
8373 bottom: px(350.),
8374 ..Default::default()
8375 },
8376 ..Default::default()
8377 };
8378 platform_window.simulate_insets_change(insets.clone());
8379 assert!(platform_window.frame_wake_count() > wakes);
8380 window
8381 .update(cx, |_, window, cx| {
8382 let focus = cx.focus_handle();
8383 window.focus(&focus, cx);
8384 assert_eq!(window.insets(), insets);
8385 assert_eq!(window.viewport_size(), size(px(400.), px(800.)));
8386 assert_eq!(window.visual_viewport_bounds(), visual_bounds);
8387 assert_eq!(
8388 window.fully_visible_bounds(),
8389 Bounds::new(point(px(10.), px(60.)), size(px(370.), px(390.)))
8390 );
8391 window.request_virtual_keyboard();
8392 window.dismiss_virtual_keyboard();
8393 assert!(focus.is_focused(window));
8394 assert_eq!(window.viewport_size(), size(px(400.), px(800.)));
8395 })
8396 .unwrap();
8397 assert_eq!(platform_window.virtual_keyboard_requests(), 1);
8398 assert_eq!(platform_window.virtual_keyboard_dismissals(), 1);
8399
8400 platform_window.simulate_insets_change(crate::WindowInsets {
8401 safe_area: crate::Edges {
8402 top: px(900.),
8403 left: px(500.),
8404 ..Default::default()
8405 },
8406 ..Default::default()
8407 });
8408 window
8409 .update(cx, |_, window, _| {
8410 assert_eq!(
8411 window.fully_visible_bounds().size,
8412 size(Pixels::ZERO, Pixels::ZERO)
8413 );
8414 })
8415 .unwrap();
8416
8417 use crate::PlatformWindow as _;
8419 platform_window.on_insets_changed(Box::new(|_| {}));
8420 platform_window.simulate_insets_change(crate::WindowInsets::default());
8421 window
8422 .update(cx, |_, window, _| {
8423 assert_eq!(window.insets(), crate::WindowInsets::default());
8424 })
8425 .unwrap();
8426 }
8427
8428 struct EmptyView;
8429
8430 impl Render for EmptyView {
8431 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
8432 div()
8433 }
8434 }
8435
8436 struct OpensWindowOnPaint {
8437 opened: Rc<Cell<bool>>,
8438 }
8439
8440 impl Render for OpensWindowOnPaint {
8441 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
8442 let opened = self.opened.clone();
8443 div()
8444 .size_full()
8445 .child(canvas(
8446 |_, _, _| {},
8447 move |_, _, _window, cx| {
8448 if !opened.replace(true) {
8449 cx.open_window(WindowOptions::default(), |_, cx| cx.new(|_| EmptyView))
8450 .unwrap();
8451 }
8452 },
8453 ))
8454 .child(div().child("after"))
8458 }
8459 }
8460
8461 #[test]
8467 fn test_window_opened_during_draw_defers_arena_clear() {
8468 let mut cx = TestAppContext::single();
8469
8470 let opened = Rc::new(Cell::new(false));
8471 let window = cx.add_window({
8473 let opened = opened.clone();
8474 move |_, _| OpensWindowOnPaint { opened }
8475 });
8476
8477 assert!(opened.get());
8478 assert_eq!(cx.windows().len(), 2);
8479
8480 cx.update_window(window.into(), |_, window, cx| window.draw(cx).clear(cx))
8483 .unwrap();
8484 }
8485
8486 #[test]
8487 fn test_scale_factor_change_preserves_bounds_and_survives_resize() {
8488 let mut cx = TestAppContext::single();
8489 let window = cx.add_window(|_, _| EmptyView);
8490 let handle: AnyWindowHandle = window.into();
8491 let window_state = |cx: &mut TestAppContext| {
8492 cx.update_window(handle, |_, window, _| {
8493 (
8494 window.scale_factor(),
8495 window.bounds(),
8496 window.viewport_size(),
8497 )
8498 })
8499 .unwrap()
8500 };
8501
8502 let (scale_factor, mut expected_bounds, _) = window_state(&mut cx);
8503 assert_eq!(scale_factor, 2.0);
8504
8505 for (scale_factor, resized_size) in [
8506 (1.0, size(px(800.), px(600.))),
8507 (1.25, size(px(640.), px(480.))),
8508 (2.0, size(px(1024.), px(768.))),
8509 ] {
8510 cx.simulate_window_scale_factor_change(handle, scale_factor);
8511 assert_eq!(
8512 window_state(&mut cx),
8513 (scale_factor, expected_bounds, expected_bounds.size)
8514 );
8515
8516 cx.simulate_window_resize(handle, resized_size);
8517 expected_bounds.size = resized_size;
8518 assert_eq!(
8519 window_state(&mut cx),
8520 (scale_factor, expected_bounds, resized_size)
8521 );
8522 }
8523 }
8524
8525 #[gpui::test]
8530 fn test_frame_waker_fires_on_frame_demand(cx: &mut TestAppContext) {
8531 let window = cx.add_window(|_, _| EmptyView);
8532 let test_window = cx.test_window(window.into());
8533
8534 assert!(
8538 test_window.frame_wake_count() >= 1,
8539 "opening a window must wake the frame source for the initial frame"
8540 );
8541
8542 test_window.simulate_frame_request(RequestFrameOptions::default());
8544
8545 let baseline = test_window.frame_wake_count();
8548 test_window.simulate_frame_request(RequestFrameOptions::default());
8549 window.update(cx, |_, _, _| {}).unwrap();
8550 assert_eq!(
8551 test_window.frame_wake_count(),
8552 baseline,
8553 "clean frames and non-notifying updates must not wake the frame source"
8554 );
8555
8556 window.update(cx, |_, _, cx| cx.notify()).unwrap();
8558 assert!(
8559 test_window.frame_wake_count() > baseline,
8560 "notifying a view in an idle window must wake the frame source"
8561 );
8562
8563 test_window.simulate_frame_request(RequestFrameOptions::default());
8565 let baseline = test_window.frame_wake_count();
8566 test_window.simulate_frame_request(RequestFrameOptions::default());
8567 assert_eq!(
8568 test_window.frame_wake_count(),
8569 baseline,
8570 "serving demand must return the window to idle"
8571 );
8572
8573 window
8575 .update(cx, |_, window, _| window.on_next_frame(|_, _| {}))
8576 .unwrap();
8577 assert!(
8578 test_window.frame_wake_count() > baseline,
8579 "scheduling a next-frame callback in an idle window must wake the frame source"
8580 );
8581 }
8582
8583 #[gpui::test]
8588 fn test_pending_next_frame_callbacks_are_not_stranded(cx: &mut TestAppContext) {
8589 let window = cx.add_window(|_, _| EmptyView);
8590 let test_window = cx.test_window(window.into());
8591 test_window.simulate_frame_request(RequestFrameOptions::default());
8594
8595 let callback_ran = Rc::new(Cell::new(false));
8596 window
8597 .update(cx, {
8598 let callback_ran = callback_ran.clone();
8599 move |_, window, _| {
8600 window.on_next_frame(move |_, _| callback_ran.set(true));
8601 }
8602 })
8603 .unwrap();
8604
8605 let baseline = test_window.frame_wake_count();
8606 test_window.simulate_frame_request(RequestFrameOptions::default());
8607 assert!(
8614 test_window.frame_wake_count() > baseline || callback_ran.get(),
8615 "a frame request with pending next-frame callbacks must either run them or re-arm the frame source"
8616 );
8617 }
8618
8619 #[gpui::test]
8620 fn test_window_reports_no_raw_handle_instead_of_panicking(cx: &mut TestAppContext) {
8621 use raw_window_handle::{HandleError, HasDisplayHandle as _, HasWindowHandle as _};
8622
8623 let window = cx.add_window(|_, _| EmptyView);
8624 window
8625 .update(cx, |_, window, _| {
8626 assert!(matches!(
8627 window.window_handle(),
8628 Err(HandleError::NotSupported)
8629 ));
8630 assert!(matches!(
8631 window.display_handle(),
8632 Err(HandleError::NotSupported)
8633 ));
8634 })
8635 .unwrap();
8636 }
8637
8638 #[gpui::test]
8639 fn test_appearance_change_runs_after_app_update(cx: &mut TestAppContext) {
8640 let window = cx.add_window(|_, _| EmptyView);
8641 let observed_appearance = Rc::new(Cell::new(None));
8642 let _subscription = window
8643 .update(cx, {
8644 let observed_appearance = observed_appearance.clone();
8645 move |_, window, _| {
8646 window.observe_window_appearance(move |window, _| {
8647 observed_appearance.set(Some(window.appearance()));
8648 })
8649 }
8650 })
8651 .unwrap();
8652 let test_window = cx.test_window(window.into());
8653
8654 cx.update(|_| {
8655 test_window.simulate_appearance_change(WindowAppearance::Dark);
8656 assert_eq!(observed_appearance.get(), None);
8657 });
8658 cx.run_until_parked();
8659
8660 assert_eq!(observed_appearance.get(), Some(WindowAppearance::Dark));
8661 }
8662
8663 #[gpui::test]
8664 fn queued_frame_callback_wakes_a_parked_render_loop(cx: &mut TestAppContext) {
8665 let window = cx.add_window(|_, _| Empty);
8666 let test_window = cx.test_window(window.into());
8667
8668 assert!(test_window.simulate_scheduled_frame());
8669 assert!(test_window.simulate_scheduled_frame());
8670 assert!(!test_window.frame_scheduled());
8671
8672 cx.update_window(window.into(), |_, window, _| {
8673 window.active.set(true);
8674 window.on_next_frame(|_, _| {});
8675 })
8676 .unwrap();
8677 assert!(
8678 test_window.frame_scheduled(),
8679 "queuing work on a parked window must wake the render loop"
8680 );
8681
8682 assert!(test_window.simulate_scheduled_frame());
8683 assert!(
8684 test_window.frame_scheduled(),
8685 "presenting the frame must await one compositor callback"
8686 );
8687 assert!(test_window.simulate_scheduled_frame());
8688 assert!(!test_window.frame_scheduled());
8689 }
8690
8691 #[gpui::test]
8692 fn pending_presentation_wakes_a_parked_render_loop(cx: &mut TestAppContext) {
8693 let window = cx.add_window(|_, _| Empty);
8694 let test_window = cx.test_window(window.into());
8695
8696 assert!(test_window.simulate_scheduled_frame());
8697 assert!(test_window.simulate_scheduled_frame());
8698 assert!(!test_window.frame_scheduled());
8699
8700 cx.update_window(window.into(), |_, window, cx| window.draw(cx).clear(cx))
8701 .unwrap();
8702
8703 assert!(
8704 test_window.frame_scheduled(),
8705 "a rendered scene awaiting presentation must wake the render loop"
8706 );
8707 }
8708
8709 #[gpui::test]
8710 fn callback_queued_during_a_frame_requests_a_follow_up(cx: &mut TestAppContext) {
8711 let window = cx.add_window(|_, _| Empty);
8712 let test_window = cx.test_window(window.into());
8713
8714 let callback_ran = Rc::new(Cell::new(false));
8715 cx.update_window(window.into(), |_, window, _| {
8716 window.active.set(true);
8719 let callback_ran = callback_ran.clone();
8720 window.on_next_frame(move |window, _| {
8721 window.on_next_frame(move |_, _| callback_ran.set(true));
8722 });
8723 })
8724 .unwrap();
8725
8726 assert!(test_window.simulate_scheduled_frame());
8727 assert!(!callback_ran.get());
8728 assert!(
8729 test_window.frame_scheduled(),
8730 "a callback queued mid-frame must schedule a follow-up before the loop parks"
8731 );
8732
8733 assert!(test_window.simulate_scheduled_frame());
8734 assert!(callback_ran.get());
8735 }
8736
8737 struct RootView {
8738 explicit_size: bool,
8739 child_bounds: Rc<Cell<Bounds<Pixels>>>,
8740 }
8741
8742 impl Render for RootView {
8743 fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
8744 let child_bounds = self.child_bounds.clone();
8745 let root = div().flex().flex_col().child(
8746 canvas(
8747 move |bounds, _, _| child_bounds.set(bounds),
8748 |_, _, _, _| {},
8749 )
8750 .size_full(),
8751 );
8752 if self.explicit_size {
8753 root.w(px(300.)).h(px(200.))
8754 } else {
8755 root
8756 }
8757 }
8758 }
8759
8760 #[test]
8761 fn auto_sized_window_root_fills_the_window() {
8762 let mut cx = TestAppContext::single();
8763 let child_bounds = Rc::new(Cell::new(Bounds::default()));
8764 let window = cx.add_window({
8765 let child_bounds = child_bounds.clone();
8766 move |_, _| RootView {
8767 explicit_size: false,
8768 child_bounds,
8769 }
8770 });
8771
8772 let viewport_size = cx
8773 .update_window(window.into(), |_, window, cx| {
8774 window.draw(cx).clear(cx);
8775 window.viewport_size()
8776 })
8777 .unwrap();
8778
8779 assert_eq!(child_bounds.get().size, viewport_size);
8780 }
8781
8782 #[test]
8783 fn explicitly_sized_window_root_keeps_its_size() {
8784 let mut cx = TestAppContext::single();
8785 let child_bounds = Rc::new(Cell::new(Bounds::default()));
8786 let window = cx.add_window({
8787 let child_bounds = child_bounds.clone();
8788 move |_, _| RootView {
8789 explicit_size: true,
8790 child_bounds,
8791 }
8792 });
8793
8794 cx.update_window(window.into(), |_, window, cx| {
8795 window.draw(cx).clear(cx);
8796 })
8797 .unwrap();
8798
8799 assert_eq!(child_bounds.get().size, size(px(300.), px(200.)));
8800 }
8801
8802 struct FileDragView {
8803 path: PathBuf,
8804 observed_drag_moves: Rc<RefCell<Vec<Point<Pixels>>>>,
8805 observed_drops: Rc<RefCell<Vec<PathBuf>>>,
8806 }
8807
8808 struct FileDropExitView(Rc<Cell<usize>>);
8809
8810 impl Render for FileDropExitView {
8811 fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
8812 div().size_full().on_file_drop_exit({
8813 let observed_file_drop_exit = self.0.clone();
8814 move |_, _, _| observed_file_drop_exit.set(observed_file_drop_exit.get() + 1)
8815 })
8816 }
8817 }
8818
8819 impl Render for FileDragView {
8820 fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
8821 div()
8822 .id("file-drag")
8823 .size_full()
8824 .on_drag(self.path.clone(), |_, _, _, cx| cx.new(|_| Empty))
8825 .external_drag_payload(|path: &PathBuf, _, _| {
8826 Some(ExternalDragPayload::Files(FileDragPaths::new([(
8827 path.clone(),
8828 true,
8829 )])))
8830 })
8831 .on_drag_move({
8832 let observed_drag_moves = self.observed_drag_moves.clone();
8833 move |event: &DragMoveEvent<PathBuf>, _, _| {
8834 observed_drag_moves.borrow_mut().push(event.event.position);
8835 }
8836 })
8837 .on_drop({
8838 let observed_drops = self.observed_drops.clone();
8839 move |path: &PathBuf, _, _| observed_drops.borrow_mut().push(path.clone())
8840 })
8841 }
8842 }
8843
8844 #[gpui::test]
8845 fn file_drag_is_promoted_once_and_restored_in_source_window(cx: &mut TestAppContext) {
8846 struct Drag {
8847 window: AnyWindowHandle,
8848 observed_drag_moves: Rc<RefCell<Vec<Point<Pixels>>>>,
8849 observed_drops: Rc<RefCell<Vec<PathBuf>>>,
8850 }
8851
8852 fn start_drag(cx: &mut TestAppContext, path: PathBuf, platform_result: bool) -> Drag {
8853 let observed_drag_moves = Rc::new(RefCell::new(Vec::new()));
8854 let observed_drops = Rc::new(RefCell::new(Vec::new()));
8855 let window: AnyWindowHandle = cx
8856 .add_window({
8857 let observed_drag_moves = observed_drag_moves.clone();
8858 let observed_drops = observed_drops.clone();
8859 move |_, _| FileDragView {
8860 path,
8861 observed_drag_moves,
8862 observed_drops,
8863 }
8864 })
8865 .into();
8866 cx.test_window(window)
8867 .set_start_external_drag_result(platform_result);
8868
8869 let update_result = cx.update_window(window, |_, window, cx| {
8870 window.draw(cx).clear(cx);
8871 window.dispatch_event(
8872 MouseDownEvent {
8873 position: point(px(10.), px(10.)),
8874 button: MouseButton::Left,
8875 modifiers: Default::default(),
8876 click_count: 1,
8877 first_mouse: false,
8878 }
8879 .to_platform_input(),
8880 cx,
8881 );
8882 window.dispatch_event(
8883 MouseMoveEvent {
8884 position: point(px(20.), px(20.)),
8885 pressed_button: Some(MouseButton::Left),
8886 modifiers: Default::default(),
8887 }
8888 .to_platform_input(),
8889 cx,
8890 );
8891 assert!(cx.active_drag.is_some());
8892 });
8893 assert!(
8894 update_result.is_ok(),
8895 "failed to start drag: {update_result:?}"
8896 );
8897
8898 assert!(cx.test_window(window).external_drag_files().is_empty());
8899 Drag {
8900 window,
8901 observed_drag_moves,
8902 observed_drops,
8903 }
8904 }
8905
8906 let successful_path = PathBuf::from("/tmp/successful-drag");
8907 let successful = start_drag(cx, successful_path.clone(), true);
8908 let outside_position = point(px(-1.), px(20.));
8909 let update_result = cx.update_window(successful.window, |_, window, cx| {
8910 window.dispatch_event(
8911 MouseMoveEvent {
8912 position: outside_position,
8913 pressed_button: Some(MouseButton::Left),
8914 modifiers: Default::default(),
8915 }
8916 .to_platform_input(),
8917 cx,
8918 );
8919 assert!(cx.active_drag.is_none());
8920 });
8921 assert!(
8922 update_result.is_ok(),
8923 "failed to promote drag: {update_result:?}"
8924 );
8925 assert_eq!(
8926 cx.test_window(successful.window).external_drag_files(),
8927 [(successful_path.clone(), true)]
8928 );
8929 assert_eq!(
8932 successful.observed_drag_moves.borrow().last(),
8933 Some(&outside_position)
8934 );
8935
8936 let first_destination_exit_count = Rc::new(Cell::new(0));
8937 let first_destination: AnyWindowHandle = cx
8938 .add_window({
8939 let first_destination_exit_count = first_destination_exit_count.clone();
8940 move |_, _| FileDropExitView(first_destination_exit_count)
8941 })
8942 .into();
8943 let second_destination_exit_count = Rc::new(Cell::new(0));
8944 let second_destination: AnyWindowHandle = cx
8945 .add_window({
8946 let second_destination_exit_count = second_destination_exit_count.clone();
8947 move |_, _| FileDropExitView(second_destination_exit_count)
8948 })
8949 .into();
8950 let reentry_position = point(px(30.), px(30.));
8951 let external_paths = || ExternalPaths([successful_path.clone()].into_iter().collect());
8952 let update_result = cx.update_window(first_destination, |_, window, cx| {
8953 window.draw(cx).clear(cx);
8954 window.dispatch_event(
8955 FileDropEvent::Entered {
8956 position: reentry_position,
8957 paths: external_paths(),
8958 }
8959 .to_platform_input(),
8960 cx,
8961 );
8962 assert!(
8963 cx.active_drag
8964 .as_ref()
8965 .is_some_and(|drag| drag.value.downcast_ref::<ExternalPaths>().is_some())
8966 );
8967 window.dispatch_event(FileDropEvent::Exited.to_platform_input(), cx);
8968 assert!(cx.active_drag.is_none());
8969 assert_eq!(first_destination_exit_count.get(), 1);
8970 assert_eq!(second_destination_exit_count.get(), 0);
8971 });
8972 assert!(
8973 update_result.is_ok(),
8974 "failed to handle drag in first destination window: {update_result:?}"
8975 );
8976
8977 let update_result = cx.update_window(second_destination, |_, window, cx| {
8978 window.draw(cx).clear(cx);
8979 window.dispatch_event(
8980 PlatformInput::KeyDown(KeyDownEvent {
8981 keystroke: Keystroke::parse("down").expect("valid keystroke"),
8982 is_held: false,
8983 prefer_character_input: false,
8984 }),
8985 cx,
8986 );
8987 window.dispatch_event(
8988 FileDropEvent::Entered {
8989 position: reentry_position,
8990 paths: external_paths(),
8991 }
8992 .to_platform_input(),
8993 cx,
8994 );
8995 assert!(
8996 cx.active_drag
8997 .as_ref()
8998 .is_some_and(|drag| drag.value.downcast_ref::<ExternalPaths>().is_some())
8999 );
9000 assert_eq!(first_destination_exit_count.get(), 1);
9001 assert_eq!(second_destination_exit_count.get(), 0);
9002
9003 window.dispatch_event(FileDropEvent::Exited.to_platform_input(), cx);
9004 assert!(cx.active_drag.is_none());
9005 assert_eq!(first_destination_exit_count.get(), 1);
9006 assert_eq!(second_destination_exit_count.get(), 1);
9007 });
9008 assert!(
9009 update_result.is_ok(),
9010 "failed to handle drag in second destination window: {update_result:?}"
9011 );
9012
9013 let update_result = cx.update_window(successful.window, |_, window, cx| {
9014 window.dispatch_event(
9015 FileDropEvent::Entered {
9016 position: reentry_position,
9017 paths: external_paths(),
9018 }
9019 .to_platform_input(),
9020 cx,
9021 );
9022 assert!(
9023 cx.active_drag
9024 .as_ref()
9025 .is_some_and(|drag| drag.value.downcast_ref::<PathBuf>().is_some())
9026 );
9027 assert_eq!(
9028 successful.observed_drag_moves.borrow().last(),
9029 Some(&reentry_position)
9030 );
9031
9032 window.dispatch_event(FileDropEvent::Exited.to_platform_input(), cx);
9033 assert!(cx.active_drag.is_none());
9034
9035 window.dispatch_event(
9036 FileDropEvent::Entered {
9037 position: reentry_position,
9038 paths: external_paths(),
9039 }
9040 .to_platform_input(),
9041 cx,
9042 );
9043 assert!(
9044 cx.active_drag
9045 .as_ref()
9046 .is_some_and(|drag| drag.value.downcast_ref::<PathBuf>().is_some())
9047 );
9048
9049 window.dispatch_event(
9050 FileDropEvent::Submit {
9051 position: reentry_position,
9052 }
9053 .to_platform_input(),
9054 cx,
9055 );
9056 assert_eq!(
9057 successful.observed_drops.borrow().as_slice(),
9058 std::slice::from_ref(&successful_path)
9059 );
9060 assert!(cx.active_drag.is_none());
9061
9062 window.dispatch_event(FileDropEvent::Exited.to_platform_input(), cx);
9063 assert!(cx.active_drag.is_none());
9064 window.dispatch_event(FileDropEvent::Ended.to_platform_input(), cx);
9065 assert!(cx.active_drag.is_none());
9066
9067 window.dispatch_event(
9068 FileDropEvent::Entered {
9069 position: reentry_position,
9070 paths: external_paths(),
9071 }
9072 .to_platform_input(),
9073 cx,
9074 );
9075 assert!(
9076 cx.active_drag
9077 .as_ref()
9078 .is_some_and(|drag| drag.value.downcast_ref::<ExternalPaths>().is_some())
9079 );
9080 window.dispatch_event(FileDropEvent::Exited.to_platform_input(), cx);
9081 });
9082 assert!(
9083 update_result.is_ok(),
9084 "failed to restore drag in source window: {update_result:?}"
9085 );
9086
9087 let cancelled_path = PathBuf::from("/tmp/cancelled-drag");
9088 let cancelled = start_drag(cx, cancelled_path.clone(), true);
9089 let update_result = cx.update_window(cancelled.window, |_, window, cx| {
9090 window.dispatch_event(
9091 MouseMoveEvent {
9092 position: outside_position,
9093 pressed_button: Some(MouseButton::Left),
9094 modifiers: Default::default(),
9095 }
9096 .to_platform_input(),
9097 cx,
9098 );
9099 assert!(cx.active_drag.is_none());
9100
9101 window.dispatch_event(
9102 FileDropEvent::Entered {
9103 position: reentry_position,
9104 paths: ExternalPaths([cancelled_path].into_iter().collect()),
9105 }
9106 .to_platform_input(),
9107 cx,
9108 );
9109 assert!(
9110 cx.active_drag
9111 .as_ref()
9112 .is_some_and(|drag| drag.value.downcast_ref::<PathBuf>().is_some())
9113 );
9114 assert!(cx.stop_active_drag(window));
9115 assert!(cx.active_drag.is_none());
9116 });
9117 assert!(
9118 update_result.is_ok(),
9119 "failed to cancel restored drag: {update_result:?}"
9120 );
9121 assert!(!cx.update(|cx| cx.end_platform_drag(cancelled.window.window_id())));
9122
9123 let removed_path = PathBuf::from("/tmp/removed-window-drag");
9124 let removed = start_drag(cx, removed_path, true);
9125 let removed_window_id = removed.window.window_id();
9126 let update_result = cx.update_window(removed.window, |_, window, cx| {
9127 window.dispatch_event(
9128 MouseMoveEvent {
9129 position: outside_position,
9130 pressed_button: Some(MouseButton::Left),
9131 modifiers: Default::default(),
9132 }
9133 .to_platform_input(),
9134 cx,
9135 );
9136 assert!(cx.active_drag.is_none());
9137 window.remove_window();
9138 });
9139 assert!(
9140 update_result.is_ok(),
9141 "failed to remove drag source window: {update_result:?}"
9142 );
9143 assert!(!cx.update(|cx| cx.end_platform_drag(removed_window_id)));
9144
9145 let failed_path = PathBuf::from("/tmp/failed-drag");
9146 let failed = start_drag(cx, failed_path.clone(), false);
9147 let update_result = cx.update_window(failed.window, |_, window, cx| {
9148 for x_position in [-1., -2.] {
9149 window.dispatch_event(
9150 MouseMoveEvent {
9151 position: point(px(x_position), px(20.)),
9152 pressed_button: Some(MouseButton::Left),
9153 modifiers: Default::default(),
9154 }
9155 .to_platform_input(),
9156 cx,
9157 );
9158 }
9159 assert!(cx.active_drag.is_some());
9160 });
9161 assert!(
9162 update_result.is_ok(),
9163 "failed to retain drag after platform failure: {update_result:?}"
9164 );
9165 assert_eq!(
9166 cx.test_window(failed.window).external_drag_files(),
9167 [(failed_path, true)]
9168 );
9169 }
9170
9171 struct FocusForwarder {
9172 a: FocusHandle,
9173 b: FocusHandle,
9174 }
9175
9176 impl Render for FocusForwarder {
9177 fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
9178 div()
9179 .size_full()
9180 .child(div().w(px(50.)).h(px(50.)).track_focus(&self.a))
9181 .child(div().w(px(50.)).h(px(50.)).track_focus(&self.b))
9182 }
9183 }
9184
9185 #[gpui::test]
9189 fn test_focus_moved_by_focus_listener_is_dispatched(cx: &mut TestAppContext) {
9190 let b_focus_count = Rc::new(Cell::new(0));
9191 let window = cx.add_window({
9192 let b_focus_count = b_focus_count.clone();
9193 move |window, cx| {
9194 let a = cx.focus_handle();
9195 let b = cx.focus_handle();
9196 cx.on_focus(&a, window, |this: &mut FocusForwarder, window, cx| {
9197 let b = this.b.clone();
9198 window.focus(&b, cx);
9199 })
9200 .detach();
9201 cx.on_focus(&b, window, move |_, _, _| {
9202 b_focus_count.set(b_focus_count.get() + 1);
9203 })
9204 .detach();
9205 FocusForwarder { a, b }
9206 }
9207 });
9208
9209 window
9210 .update(cx, |_, window, _| window.activate_window())
9211 .unwrap();
9212 cx.executor().run_until_parked();
9213
9214 window
9215 .update(cx, |this, window, cx| {
9216 let a = this.a.clone();
9217 window.focus(&a, cx);
9218 })
9219 .unwrap();
9220 cx.executor().run_until_parked();
9221
9222 window
9223 .update(cx, |this, window, _| {
9224 assert!(this.b.is_focused(window));
9225 })
9226 .unwrap();
9227 assert_eq!(b_focus_count.get(), 1);
9228 }
9229
9230 #[gpui::test]
9231 fn claimed_touch_drag_receives_movement_and_release(cx: &mut TestAppContext) {
9232 let events = Rc::new(RefCell::new(Vec::new()));
9233 let window = cx.add_window({
9234 let events = events.clone();
9235 move |_, _| TouchDragListener { events }
9236 });
9237 let touch = TouchId(1);
9238
9239 dispatch_touch(window, cx, touch, TouchPhase::Started, 10.);
9240 dispatch_touch(window, cx, touch, TouchPhase::Moved, 30.);
9241 dispatch_touch(window, cx, touch, TouchPhase::Ended, 40.);
9242
9243 assert_eq!(
9244 events.borrow().as_slice(),
9245 [
9246 (TouchPhase::Started, px(10.)),
9247 (TouchPhase::Moved, px(30.)),
9248 (TouchPhase::Ended, px(40.)),
9249 ]
9250 );
9251 }
9252
9253 #[gpui::test]
9254 fn back_gesture_is_claimed_by_the_innermost_listener(cx: &mut TestAppContext) {
9255 let claims = Rc::new(RefCell::new(Vec::new()));
9256 let window = cx.add_window({
9257 let claims = claims.clone();
9258 move |_, _| BackListeners { claims }
9259 });
9260 let dispatch_back = |cx: &mut TestAppContext, x: f32| {
9261 window
9262 .update(cx, |_, window, cx| {
9263 window
9264 .dispatch_event(
9265 BackGestureEvent {
9266 phase: BackGesturePhase::Started,
9267 start_position: point(px(x), px(10.)),
9268 progress: 0.,
9269 }
9270 .to_platform_input(),
9271 cx,
9272 )
9273 .default_prevented
9274 })
9275 .unwrap()
9276 };
9277 assert!(dispatch_back(cx, 10.));
9278 assert!(dispatch_back(cx, 80.));
9279 assert!(!dispatch_back(cx, 150.));
9280 assert_eq!(claims.borrow().as_slice(), ["inner", "outer"]);
9281 }
9282
9283 struct BackListeners {
9284 claims: Rc<RefCell<Vec<&'static str>>>,
9285 }
9286
9287 impl Render for BackListeners {
9288 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
9289 let claim = |name: &'static str| {
9290 let claims = self.claims.clone();
9291 move |_: &BackGestureEvent, _: &mut Window, _: &mut crate::App| {
9292 claims.borrow_mut().push(name)
9293 }
9294 };
9295 div().size_full().child(
9296 div()
9297 .w(px(100.))
9298 .h_full()
9299 .on_back_gesture(claim("outer"))
9300 .child(div().w(px(50.)).h_full().on_back_gesture(claim("inner"))),
9301 )
9302 }
9303 }
9304
9305 struct TouchDragListener {
9306 events: Rc<RefCell<Vec<(TouchPhase, Pixels)>>>,
9307 }
9308
9309 impl Render for TouchDragListener {
9310 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
9311 let events = self.events.clone();
9312 canvas(
9313 |_, _, _| {},
9314 move |_, _, window, _| {
9315 window.on_mouse_event(move |event: &TouchDragEvent, phase, window, _cx| {
9316 if phase != DispatchPhase::Bubble {
9317 return;
9318 }
9319 events.borrow_mut().push((event.phase, event.position.x));
9320 if event.phase == TouchPhase::Started {
9321 window.prevent_default();
9322 }
9323 });
9324 },
9325 )
9326 }
9327 }
9328
9329 #[gpui::test]
9330 fn long_press_is_claimed_only_when_started_prevents_default(cx: &mut TestAppContext) {
9331 for response in [
9332 LongPressResponse::PreventDefault,
9333 LongPressResponse::StopPropagation,
9334 LongPressResponse::None,
9335 ] {
9336 let phases = Rc::new(RefCell::new(Vec::new()));
9337 let window = cx.add_window({
9338 let phases = phases.clone();
9339 move |_, _| LongPressListener { phases, response }
9340 });
9341 dispatch_touch(window, cx, TouchId(1), TouchPhase::Started, 0.);
9342 cx.executor().advance_clock(Duration::from_millis(501));
9343 cx.executor().run_until_parked();
9344 window
9345 .update(cx, |_, window, _| {
9346 assert_eq!(
9347 window.long_press_capture.is_some(),
9348 response == LongPressResponse::PreventDefault
9349 );
9350 })
9351 .unwrap();
9352 dispatch_touch(window, cx, TouchId(1), TouchPhase::Moved, 2.);
9353 dispatch_touch(window, cx, TouchId(1), TouchPhase::Ended, 2.);
9354 window
9355 .update(cx, |_, window, _| {
9356 assert!(window.long_press_capture.is_none());
9357 })
9358 .unwrap();
9359
9360 let phases = phases.borrow();
9361 if response == LongPressResponse::PreventDefault {
9362 assert_eq!(
9363 phases.as_slice(),
9364 [TouchPhase::Started, TouchPhase::Moved, TouchPhase::Ended]
9365 );
9366 } else {
9367 assert_eq!(phases.as_slice(), [TouchPhase::Started]);
9368 }
9369 }
9370 }
9371
9372 #[gpui::test]
9373 fn stale_default_prevention_does_not_claim_long_press(cx: &mut TestAppContext) {
9374 let phases = Rc::new(RefCell::new(Vec::new()));
9375 let window = cx.add_window({
9376 let phases = phases.clone();
9377 move |_, _| LongPressListener {
9378 phases,
9379 response: LongPressResponse::None,
9380 }
9381 });
9382 window
9383 .update(cx, |_, window, _| {
9384 window.prevent_default();
9385 })
9386 .unwrap();
9387
9388 dispatch_touch(window, cx, TouchId(1), TouchPhase::Started, 0.);
9389 cx.executor().advance_clock(Duration::from_millis(501));
9390 cx.executor().run_until_parked();
9391 dispatch_touch(window, cx, TouchId(1), TouchPhase::Moved, 2.);
9392
9393 assert_eq!(phases.borrow().as_slice(), [TouchPhase::Started]);
9394 }
9395
9396 #[gpui::test]
9397 fn resolved_touch_cancels_scheduled_long_press(cx: &mut TestAppContext) {
9398 for (phase, position) in [
9399 (TouchPhase::Ended, 0.),
9400 (TouchPhase::Cancelled, 0.),
9401 (TouchPhase::Moved, 20.),
9402 ] {
9403 let phases = Rc::new(RefCell::new(Vec::new()));
9404 let window = cx.add_window({
9405 let phases = phases.clone();
9406 move |_, _| LongPressListener {
9407 phases,
9408 response: LongPressResponse::PreventDefault,
9409 }
9410 });
9411 dispatch_touch(window, cx, TouchId(1), TouchPhase::Started, 0.);
9412 dispatch_touch(window, cx, TouchId(1), phase, position);
9413 cx.executor().advance_clock(Duration::from_millis(501));
9414 cx.executor().run_until_parked();
9415
9416 assert!(phases.borrow().is_empty(), "{phase:?} allowed long press");
9417 }
9418 }
9419
9420 #[gpui::test]
9421 fn stale_long_press_timer_cannot_affect_replacement_touch(cx: &mut TestAppContext) {
9422 let phases = Rc::new(RefCell::new(Vec::new()));
9423 let window = cx.add_window({
9424 let phases = phases.clone();
9425 move |_, _| LongPressListener {
9426 phases,
9427 response: LongPressResponse::PreventDefault,
9428 }
9429 });
9430 let first_touch = TouchId(1);
9431 dispatch_touch(window, cx, first_touch, TouchPhase::Started, 0.);
9432 cx.executor().advance_clock(Duration::from_millis(250));
9433 dispatch_touch(window, cx, first_touch, TouchPhase::Cancelled, 0.);
9434 dispatch_touch(window, cx, TouchId(2), TouchPhase::Started, 10.);
9435
9436 cx.executor().advance_clock(Duration::from_millis(251));
9437 cx.executor().run_until_parked();
9438 assert!(phases.borrow().is_empty());
9439
9440 cx.executor().advance_clock(Duration::from_millis(250));
9441 cx.executor().run_until_parked();
9442 assert_eq!(phases.borrow().as_slice(), [TouchPhase::Started]);
9443 }
9444
9445 #[gpui::test]
9446 fn test_underline_exclusions_preserve_device_geometry(cx: &mut TestAppContext) {
9447 test_underline_paint_at_scales(cx, |window| {
9448 let (numerator, denominator) = match window.scale_factor() {
9449 1.0 => (1, 1),
9450 1.25 => (5, 4),
9451 1.5 => (3, 2),
9452 2.0 => (2, 1),
9453 3.0 => (3, 1),
9454 scale => panic!("unexpected scale {scale}"),
9455 };
9456 let snap = |quarters: i32| {
9457 let scaled = quarters * numerator;
9458 let divisor = 4 * denominator;
9459 let rounded =
9460 scaled.abs() / divisor + i32::from(2 * (scaled.abs() % divisor) > divisor);
9461 ScaledPixels((scaled.signum() * rounded) as f32)
9462 };
9463 let stroke = |quarters| {
9464 if quarters == 0 {
9465 ScaledPixels(0.)
9466 } else {
9467 snap(quarters).max(ScaledPixels(1.))
9468 }
9469 };
9470
9471 for origin in [-101, -3, -2, -1, 0, 1, 2, 3, 101] {
9472 for width in [0, 1, 3, 84] {
9473 for thickness in [0, 1, 4, 7] {
9474 for wavy in [false, true] {
9475 let style = UnderlineStyle {
9476 thickness: px(thickness as f32 / 4.),
9477 color: Some(hsla(0.25, 0.5, 0.75, 0.5)),
9478 wavy,
9479 };
9480 let bounds = Bounds::new(
9481 point(snap(origin), snap(-origin)),
9482 size(
9483 stroke(width),
9484 stroke(thickness) * if wavy { 3. } else { 1. },
9485 ),
9486 );
9487 let origin = point(px(origin as f32 / 4.), px(-origin as f32 / 4.));
9488 let width = px(width as f32 / 4.);
9489 assert_eq!(window.underline_bounds(origin, width, &style), bounds);
9490 let original = paint_test_underlines(window, |window| {
9491 window.paint_underline(origin, width, &style);
9492 })
9493 .to_vec();
9494 assert_eq!(original.len(), usize::from(!bounds.is_empty()));
9495 if let Some(underline) = original.first() {
9496 assert_eq!(underline.bounds, bounds);
9497 assert_eq!(underline.thickness, stroke(thickness));
9498 assert_eq!(underline.wavy, wavy.into());
9499 assert_eq!(underline.color, hsla(0.25, 0.5, 0.75, 0.5));
9500 }
9501
9502 let underlines = paint_test_underlines(window, |window| {
9503 window.paint_underline_with_exclusions(origin, width, &style, &[]);
9504 });
9505 assert_eq!(underlines.len(), original.len());
9506 for (actual, original) in underlines.iter().zip(&original) {
9507 assert_same_underline_geometry(actual, original);
9508 assert_eq!(actual.content_mask, original.content_mask);
9509 }
9510
9511 let left = bounds.left().0 as i32;
9512 let right = bounds.right().0 as i32;
9513 let exclusions = [
9514 (15, 25),
9515 (3, 7),
9516 (5, 10),
9517 (10, 12),
9518 (0, 0),
9519 (4, 2),
9520 (-50, -1),
9521 (70, 100),
9522 ]
9523 .map(|(start, end)| {
9524 ScaledPixels((left + start) as f32)
9525 ..ScaledPixels((left + end) as f32)
9526 });
9527 let underlines = paint_test_underlines(window, |window| {
9528 window.paint_underline_with_exclusions(
9529 origin,
9530 width,
9531 &style,
9532 &exclusions,
9533 );
9534 });
9535 let expected = (left..right)
9536 .filter(|column| {
9537 !bounds.is_empty()
9538 && !exclusions.iter().any(|span| {
9539 span.contains(&ScaledPixels(*column as f32))
9540 })
9541 })
9542 .collect::<Vec<_>>();
9543 assert_eq!(underline_device_columns(underlines), expected);
9544 for underline in underlines {
9545 assert_same_underline_geometry(underline, &original[0]);
9546 }
9547 }
9548 }
9549 }
9550 }
9551 });
9552 }
9553
9554 #[gpui::test]
9555 fn test_underline_exclusions_preserve_helvetica_warning_edge(cx: &mut TestAppContext) {
9556 test_underline_paint_at_scales(cx, |window| {
9557 if window.scale_factor() != 2.0 {
9558 return;
9559 }
9560 let style = UnderlineStyle {
9561 thickness: px(1.),
9562 color: None,
9563 wavy: true,
9564 };
9565 let origin = point(px(2.888_183_8), px(15.357_917));
9566 let width = px(23.848_145) - origin.x;
9567 let original = paint_test_underlines(window, |window| {
9568 window.paint_underline(origin, width, &style);
9569 })[0];
9570 assert_eq!(original.bounds.left(), ScaledPixels(6.));
9571 assert_eq!(original.bounds.right(), ScaledPixels(48.));
9572 let point_bounds = window.underline_bounds(origin, px(10.829_102), &style);
9573 assert_eq!(point_bounds.left(), ScaledPixels(6.));
9574 assert_eq!(point_bounds.right(), ScaledPixels(28.));
9575
9576 let underlines = paint_test_underlines(window, |window| {
9577 window.paint_underline_with_exclusions(
9578 origin,
9579 width,
9580 &style,
9581 &[point_bounds.left()..point_bounds.right()],
9582 );
9583 });
9584 assert_eq!(underlines.len(), 1);
9585 assert_same_underline_geometry(&underlines[0], &original);
9586 assert_eq!(
9587 underline_device_columns(underlines),
9588 (28..48).collect::<Vec<_>>()
9589 );
9590 });
9591 }
9592
9593 #[gpui::test]
9594 fn test_underline_exclusions_preserve_content_mask_and_opacity(cx: &mut TestAppContext) {
9595 test_underline_paint_at_scales(cx, |window| {
9596 let scale = window.scale_factor();
9597 let original_mask = window.content_mask();
9598 let original_opacity = window.element_opacity();
9599 let mask = ContentMask {
9600 bounds: Bounds::from_corners(point(px(4.), px(10.)), point(px(16.), px(12.))),
9601 };
9602 let style = UnderlineStyle {
9603 thickness: px(2.),
9604 color: Some(hsla(0.25, 0.5, 0.75, 0.5)),
9605 wavy: true,
9606 };
9607 let origin = point(px(-1.25), px(9.25));
9608 let width = px(24.);
9609 window.with_content_mask(Some(mask), |window| {
9610 window.with_element_opacity(Some(0.5), |window| {
9611 window.with_element_opacity(Some(0.5), |window| {
9612 let original = paint_test_underlines(window, |window| {
9613 window.paint_underline(origin, width, &style);
9614 })[0];
9615 assert_eq!(original.color, hsla(0.25, 0.5, 0.75, 0.125));
9616 let underlines = paint_test_underlines(window, |window| {
9617 window.paint_underline_with_exclusions(
9618 origin,
9619 width,
9620 &style,
9621 &[ScaledPixels(6. * scale)..ScaledPixels(8. * scale)],
9622 );
9623 });
9624 assert_eq!(underlines.len(), 2);
9625 let expected = [(4. * scale, 6. * scale), (8. * scale, 16. * scale)].map(
9626 |(left, right)| {
9627 Bounds::from_corners(
9628 point(ScaledPixels(left), ScaledPixels((10. * scale).floor())),
9629 point(ScaledPixels(right), ScaledPixels((12. * scale).ceil())),
9630 )
9631 },
9632 );
9633 assert_eq!(
9634 underlines
9635 .iter()
9636 .map(|underline| underline.content_mask.bounds)
9637 .collect::<Vec<_>>(),
9638 expected
9639 );
9640 for underline in underlines {
9641 assert_same_underline_geometry(underline, &original);
9642 }
9643 });
9644 });
9645 });
9646 assert_eq!(window.content_mask(), original_mask);
9647 assert_eq!(window.element_opacity(), original_opacity);
9648 });
9649 }
9650
9651 #[gpui::test]
9652 fn test_underline_exclusions_adversarial_permutations(cx: &mut TestAppContext) {
9653 test_underline_paint_at_scales(cx, |window| {
9654 let style = UnderlineStyle {
9655 thickness: px(1.),
9656 color: None,
9657 wavy: true,
9658 };
9659 let origin = point(px(-4.), px(-1.));
9660 let width = px(8.);
9661 let left = (-4. * window.scale_factor()) as i32;
9662 let right = (4. * window.scale_factor()) as i32;
9663 let endpoints = [-16, -8, -1, 0, 1, 8, 16];
9664 for first_start in endpoints {
9665 for first_end in endpoints {
9666 for second_start in endpoints {
9667 for second_end in endpoints {
9668 let exclusions = [first_start..first_end, second_start..second_end];
9669 let expected = (left..right)
9670 .filter(|column| {
9671 !exclusions.iter().any(|span| span.contains(column))
9672 })
9673 .collect::<Vec<_>>();
9674 let exclusions = exclusions.map(|span| {
9675 ScaledPixels(span.start as f32)..ScaledPixels(span.end as f32)
9676 });
9677 let underlines = paint_test_underlines(window, |window| {
9678 window.paint_underline_with_exclusions(
9679 origin,
9680 width,
9681 &style,
9682 &exclusions,
9683 );
9684 });
9685 assert_eq!(
9686 underline_device_columns(underlines),
9687 expected,
9688 "{exclusions:?}"
9689 );
9690 }
9691 }
9692 }
9693 }
9694 });
9695 }
9696
9697 #[derive(Clone, Copy, PartialEq)]
9698 enum LongPressResponse {
9699 PreventDefault,
9700 StopPropagation,
9701 None,
9702 }
9703
9704 struct LongPressListener {
9705 phases: Rc<RefCell<Vec<TouchPhase>>>,
9706 response: LongPressResponse,
9707 }
9708
9709 impl Render for LongPressListener {
9710 fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
9711 let entity = cx.entity();
9712 let phases = self.phases.clone();
9713 let response = self.response;
9714 canvas(
9715 |_, _, _| {},
9716 move |_, _, window, _| {
9717 window.on_mouse_event(move |event: &LongPressEvent, phase, window, cx| {
9718 if phase != DispatchPhase::Bubble {
9719 return;
9720 }
9721 phases.borrow_mut().push(event.phase);
9722 match response {
9723 LongPressResponse::PreventDefault => {
9724 window.capture_long_press(&entity);
9725 window.prevent_default();
9726 }
9727 LongPressResponse::StopPropagation => cx.stop_propagation(),
9728 LongPressResponse::None => {}
9729 }
9730 });
9731 },
9732 )
9733 }
9734 }
9735
9736 struct UnderlineTestView(Rc<dyn Fn(&mut Window)>);
9737
9738 impl Render for UnderlineTestView {
9739 fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
9740 let paint = self.0.clone();
9741 canvas(
9742 |_, _, _| {},
9743 move |_, _, window, _| {
9744 window.content_mask_stack.push(ContentMask {
9745 bounds: Bounds::from_corners(
9746 point(px(-1000.), px(-1000.)),
9747 point(px(1000.), px(1000.)),
9748 ),
9749 });
9750 paint(window);
9751 window.content_mask_stack.pop();
9752 },
9753 )
9754 .size_full()
9755 }
9756 }
9757
9758 fn test_underline_paint_at_scales(
9759 cx: &mut TestAppContext,
9760 paint: impl Fn(&mut Window) + 'static,
9761 ) {
9762 let window = cx.add_window(move |_, _| UnderlineTestView(Rc::new(paint)));
9763 for scale in [1., 1.25, 1.5, 2., 3.] {
9764 cx.simulate_window_scale_factor_change(window.into(), scale);
9765 cx.update_window(window.into(), |_, window, cx| window.draw(cx).clear(cx))
9766 .unwrap();
9767 }
9768 }
9769
9770 fn paint_test_underlines(window: &mut Window, paint: impl FnOnce(&mut Window)) -> &[Underline] {
9771 window.next_frame.scene.clear();
9772 paint(window);
9773 &window.next_frame.scene.underlines
9774 }
9775
9776 fn assert_same_underline_geometry(actual: &Underline, expected: &Underline) {
9777 assert_eq!(actual.bounds, expected.bounds);
9778 assert_eq!(actual.thickness, expected.thickness);
9779 assert_eq!(actual.wavy, expected.wavy);
9780 assert_eq!(actual.color, expected.color);
9781 assert_eq!(actual.pad, expected.pad);
9782 }
9783
9784 fn underline_device_columns(underlines: &[Underline]) -> Vec<i32> {
9785 underlines
9786 .iter()
9787 .flat_map(|underline| {
9788 let bounds = underline.bounds.intersect(&underline.content_mask.bounds);
9789 bounds.left().0 as i32..bounds.right().0 as i32
9790 })
9791 .collect()
9792 }
9793
9794 fn dispatch_touch<T: 'static>(
9795 window: crate::WindowHandle<T>,
9796 cx: &mut TestAppContext,
9797 id: TouchId,
9798 phase: TouchPhase,
9799 x: f32,
9800 ) {
9801 window
9802 .update(cx, |_, window, cx| {
9803 window.dispatch_event(
9804 TouchEvent {
9805 id,
9806 phase,
9807 position: point(px(x), px(0.)),
9808 predicted_position: None,
9809 force: None,
9810 }
9811 .to_platform_input(),
9812 cx,
9813 );
9814 })
9815 .unwrap();
9816 }
9817}
9818
9819#[cfg(all(test, any(feature = "inspector", debug_assertions)))]
9820mod inspector_tests {
9821 use super::*;
9822 use crate::{
9823 DivInspectorState, InspectorElementId, MouseDownEvent, StyleRefinement, TestAppContext, div,
9824 };
9825
9826 #[gpui::test]
9827 fn inspector_only_tracks_its_open_window(cx: &mut TestAppContext) {
9828 let windows = [
9829 cx.add_window(|_, cx| InspectorTestRoot {
9830 child: cx.new(|_| InspectorTestView::default()),
9831 }),
9832 cx.add_window(|_, cx| InspectorTestRoot {
9833 child: cx.new(|_| InspectorTestView::default()),
9834 }),
9835 ];
9836 for window in windows {
9837 assert_closed_inspector(window.into(), cx);
9838 }
9839 for _ in 0..2 {
9840 cx.update_window(windows[0].into(), |root, window, cx| {
9841 let root = root.downcast::<InspectorTestRoot>().expect("test root");
9842 let child_widths = root.read(cx).child.read(cx).child_widths.clone();
9843 window.toggle_inspector(cx);
9844 window.draw(cx).clear(cx);
9845 assert_eq!(child_widths.borrow().as_slice(), &[px(10.); 3]);
9846 let path = window
9847 .rendered_frame
9848 .next_inspector_instance_ids
9849 .iter()
9850 .find_map(|(path, count)| (*count == 3).then(|| path.clone()))
9851 .expect("anonymous siblings share an inspector path");
9852 let selected_id = InspectorElementId {
9853 path,
9854 instance_id: 1,
9855 };
9856 let position = window
9857 .rendered_frame
9858 .hitboxes
9859 .iter()
9860 .find(|hitbox| {
9861 window.rendered_frame.inspector_hitboxes.get(&hitbox.id)
9862 == Some(&selected_id)
9863 })
9864 .expect("middle sibling is pickable")
9865 .bounds
9866 .center();
9867 window.simulate_mouse_move(position, cx);
9868 window.dispatch_event(
9869 PlatformInput::MouseDown(MouseDownEvent {
9870 position,
9871 button: MouseButton::Left,
9872 modifiers: Modifiers::default(),
9873 click_count: 1,
9874 first_mouse: false,
9875 }),
9876 cx,
9877 );
9878 window.dispatch_event(
9879 PlatformInput::MouseUp(MouseUpEvent {
9880 position,
9881 button: MouseButton::Left,
9882 modifiers: Modifiers::default(),
9883 click_count: 1,
9884 }),
9885 cx,
9886 );
9887 assert!(!window.is_inspector_picking(cx));
9888 assert_eq!(
9889 window
9890 .inspector
9891 .as_ref()
9892 .expect("open inspector")
9893 .read(cx)
9894 .active_element_id(),
9895 Some(&selected_id)
9896 );
9897 window.draw(cx).clear(cx);
9898 window.with_inspector_state::<DivInspectorState, _>(
9899 Some(&selected_id),
9900 cx,
9901 |state, _| {
9902 let state = state.as_mut().expect("selected div has style state");
9903 assert_eq!(
9904 state.base_style.size.width,
9905 Some(crate::Length::from(px(10.)))
9906 );
9907 state.base_style.size.width = Some(crate::Length::from(px(25.)));
9908 },
9909 );
9910 window.refresh();
9911 window.draw(cx).clear(cx);
9912 assert_eq!(
9913 child_widths.borrow().as_slice(),
9914 &[px(10.), px(25.), px(10.)]
9915 );
9916 })
9917 .expect("pick and edit a cached child");
9918 assert_closed_inspector(windows[1].into(), cx);
9919 windows[0]
9920 .update(cx, |_, window, cx| window.toggle_inspector(cx))
9921 .expect("close inspector");
9922 assert_closed_inspector(windows[0].into(), cx);
9923 }
9924 }
9925
9926 struct InspectorTestRoot {
9927 child: Entity<InspectorTestView>,
9928 }
9929
9930 impl Render for InspectorTestRoot {
9931 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
9932 self.child
9933 .clone()
9934 .cached(StyleRefinement::default().size(px(100.)))
9935 }
9936 }
9937
9938 #[derive(Default)]
9939 struct InspectorTestView {
9940 child_widths: Rc<RefCell<Vec<Pixels>>>,
9941 }
9942
9943 impl Render for InspectorTestView {
9944 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
9945 let child_widths = self.child_widths.clone();
9946 div()
9947 .on_children_prepainted(move |bounds, _, _| {
9948 *child_widths.borrow_mut() =
9949 bounds.iter().map(|bounds| bounds.size.width).collect();
9950 })
9951 .with_dynamic_prepaint_order(|_, _| SmallVec::from_iter([2, 0, 1]))
9952 .id("inspector-root")
9953 .flex()
9954 .children((0..3).map(|_| div().size(px(10.)).flex_shrink_0()))
9955 }
9956 }
9957
9958 fn assert_closed_inspector(window: AnyWindowHandle, cx: &mut TestAppContext) {
9959 cx.update_window(window, |root, window, cx| {
9960 window.draw(cx).clear(cx);
9961 window.draw(cx).clear(cx);
9962 let root = root.downcast::<InspectorTestRoot>().expect("test root");
9963 assert_eq!(
9964 root.read(cx)
9965 .child
9966 .read(cx)
9967 .child_widths
9968 .borrow()
9969 .as_slice(),
9970 &[px(10.); 3]
9971 );
9972 for frame in [&window.rendered_frame, &window.next_frame] {
9973 assert_eq!(frame.next_inspector_instance_ids.capacity(), 0);
9974 assert_eq!(frame.inspector_hitboxes.capacity(), 0);
9975 }
9976 })
9977 .expect("closed inspector has no bookkeeping and no style overrides");
9978 }
9979}