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, IsZero, KeyBinding, KeyContext, KeyDownEvent, KeyEvent, Keystroke,
14 KeystrokeEvent, LayoutId, LineLayoutIndex, Modifiers, ModifiersChangedEvent, MonochromeSprite,
15 MouseButton, MouseEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels, PlatformAtlas,
16 PlatformDisplay, PlatformInput, PlatformInputHandler, PlatformWindow, Point, PolychromeSprite,
17 Priority, PromptButton, PromptLevel, Quad, Render, RenderGlyphParams, RenderImage,
18 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, WindowOptions, WindowParams, WindowTextSystem,
25 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};
32#[cfg(target_os = "macos")]
33use core_video::pixel_buffer::CVPixelBuffer;
34use derive_more::{Deref, DerefMut};
35use futures::channel::oneshot;
36use gpui_util::post_inc;
37use gpui_util::{ResultExt, measure};
38use itertools::FoldWhile::{Continue, Done};
39use itertools::Itertools;
40use parking_lot::RwLock;
41use raw_window_handle::{HandleError, HasDisplayHandle, HasWindowHandle};
42use refineable::Refineable;
43use scheduler::Instant;
44use slotmap::SlotMap;
45use smallvec::SmallVec;
46use std::{
47 any::{Any, TypeId},
48 borrow::Cow,
49 cell::{Cell, RefCell},
50 cmp,
51 fmt::{Debug, Display},
52 hash::{Hash, Hasher},
53 marker::PhantomData,
54 mem,
55 ops::{DerefMut, Range},
56 rc::Rc,
57 sync::{
58 Arc, Weak,
59 atomic::{AtomicBool, AtomicUsize, Ordering::SeqCst},
60 },
61 thread::AccessError,
62 time::Duration,
63};
64use uuid::Uuid;
65
66pub(crate) mod a11y;
67mod prompts;
68
69pub use a11y::A11ySubtreeBuilder;
70
71use self::a11y::A11y;
72#[cfg(not(target_family = "wasm"))]
73use self::a11y::ROOT_NODE_ID;
74use crate::util::{
75 atomic_incr_if_not_zero, ceil_to_device_pixel, floor_to_device_pixel, round_half_toward_zero,
76 round_half_toward_zero_f64, round_stroke_to_device_pixel, round_to_device_pixel,
77};
78pub use prompts::*;
79
80pub const DEFAULT_WINDOW_SIZE: Size<Pixels> = size(px(1536.), px(1095.));
82
83pub const DEFAULT_ADDITIONAL_WINDOW_SIZE: Size<Pixels> = Size {
86 width: Pixels(900.),
87 height: Pixels(750.),
88};
89
90#[derive(Default, Copy, Clone, Debug, Eq, PartialEq)]
92pub enum DispatchPhase {
93 #[default]
98 Bubble,
99 Capture,
105}
106
107impl DispatchPhase {
108 #[inline]
110 pub fn bubble(self) -> bool {
111 self == DispatchPhase::Bubble
112 }
113
114 #[inline]
116 pub fn capture(self) -> bool {
117 self == DispatchPhase::Capture
118 }
119}
120
121struct WindowInvalidatorInner {
122 #[cfg(feature = "profiler")]
123 pub window_id: WindowId,
124 pub dirty: bool,
125 pub draw_phase: DrawPhase,
126 pub dirty_views: FxHashSet<EntityId>,
127 pub update_count: usize,
128 #[cfg(feature = "profiler")]
129 pub frame_dirty: FrameDirtyAccumulator,
130 pub platform_waker: Option<Rc<dyn Fn()>>,
131}
132
133#[cfg(feature = "profiler")]
139#[derive(Default)]
140struct FrameDirtyAccumulator {
141 dirty_at: Option<Instant>,
142 invalidations: u64,
143}
144
145#[derive(Clone)]
146pub(crate) struct WindowInvalidator {
147 inner: Rc<RefCell<WindowInvalidatorInner>>,
148}
149
150impl WindowInvalidator {
151 pub fn new(#[allow(unused_variables)] window_id: WindowId) -> Self {
152 WindowInvalidator {
153 inner: Rc::new(RefCell::new(WindowInvalidatorInner {
154 #[cfg(feature = "profiler")]
155 window_id,
156 dirty: true,
157 draw_phase: DrawPhase::None,
158 dirty_views: FxHashSet::default(),
159 update_count: 0,
160 #[cfg(feature = "profiler")]
161 frame_dirty: FrameDirtyAccumulator::default(),
162 platform_waker: None,
163 })),
164 }
165 }
166
167 pub fn invalidate_view(&self, entity: EntityId, cx: &mut App) -> bool {
168 let mut inner = self.inner.borrow_mut();
169 inner.update_count += 1;
170 inner.dirty_views.insert(entity);
171 if inner.draw_phase == DrawPhase::None {
172 #[cfg(feature = "profiler")]
173 let dirty_at = Self::record_frame_dirty(&mut inner);
174 let became_dirty = !inner.dirty;
175 inner.dirty = true;
176 let waker = became_dirty.then(|| inner.platform_waker.clone()).flatten();
177 #[cfg(feature = "profiler")]
178 let window_id = inner.window_id;
179 drop(inner);
180 #[cfg(feature = "profiler")]
181 if became_dirty {
182 profiler::journal::record_frame_pending(window_id, dirty_at);
183 }
184 cx.push_effect(Effect::Notify { emitter: entity });
185 if let Some(waker) = waker {
186 waker();
187 }
188 true
189 } else {
190 false
191 }
192 }
193
194 pub fn is_dirty(&self) -> bool {
195 self.inner.borrow().dirty
196 }
197
198 pub fn set_dirty(&self, dirty: bool) {
199 let mut inner = self.inner.borrow_mut();
200 let became_dirty = dirty && !inner.dirty;
201 inner.dirty = dirty;
202 if dirty {
203 inner.update_count += 1;
204 }
205 #[cfg(feature = "profiler")]
206 let dirty_at = dirty.then(|| Self::record_frame_dirty(&mut inner));
207 let waker = became_dirty.then(|| inner.platform_waker.clone()).flatten();
208 #[cfg(feature = "profiler")]
209 let window_id = inner.window_id;
210 drop(inner);
211 #[cfg(feature = "profiler")]
212 if became_dirty && let Some(dirty_at) = dirty_at {
213 profiler::journal::record_frame_pending(window_id, dirty_at);
214 }
215 if let Some(waker) = waker {
216 waker();
217 }
218 }
219
220 pub fn set_platform_waker(&self, waker: Option<Rc<dyn Fn()>>) {
221 let mut inner = self.inner.borrow_mut();
222 inner.platform_waker = waker;
223 let waker = inner.dirty.then(|| inner.platform_waker.clone()).flatten();
224 drop(inner);
225 if let Some(waker) = waker {
226 waker();
227 }
228 }
229
230 pub fn wake_platform(&self) {
234 let waker = self.inner.borrow().platform_waker.clone();
235 if let Some(waker) = waker {
236 waker();
237 }
238 }
239
240 pub fn set_phase(&self, phase: DrawPhase) {
241 self.inner.borrow_mut().draw_phase = phase
242 }
243
244 pub fn update_count(&self) -> usize {
245 self.inner.borrow().update_count
246 }
247
248 #[cfg(feature = "profiler")]
249 fn record_frame_dirty(inner: &mut WindowInvalidatorInner) -> Instant {
250 let dirty_at = *inner.frame_dirty.dirty_at.get_or_insert_with(Instant::now);
251 inner.frame_dirty.invalidations += 1;
252 dirty_at
253 }
254
255 #[cfg(feature = "profiler")]
256 fn take_frame_dirty(&self) -> FrameDirtyAccumulator {
257 mem::take(&mut self.inner.borrow_mut().frame_dirty)
258 }
259
260 pub fn take_views(&self) -> FxHashSet<EntityId> {
261 mem::take(&mut self.inner.borrow_mut().dirty_views)
262 }
263
264 pub fn replace_views(&self, views: FxHashSet<EntityId>) {
265 self.inner.borrow_mut().dirty_views = views;
266 }
267
268 pub fn not_drawing(&self) -> bool {
269 self.inner.borrow().draw_phase == DrawPhase::None
270 }
271
272 #[track_caller]
273 pub fn debug_assert_paint(&self) {
274 debug_assert!(
275 matches!(self.inner.borrow().draw_phase, DrawPhase::Paint),
276 "this method can only be called during paint"
277 );
278 }
279
280 #[track_caller]
281 pub fn debug_assert_prepaint(&self) {
282 debug_assert!(
283 matches!(self.inner.borrow().draw_phase, DrawPhase::Prepaint),
284 "this method can only be called during request_layout, or prepaint"
285 );
286 }
287
288 #[track_caller]
289 pub fn debug_assert_paint_or_prepaint(&self) {
290 debug_assert!(
291 matches!(
292 self.inner.borrow().draw_phase,
293 DrawPhase::Paint | DrawPhase::Prepaint
294 ),
295 "this method can only be called during request_layout, prepaint, or paint"
296 );
297 }
298}
299
300type AnyObserver = Box<dyn FnMut(&mut Window, &mut App) -> bool + 'static>;
301
302pub(crate) type AnyWindowFocusListener =
303 Box<dyn FnMut(&WindowFocusEvent, &mut Window, &mut App) -> bool + 'static>;
304
305pub(crate) struct WindowFocusEvent {
306 pub(crate) previous_focus_path: SmallVec<[FocusId; 8]>,
307 pub(crate) current_focus_path: SmallVec<[FocusId; 8]>,
308}
309
310impl WindowFocusEvent {
311 pub fn is_focus_in(&self, focus_id: FocusId) -> bool {
312 !self.previous_focus_path.contains(&focus_id) && self.current_focus_path.contains(&focus_id)
313 }
314
315 pub fn is_focus_out(&self, focus_id: FocusId) -> bool {
316 self.previous_focus_path.contains(&focus_id) && !self.current_focus_path.contains(&focus_id)
317 }
318}
319
320pub struct FocusOutEvent {
322 pub blurred: WeakFocusHandle,
324}
325
326slotmap::new_key_type! {
327 pub struct FocusId;
329}
330
331thread_local! {
332 pub(crate) static ELEMENT_ARENA: RefCell<Arena> = RefCell::new(Arena::new(1024 * 1024));
335
336 static CURRENT_ELEMENT_ARENA: Cell<Option<*const RefCell<Arena>>> = const { Cell::new(None) };
340}
341
342fn draw_in_progress() -> bool {
353 CURRENT_ELEMENT_ARENA.with(|current| current.get().is_some())
354}
355
356#[inline(always)]
359pub(crate) fn with_element_arena<R>(callback: impl FnOnce(&mut Arena) -> R) -> R {
360 let mut callback = Some(callback);
361 let mut result = None;
362 let access = with_element_arena_erased(&mut |arena| {
363 result = Some(callback.take().expect("arena callback runs once")(arena));
364 });
365 drop(callback);
366 access.expect("cannot access a Thread Local Storage value during or after destruction");
367 result.expect("arena callback produces a result")
368}
369
370pub(crate) struct ElementArenaScope {
385 entered: *const RefCell<Arena>,
388 previous: Option<*const RefCell<Arena>>,
389 exited: bool,
390}
391
392impl ElementArenaScope {
393 pub(crate) fn enter(arena: &RefCell<Arena>) -> Self {
395 arena.borrow_mut().begin_scope();
396 let previous = CURRENT_ELEMENT_ARENA.with(|current| {
397 let prev = current.get();
398 current.set(Some(arena as *const RefCell<Arena>));
399 prev
400 });
401 Self {
402 entered: arena as *const RefCell<Arena>,
403 previous,
404 exited: false,
405 }
406 }
407
408 pub(crate) fn exit(mut self, arena: &RefCell<Arena>) -> ArenaClearNeeded {
417 assert!(
418 std::ptr::eq(self.entered, arena),
419 "ElementArenaScope::exit called with a different arena than was entered"
420 );
421 self.exited = true;
422 ArenaClearNeeded::new(arena)
427 }
428}
429
430impl Drop for ElementArenaScope {
431 fn drop(&mut self) {
432 CURRENT_ELEMENT_ARENA.with(|current| {
439 current.set(self.previous);
440 });
441 unsafe { &*self.entered }.borrow_mut().end_scope();
445 if !self.exited && !std::thread::panicking() {
446 debug_assert!(false, "ElementArenaScope dropped without calling exit()");
447 log::error!(
448 "ElementArenaScope dropped without calling exit(); \
449 the arena clear for this draw was never requested"
450 );
451 }
452 }
453}
454
455#[must_use]
457pub struct ArenaClearNeeded {
458 arena: *const RefCell<Arena>,
461}
462
463impl ArenaClearNeeded {
464 fn new(arena: &RefCell<Arena>) -> Self {
467 Self {
468 arena: arena as *const RefCell<Arena>,
469 }
470 }
471
472 pub fn clear(self, cx: &mut App) {
481 assert!(
482 std::ptr::eq(self.arena, &cx.element_arena),
483 "ArenaClearNeeded::clear called with a different App than the draw ran against"
484 );
485 cx.element_arena.borrow_mut().clear();
486 }
487}
488
489pub(crate) type FocusMap = RwLock<SlotMap<FocusId, FocusRef>>;
490pub(crate) struct FocusRef {
491 pub(crate) ref_count: AtomicUsize,
492 pub(crate) tab_index: isize,
493 pub(crate) tab_stop: bool,
494}
495
496impl FocusId {
497 pub fn is_focused(&self, window: &Window) -> bool {
499 window.focus == Some(*self)
500 }
501
502 pub fn contains_focused(&self, window: &Window, cx: &App) -> bool {
505 window
506 .focused(cx)
507 .is_some_and(|focused| self.contains(focused.id, window))
508 }
509
510 pub fn within_focused(&self, window: &Window, cx: &App) -> bool {
513 let focused = window.focused(cx);
514 focused.is_some_and(|focused| focused.id.contains(*self, window))
515 }
516
517 pub(crate) fn contains(&self, other: Self, window: &Window) -> bool {
519 window
520 .rendered_frame
521 .dispatch_tree
522 .focus_contains(*self, other)
523 }
524}
525
526pub struct FocusHandle {
528 pub(crate) id: FocusId,
529 handles: Arc<FocusMap>,
530 pub tab_index: isize,
532 pub tab_stop: bool,
534}
535
536impl std::fmt::Debug for FocusHandle {
537 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
538 f.write_fmt(format_args!("FocusHandle({:?})", self.id))
539 }
540}
541
542impl FocusHandle {
543 pub(crate) fn new(handles: &Arc<FocusMap>) -> Self {
544 let id = handles.write().insert(FocusRef {
545 ref_count: AtomicUsize::new(1),
546 tab_index: 0,
547 tab_stop: false,
548 });
549
550 Self {
551 id,
552 tab_index: 0,
553 tab_stop: false,
554 handles: handles.clone(),
555 }
556 }
557
558 pub(crate) fn for_id(id: FocusId, handles: &Arc<FocusMap>) -> Option<Self> {
559 let lock = handles.read();
560 let focus = lock.get(id)?;
561 if atomic_incr_if_not_zero(&focus.ref_count) == 0 {
562 return None;
563 }
564 Some(Self {
565 id,
566 tab_index: focus.tab_index,
567 tab_stop: focus.tab_stop,
568 handles: handles.clone(),
569 })
570 }
571
572 pub fn tab_index(mut self, index: isize) -> Self {
574 self.tab_index = index;
575 if let Some(focus) = self.handles.write().get_mut(self.id) {
576 focus.tab_index = index;
577 }
578 self
579 }
580
581 pub fn tab_stop(mut self, tab_stop: bool) -> Self {
585 self.tab_stop = tab_stop;
586 if let Some(focus) = self.handles.write().get_mut(self.id) {
587 focus.tab_stop = tab_stop;
588 }
589 self
590 }
591
592 pub fn downgrade(&self) -> WeakFocusHandle {
594 WeakFocusHandle {
595 id: self.id,
596 handles: Arc::downgrade(&self.handles),
597 }
598 }
599
600 pub fn focus(&self, window: &mut Window, cx: &mut App) {
602 window.focus(self, cx)
603 }
604
605 pub fn is_focused(&self, window: &Window) -> bool {
607 self.id.is_focused(window)
608 }
609
610 pub fn contains_focused(&self, window: &Window, cx: &App) -> bool {
613 self.id.contains_focused(window, cx)
614 }
615
616 pub fn within_focused(&self, window: &Window, cx: &mut App) -> bool {
619 self.id.within_focused(window, cx)
620 }
621
622 pub fn contains(&self, other: &Self, window: &Window) -> bool {
624 self.id.contains(other.id, window)
625 }
626
627 pub fn dispatch_action(&self, action: &dyn Action, window: &mut Window, cx: &mut App) {
629 if let Some(node_id) = window
630 .rendered_frame
631 .dispatch_tree
632 .focusable_node_id(self.id)
633 {
634 window.dispatch_action_on_node(node_id, action, cx)
635 }
636 }
637}
638
639impl Clone for FocusHandle {
640 fn clone(&self) -> Self {
641 Self::for_id(self.id, &self.handles).unwrap()
642 }
643}
644
645impl PartialEq for FocusHandle {
646 fn eq(&self, other: &Self) -> bool {
647 self.id == other.id
648 }
649}
650
651impl Eq for FocusHandle {}
652
653impl Drop for FocusHandle {
654 fn drop(&mut self) {
655 self.handles
656 .read()
657 .get(self.id)
658 .unwrap()
659 .ref_count
660 .fetch_sub(1, SeqCst);
661 }
662}
663
664#[derive(Clone, Debug)]
666pub struct WeakFocusHandle {
667 pub(crate) id: FocusId,
668 pub(crate) handles: Weak<FocusMap>,
669}
670
671impl WeakFocusHandle {
672 pub fn upgrade(&self) -> Option<FocusHandle> {
674 let handles = self.handles.upgrade()?;
675 FocusHandle::for_id(self.id, &handles)
676 }
677}
678
679impl PartialEq for WeakFocusHandle {
680 fn eq(&self, other: &WeakFocusHandle) -> bool {
681 self.id == other.id
682 }
683}
684
685impl Eq for WeakFocusHandle {}
686
687impl PartialEq<FocusHandle> for WeakFocusHandle {
688 fn eq(&self, other: &FocusHandle) -> bool {
689 self.id == other.id
690 }
691}
692
693impl PartialEq<WeakFocusHandle> for FocusHandle {
694 fn eq(&self, other: &WeakFocusHandle) -> bool {
695 self.id == other.id
696 }
697}
698
699pub trait Focusable: 'static {
702 fn focus_handle(&self, cx: &App) -> FocusHandle;
704}
705
706impl<V: Focusable> Focusable for Entity<V> {
707 fn focus_handle(&self, cx: &App) -> FocusHandle {
708 self.read(cx).focus_handle(cx)
709 }
710}
711
712pub trait ManagedView: Focusable + EventEmitter<DismissEvent> + Render {}
715
716impl<M: Focusable + EventEmitter<DismissEvent> + Render> ManagedView for M {}
717
718pub struct DismissEvent;
720
721type FrameCallback = Box<dyn FnOnce(&mut Window, &mut App)>;
722
723pub(crate) type AnyMouseListener =
724 Box<dyn FnMut(&dyn Any, DispatchPhase, &mut Window, &mut App) + 'static>;
725
726#[derive(Clone)]
727pub(crate) struct CursorStyleRequest {
728 pub(crate) hitbox_id: Option<HitboxId>,
729 pub(crate) style: CursorStyle,
730}
731
732#[derive(Default, Eq, PartialEq)]
733pub(crate) struct HitTest {
734 pub(crate) ids: SmallVec<[HitboxId; 8]>,
735 pub(crate) hover_hitbox_count: usize,
736}
737
738#[derive(Clone, Copy, Debug, Eq, PartialEq)]
740pub enum WindowControlArea {
741 Drag,
743 Close,
745 Max,
747 Min,
749}
750
751#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
753pub struct HitboxId(u64);
754
755#[cfg(feature = "test-support")]
756impl HitboxId {
757 pub const fn placeholder() -> Self {
762 Self(0)
763 }
764}
765
766impl HitboxId {
767 pub fn is_hovered(self, window: &Window) -> bool {
774 if window.captured_hitbox == Some(self) {
776 return true;
777 }
778 if window.last_input_was_keyboard() {
779 return false;
780 }
781 self.hit_test(window)
782 }
783
784 pub(crate) fn is_hovered_ignoring_last_input(self, window: &Window) -> bool {
789 if window.captured_hitbox == Some(self) {
791 return true;
792 }
793 self.hit_test(window)
794 }
795
796 fn hit_test(self, window: &Window) -> bool {
797 let hit_test = &window.mouse_hit_test;
798 for id in hit_test.ids.iter().take(hit_test.hover_hitbox_count) {
799 if self == *id {
800 return true;
801 }
802 }
803 false
804 }
805
806 pub fn should_handle_scroll(self, window: &Window) -> bool {
811 window.mouse_hit_test.ids.contains(&self)
812 }
813
814 fn next(mut self) -> HitboxId {
815 HitboxId(self.0.wrapping_add(1))
816 }
817}
818
819#[derive(Clone, Debug, Deref)]
822pub struct Hitbox {
823 pub id: HitboxId,
825 #[deref]
827 pub bounds: Bounds<Pixels>,
828 pub content_mask: ContentMask<Pixels>,
830 pub behavior: HitboxBehavior,
832}
833
834impl Hitbox {
835 pub fn is_hovered(&self, window: &Window) -> bool {
852 self.id.is_hovered(window)
853 }
854
855 pub fn is_hovered_at(&self, position: Point<Pixels>, window: &Window) -> bool {
858 let hit_test = window.rendered_frame.hit_test(position);
859 hit_test
860 .ids
861 .iter()
862 .take(hit_test.hover_hitbox_count)
863 .any(|id| self.id == *id)
864 }
865
866 pub fn should_handle_scroll(&self, window: &Window) -> bool {
873 self.id.should_handle_scroll(window)
874 }
875}
876
877#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
879pub enum HitboxBehavior {
880 #[default]
882 Normal,
883
884 BlockMouse,
906
907 BlockMouseExceptScroll,
934}
935
936#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
938pub struct TooltipId(usize);
939
940impl TooltipId {
941 pub fn is_hovered(&self, window: &Window) -> bool {
943 window
944 .tooltip_bounds
945 .as_ref()
946 .is_some_and(|tooltip_bounds| {
947 tooltip_bounds.id == *self
948 && tooltip_bounds.bounds.contains(&window.mouse_position())
949 })
950 }
951}
952
953pub(crate) struct TooltipBounds {
954 id: TooltipId,
955 bounds: Bounds<Pixels>,
956}
957
958#[derive(Clone)]
959pub(crate) struct TooltipRequest {
960 id: TooltipId,
961 tooltip: AnyTooltip,
962}
963
964pub(crate) struct DeferredDraw {
965 current_view: EntityId,
966 priority: usize,
967 parent_node: DispatchNodeId,
968 element_id_stack: SmallVec<[ElementId; 32]>,
969 text_style_stack: Vec<TextStyleRefinement>,
970 content_mask: Option<ContentMask<Pixels>>,
971 rem_size: Pixels,
972 element: Option<AnyElement>,
973 absolute_offset: Point<Pixels>,
974 prepaint_range: Range<PrepaintStateIndex>,
975 paint_range: Range<PaintIndex>,
976}
977
978pub(crate) struct Frame {
979 pub(crate) focus: Option<FocusId>,
980 pub(crate) window_active: bool,
981 pub(crate) element_states: FxHashMap<(GlobalElementId, TypeId), ElementStateBox>,
982 accessed_element_states: Vec<(GlobalElementId, TypeId)>,
983 pub(crate) mouse_listeners: Vec<Option<AnyMouseListener>>,
984 pub(crate) dispatch_tree: DispatchTree,
985 pub(crate) scene: Scene,
986 pub(crate) hitboxes: Vec<Hitbox>,
987 pub(crate) window_control_hitboxes: Vec<(WindowControlArea, Hitbox)>,
988 pub(crate) deferred_draws: Vec<DeferredDraw>,
989 pub(crate) input_handlers: Vec<Option<PlatformInputHandler>>,
990 pub(crate) tooltip_requests: Vec<Option<TooltipRequest>>,
991 pub(crate) cursor_styles: Vec<CursorStyleRequest>,
992 #[cfg(any(test, feature = "test-support"))]
993 pub(crate) debug_bounds: FxHashMap<String, Bounds<Pixels>>,
994 #[cfg(any(test, feature = "test-support"))]
995 debug_bounds_records: Vec<(String, Bounds<Pixels>)>,
996 #[cfg(any(feature = "inspector", debug_assertions))]
997 pub(crate) next_inspector_instance_ids: FxHashMap<Rc<crate::InspectorElementPath>, usize>,
998 #[cfg(any(feature = "inspector", debug_assertions))]
999 pub(crate) inspector_hitboxes: FxHashMap<HitboxId, crate::InspectorElementId>,
1000 pub(crate) tab_stops: TabStopMap,
1001}
1002
1003#[derive(Clone, Default)]
1004pub(crate) struct PrepaintStateIndex {
1005 hitboxes_index: usize,
1006 tooltips_index: usize,
1007 deferred_draws_index: usize,
1008 dispatch_tree_index: usize,
1009 accessed_element_states_index: usize,
1010 line_layout_index: LineLayoutIndex,
1011}
1012
1013#[derive(Clone, Default)]
1014pub(crate) struct PaintIndex {
1015 scene_index: usize,
1016 #[cfg(any(test, feature = "test-support"))]
1017 debug_bounds_index: usize,
1018 mouse_listeners_index: usize,
1019 input_handlers_index: usize,
1020 cursor_styles_index: usize,
1021 accessed_element_states_index: usize,
1022 tab_handle_index: usize,
1023 line_layout_index: LineLayoutIndex,
1024}
1025
1026impl Frame {
1027 #[cfg(any(test, feature = "test-support"))]
1028 pub(crate) fn record_debug_bounds(&mut self, selector: String, bounds: Bounds<Pixels>) {
1029 self.debug_bounds.insert(selector.clone(), bounds);
1030 self.debug_bounds_records.push((selector, bounds));
1031 }
1032
1033 pub(crate) fn new(dispatch_tree: DispatchTree) -> Self {
1034 Frame {
1035 focus: None,
1036 window_active: false,
1037 element_states: FxHashMap::default(),
1038 accessed_element_states: Vec::new(),
1039 mouse_listeners: Vec::new(),
1040 dispatch_tree,
1041 scene: Scene::default(),
1042 hitboxes: Vec::new(),
1043 window_control_hitboxes: Vec::new(),
1044 deferred_draws: Vec::new(),
1045 input_handlers: Vec::new(),
1046 tooltip_requests: Vec::new(),
1047 cursor_styles: Vec::new(),
1048
1049 #[cfg(any(test, feature = "test-support"))]
1050 debug_bounds: FxHashMap::default(),
1051 #[cfg(any(test, feature = "test-support"))]
1052 debug_bounds_records: Vec::new(),
1053
1054 #[cfg(any(feature = "inspector", debug_assertions))]
1055 next_inspector_instance_ids: FxHashMap::default(),
1056
1057 #[cfg(any(feature = "inspector", debug_assertions))]
1058 inspector_hitboxes: FxHashMap::default(),
1059 tab_stops: TabStopMap::default(),
1060 }
1061 }
1062
1063 pub(crate) fn clear(&mut self) {
1064 self.element_states.clear();
1065 self.accessed_element_states.clear();
1066 self.mouse_listeners.clear();
1067 self.dispatch_tree.clear();
1068 self.scene.clear();
1069 self.input_handlers.clear();
1070 self.tooltip_requests.clear();
1071 self.cursor_styles.clear();
1072 self.hitboxes.clear();
1073 self.window_control_hitboxes.clear();
1074 self.deferred_draws.clear();
1075 self.tab_stops.clear();
1076 self.focus = None;
1077
1078 #[cfg(any(test, feature = "test-support"))]
1079 {
1080 self.debug_bounds.clear();
1081 self.debug_bounds_records.clear();
1082 }
1083
1084 #[cfg(any(feature = "inspector", debug_assertions))]
1085 {
1086 self.next_inspector_instance_ids.clear();
1087 self.inspector_hitboxes.clear();
1088 }
1089 }
1090
1091 pub(crate) fn cursor_style(&self, window: &Window) -> Option<CursorStyle> {
1092 self.cursor_styles
1093 .iter()
1094 .rev()
1095 .fold_while(None, |style, request| match request.hitbox_id {
1096 None => Done(Some(request.style)),
1097 Some(hitbox_id) => Continue(style.or_else(|| {
1098 hitbox_id
1099 .is_hovered_ignoring_last_input(window)
1100 .then_some(request.style)
1101 })),
1102 })
1103 .into_inner()
1104 }
1105
1106 pub(crate) fn hit_test(&self, position: Point<Pixels>) -> HitTest {
1107 let mut set_hover_hitbox_count = false;
1108 let mut hit_test = HitTest::default();
1109 for hitbox in self.hitboxes.iter().rev() {
1110 let bounds = hitbox.bounds.intersect(&hitbox.content_mask.bounds);
1111 if bounds.contains(&position) {
1112 hit_test.ids.push(hitbox.id);
1113 if !set_hover_hitbox_count
1114 && hitbox.behavior == HitboxBehavior::BlockMouseExceptScroll
1115 {
1116 hit_test.hover_hitbox_count = hit_test.ids.len();
1117 set_hover_hitbox_count = true;
1118 }
1119 if hitbox.behavior == HitboxBehavior::BlockMouse {
1120 break;
1121 }
1122 }
1123 }
1124 if !set_hover_hitbox_count {
1125 hit_test.hover_hitbox_count = hit_test.ids.len();
1126 }
1127 hit_test
1128 }
1129
1130 pub(crate) fn focus_path(&self) -> SmallVec<[FocusId; 8]> {
1131 self.focus
1132 .map(|focus_id| self.dispatch_tree.focus_path(focus_id))
1133 .unwrap_or_default()
1134 }
1135
1136 pub(crate) fn finish(&mut self, prev_frame: &mut Self) {
1137 for element_state_key in &self.accessed_element_states {
1138 if let Some((element_state_key, element_state)) =
1139 prev_frame.element_states.remove_entry(element_state_key)
1140 {
1141 self.element_states.insert(element_state_key, element_state);
1142 }
1143 }
1144
1145 self.scene.finish();
1146 }
1147}
1148
1149#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
1150enum InputModality {
1151 Mouse,
1152 Keyboard,
1153 Touch,
1154}
1155
1156pub struct Window {
1158 pub(crate) handle: AnyWindowHandle,
1159 pub(crate) invalidator: WindowInvalidator,
1160 pub(crate) removed: bool,
1161 pub(crate) platform_window: Box<dyn PlatformWindow>,
1162 display_id: Option<DisplayId>,
1163 is_resizable: bool,
1164 is_minimizable: bool,
1165 sprite_atlas: Arc<dyn PlatformAtlas>,
1166 text_system: Arc<WindowTextSystem>,
1167 text_rendering_mode: Rc<Cell<TextRenderingMode>>,
1168 rem_size: Pixels,
1169 rem_size_override_stack: SmallVec<[Pixels; 8]>,
1174 pub(crate) viewport_size: Size<Pixels>,
1175 layout_engine: Option<TaffyLayoutEngine>,
1176 pub(crate) root: Option<AnyView>,
1177 pub(crate) element_id_stack: SmallVec<[ElementId; 32]>,
1178 pub(crate) text_style_stack: Vec<TextStyleRefinement>,
1179 pub(crate) rendered_entity_stack: Vec<EntityId>,
1180 pub(crate) element_offset_stack: Vec<Point<Pixels>>,
1181 pub(crate) element_opacity: f32,
1182 pub(crate) content_mask_stack: Vec<ContentMask<Pixels>>,
1183 pub(crate) requested_autoscroll: Option<Bounds<Pixels>>,
1184 last_text_input_configuration: Option<TextInputConfiguration>,
1188 focused_text_input_active: bool,
1189 pub(crate) image_cache_stack: Vec<AnyImageCache>,
1190 pub(crate) rendered_frame: Frame,
1191 pub(crate) next_frame: Frame,
1192 next_hitbox_id: HitboxId,
1193 pub(crate) next_tooltip_id: TooltipId,
1194 pub(crate) tooltip_bounds: Option<TooltipBounds>,
1195 pub(crate) next_frame_callbacks: Rc<RefCell<Vec<FrameCallback>>>,
1196 pub(crate) dirty_views: FxHashSet<EntityId>,
1197 focus_listeners: SubscriberSet<(), AnyWindowFocusListener>,
1198 pub(crate) focus_lost_listeners: SubscriberSet<(), AnyObserver>,
1199 focus_lost_path: SmallVec<[FocusId; 8]>,
1200 default_prevented: bool,
1201 mouse_position: Point<Pixels>,
1202 mouse_hit_test: HitTest,
1203 modifiers: Modifiers,
1204 capslock: Capslock,
1205 scale_factor: f32,
1206 pub(crate) bounds_observers: SubscriberSet<(), AnyObserver>,
1207 appearance: WindowAppearance,
1208 pub(crate) appearance_observers: SubscriberSet<(), AnyObserver>,
1209 pub(crate) button_layout_observers: SubscriberSet<(), AnyObserver>,
1210 active: Rc<Cell<bool>>,
1211 visibility: WindowVisibility,
1212 pub(crate) visibility_observers:
1213 SubscriberSet<(), Box<dyn FnMut(WindowVisibility, &mut Window, &mut App) -> bool>>,
1214 hovered: Rc<Cell<bool>>,
1215 pub(crate) needs_present: Rc<Cell<bool>>,
1216 pub(crate) input_rate_tracker: Rc<RefCell<InputRateTracker>>,
1219 #[cfg(feature = "profiler")]
1220 window_profiler: profiler::WindowProfiler,
1221 last_input_modality: InputModality,
1222 touch_gestures: TouchGestureRecognizer,
1223 touch_prediction_enabled: bool,
1224 long_press_timer: Option<Task<()>>,
1225 long_press_capture: Option<EntityId>,
1226 pub(crate) refreshing: bool,
1227 pub(crate) activation_observers: SubscriberSet<(), AnyObserver>,
1228 pub(crate) focus: Option<FocusId>,
1229 focus_enabled: bool,
1230 pub(crate) focus_generation: u64,
1233 pending_input: Option<PendingInput>,
1234 pending_modifier: ModifierState,
1235 pub(crate) pending_input_observers: SubscriberSet<(), AnyObserver>,
1236 prompt: Option<RenderablePromptHandle>,
1237 pub(crate) client_inset: Option<Pixels>,
1238 captured_hitbox: Option<HitboxId>,
1241 #[cfg(any(feature = "inspector", debug_assertions))]
1242 inspector: Option<Entity<Inspector>>,
1243 #[cfg(feature = "profiler")]
1244 debug_frame_overlay: crate::debug_overlay::DebugFrameOverlay,
1245 pub(crate) a11y: A11y,
1246}
1247
1248#[derive(Clone, Debug, Default)]
1249struct ModifierState {
1250 modifiers: Modifiers,
1251 saw_other_input: bool,
1252}
1253
1254#[derive(Clone, Debug)]
1257pub(crate) struct InputRateTracker {
1258 timestamps: Vec<Instant>,
1259 window: Duration,
1260 inputs_per_second: u32,
1261 sustain_until: Instant,
1262 sustain_duration: Duration,
1263}
1264
1265impl Default for InputRateTracker {
1266 fn default() -> Self {
1267 Self {
1268 timestamps: Vec::new(),
1269 window: Duration::from_millis(100),
1270 inputs_per_second: 60,
1271 sustain_until: Instant::now(),
1272 sustain_duration: Duration::from_secs(1),
1273 }
1274 }
1275}
1276
1277impl InputRateTracker {
1278 pub fn record_input(&mut self) {
1279 let now = Instant::now();
1280 self.timestamps.push(now);
1281 self.prune_old_timestamps(now);
1282
1283 let min_events = self.inputs_per_second as u128 * self.window.as_millis() / 1000;
1284 if self.timestamps.len() as u128 >= min_events {
1285 self.sustain_until = now + self.sustain_duration;
1286 }
1287 }
1288
1289 pub fn is_high_rate(&self) -> bool {
1290 Instant::now() < self.sustain_until
1291 }
1292
1293 fn prune_old_timestamps(&mut self, now: Instant) {
1294 self.timestamps
1295 .retain(|&t| now.duration_since(t) <= self.window);
1296 }
1297}
1298
1299#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1300pub(crate) enum DrawPhase {
1301 None,
1302 Prepaint,
1303 Paint,
1304 Focus,
1305}
1306
1307pub(crate) const PENDING_INPUT_TIMEOUT: Duration = Duration::from_secs(1);
1308
1309pub struct PendingInputStatus<'a> {
1311 keystrokes: &'a [Keystroke],
1312 timeout: Option<PendingInputTimeoutStatus>,
1313}
1314
1315impl<'a> PendingInputStatus<'a> {
1316 pub fn keystrokes(&self) -> &'a [Keystroke] {
1318 self.keystrokes
1319 }
1320
1321 pub fn timeout(&self) -> Option<PendingInputTimeoutStatus> {
1323 self.timeout
1324 }
1325}
1326
1327#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1329pub struct PendingInputTimeoutStatus {
1330 duration: Duration,
1331 remaining: Duration,
1332 started_at: Option<Instant>,
1333 paused: bool,
1334}
1335
1336impl PendingInputTimeoutStatus {
1337 pub fn duration(&self) -> Duration {
1339 self.duration
1340 }
1341
1342 pub fn remaining(&self, cx: &App) -> Duration {
1344 self.started_at
1345 .map(|started_at| {
1346 self.remaining
1347 .saturating_sub(cx.background_executor().now() - started_at)
1348 })
1349 .unwrap_or(self.remaining)
1350 }
1351
1352 pub fn is_paused(&self) -> bool {
1354 self.paused
1355 }
1356}
1357
1358#[derive(Debug)]
1359struct PendingInputTimeout {
1360 duration: Duration,
1361 remaining: Duration,
1362 state: PendingInputTimeoutState,
1363}
1364
1365#[derive(Debug)]
1366enum PendingInputTimeoutState {
1367 Running { started_at: Instant, task: Task<()> },
1368 Paused { pause: PendingInputTimeoutPause },
1369}
1370
1371#[derive(Debug)]
1372struct PendingInputTimeoutPause {
1373 owner_id: EntityId,
1374 _release_subscription: Subscription,
1375}
1376
1377impl PendingInputTimeout {
1378 fn is_paused(&self) -> bool {
1379 matches!(&self.state, PendingInputTimeoutState::Paused { .. })
1380 }
1381
1382 fn pause(&mut self, pause: PendingInputTimeoutPause, now: Instant) -> bool {
1383 match std::mem::replace(&mut self.state, PendingInputTimeoutState::Paused { pause }) {
1384 PendingInputTimeoutState::Running { started_at, task } => {
1385 self.remaining = self.remaining.saturating_sub(now - started_at);
1386 drop(task);
1387 true
1388 }
1389 previous_state @ PendingInputTimeoutState::Paused { .. } => {
1390 self.state = previous_state;
1391 false
1392 }
1393 }
1394 }
1395
1396 fn pause_owner_id(&self) -> Option<EntityId> {
1397 match &self.state {
1398 PendingInputTimeoutState::Running { .. } => None,
1399 PendingInputTimeoutState::Paused { pause } => Some(pause.owner_id),
1400 }
1401 }
1402
1403 fn resume(&mut self, owner_id: EntityId, started_at: Instant, task: Task<()>) -> bool {
1404 match std::mem::replace(
1405 &mut self.state,
1406 PendingInputTimeoutState::Running { started_at, task },
1407 ) {
1408 PendingInputTimeoutState::Paused { pause } if pause.owner_id == owner_id => true,
1409 previous_state => {
1410 self.state = previous_state;
1411 false
1412 }
1413 }
1414 }
1415
1416 fn reset_duration(&mut self, duration: Duration) {
1417 self.duration = duration;
1418 self.remaining = duration;
1419 }
1420
1421 fn status(&self) -> PendingInputTimeoutStatus {
1422 let (started_at, paused) = match &self.state {
1423 PendingInputTimeoutState::Running { started_at, .. } => (Some(*started_at), false),
1424 PendingInputTimeoutState::Paused { .. } => (None, true),
1425 };
1426 PendingInputTimeoutStatus {
1427 duration: self.duration,
1428 remaining: self.remaining,
1429 started_at,
1430 paused,
1431 }
1432 }
1433}
1434
1435#[derive(Default, Debug)]
1436struct PendingInput {
1437 keystrokes: SmallVec<[Keystroke; 1]>,
1438 focus: Option<FocusId>,
1439 timeout: Option<PendingInputTimeout>,
1440}
1441
1442pub(crate) struct ElementStateBox {
1443 pub(crate) inner: Box<dyn Any>,
1444 #[cfg(debug_assertions)]
1445 pub(crate) type_name: &'static str,
1446}
1447
1448fn default_bounds(display_id: Option<DisplayId>, cx: &mut App) -> WindowBounds {
1449 let active_window_bounds = cx
1454 .active_window()
1455 .and_then(|w| w.update(cx, |_, window, _| window.window_bounds()).ok());
1456
1457 const CASCADE_OFFSET: f32 = 25.0;
1458
1459 let display = display_id
1460 .map(|id| cx.find_display(id))
1461 .unwrap_or_else(|| cx.primary_display());
1462
1463 let default_placement = || Bounds::new(point(px(0.), px(0.)), DEFAULT_WINDOW_SIZE);
1464
1465 let display_bounds = display
1467 .as_ref()
1468 .map(|d| d.visible_bounds())
1469 .unwrap_or_else(default_placement);
1470
1471 let (
1472 Bounds {
1473 origin: base_origin,
1474 size: base_size,
1475 },
1476 window_bounds_ctor,
1477 ): (_, fn(Bounds<Pixels>) -> WindowBounds) = match active_window_bounds {
1478 Some(bounds) => match bounds {
1479 WindowBounds::Windowed(bounds) => (bounds, WindowBounds::Windowed),
1480 WindowBounds::Maximized(bounds) => (bounds, WindowBounds::Maximized),
1481 WindowBounds::Fullscreen(bounds) => (bounds, WindowBounds::Fullscreen),
1482 },
1483 None => (
1484 display
1485 .as_ref()
1486 .map(|d| d.default_bounds())
1487 .unwrap_or_else(default_placement),
1488 WindowBounds::Windowed,
1489 ),
1490 };
1491
1492 let cascade_offset = point(px(CASCADE_OFFSET), px(CASCADE_OFFSET));
1493 let proposed_origin = base_origin + cascade_offset;
1494 let proposed_bounds = Bounds::new(proposed_origin, base_size);
1495
1496 let display_right = display_bounds.origin.x + display_bounds.size.width;
1497 let display_bottom = display_bounds.origin.y + display_bounds.size.height;
1498 let window_right = proposed_bounds.origin.x + proposed_bounds.size.width;
1499 let window_bottom = proposed_bounds.origin.y + proposed_bounds.size.height;
1500
1501 let fits_horizontally = window_right <= display_right;
1502 let fits_vertically = window_bottom <= display_bottom;
1503
1504 let final_origin = match (fits_horizontally, fits_vertically) {
1505 (true, true) => proposed_origin,
1506 (false, true) => point(display_bounds.origin.x, base_origin.y),
1507 (true, false) => point(base_origin.x, display_bounds.origin.y),
1508 (false, false) => display_bounds.origin,
1509 };
1510 window_bounds_ctor(Bounds::new(final_origin, base_size))
1511}
1512
1513impl Window {
1514 pub(crate) fn new(
1515 handle: AnyWindowHandle,
1516 options: WindowOptions,
1517 cx: &mut App,
1518 ) -> Result<Self> {
1519 let WindowOptions {
1520 window_bounds,
1521 titlebar,
1522 focus,
1523 show,
1524 kind,
1525 is_movable,
1526 app_owns_titlebar_drag,
1527 inactive_frame_interval,
1528 is_resizable,
1529 is_minimizable,
1530 display_id,
1531 window_background,
1532 app_id,
1533 window_min_size,
1534 window_decorations,
1535 #[cfg_attr(
1536 not(any(target_os = "linux", target_os = "freebsd")),
1537 allow(unused_variables)
1538 )]
1539 icon,
1540 #[cfg_attr(not(target_os = "macos"), allow(unused_variables))]
1541 tabbing_identifier,
1542 } = options;
1543
1544 let initial_window_title = titlebar
1545 .as_ref()
1546 .and_then(|titlebar| titlebar.title.clone());
1547
1548 let window_bounds = window_bounds.unwrap_or_else(|| default_bounds(display_id, cx));
1549 let mut platform_window = cx.platform.open_window(
1550 handle,
1551 WindowParams {
1552 bounds: window_bounds.get_bounds(),
1553 titlebar,
1554 kind,
1555 is_movable,
1556 app_owns_titlebar_drag,
1557 is_resizable,
1558 is_minimizable,
1559 focus,
1560 show,
1561 display_id,
1562 window_min_size,
1563 app_id: app_id.clone(),
1564 icon,
1565 #[cfg(target_os = "macos")]
1566 tabbing_identifier,
1567 },
1568 )?;
1569
1570 let tab_bar_visible = platform_window.tab_bar_visible();
1571 SystemWindowTabController::init_visible(cx, tab_bar_visible);
1572 if let Some(tabs) = platform_window.tabbed_windows() {
1573 SystemWindowTabController::add_tab(cx, handle.window_id(), tabs);
1574 }
1575
1576 let display_id = platform_window.display().map(|display| display.id());
1577 let sprite_atlas = platform_window.sprite_atlas();
1578 let mouse_position = platform_window.mouse_position();
1579 let modifiers = platform_window.modifiers();
1580 let capslock = platform_window.capslock();
1581 let content_size = platform_window.content_size();
1582 let scale_factor = platform_window.scale_factor();
1583 let appearance = platform_window.appearance();
1584 let text_system = Arc::new(WindowTextSystem::new(cx.text_system().clone()));
1585 let invalidator = WindowInvalidator::new(handle.window_id());
1586 let active = Rc::new(Cell::new(platform_window.is_active()));
1587 let visibility = platform_window.visibility();
1588 #[cfg(feature = "profiler")]
1589 profiler::journal::record_window_visibility(handle.window_id(), visibility);
1590 let hovered = Rc::new(Cell::new(platform_window.is_hovered()));
1591 let needs_present = Rc::new(Cell::new(false));
1592 let next_frame_callbacks: Rc<RefCell<Vec<FrameCallback>>> = Default::default();
1593 let input_rate_tracker = Rc::new(RefCell::new(InputRateTracker::default()));
1594 let last_frame_time = Rc::new(Cell::new(None));
1595
1596 platform_window
1597 .request_decorations(window_decorations.unwrap_or(WindowDecorations::Server));
1598 platform_window.set_background_appearance(window_background);
1599
1600 match window_bounds {
1601 WindowBounds::Fullscreen(_) => platform_window.toggle_fullscreen(),
1602 WindowBounds::Maximized(_) => platform_window.zoom(),
1603 WindowBounds::Windowed(_) => {}
1604 }
1605
1606 let accessibility_force_disabled = cx.accessibility_force_disabled;
1607 let a11y_active_flag = Arc::new(AtomicBool::new(false));
1608
1609 #[cfg(not(target_family = "wasm"))]
1610 if !accessibility_force_disabled {
1611 let mut initial_root_node = accesskit::Node::new(accesskit::Role::Window);
1612 if let Some(title) = &initial_window_title {
1613 initial_root_node.set_label(title.to_string());
1614 }
1615 let initial_tree = accesskit::TreeUpdate {
1616 nodes: vec![(ROOT_NODE_ID, initial_root_node)],
1617 tree: Some(accesskit::Tree::new(ROOT_NODE_ID)),
1618 tree_id: accesskit::TreeId::ROOT,
1619 focus: ROOT_NODE_ID,
1620 };
1621 let (activation_sender, activation_receiver) = async_channel::unbounded::<()>();
1622 let (deactivation_sender, deactivation_receiver) = async_channel::unbounded::<()>();
1623 let (action_sender, action_receiver) =
1624 async_channel::unbounded::<accesskit::ActionRequest>();
1625
1626 platform_window.a11y_init(crate::A11yCallbacks {
1627 activation: {
1628 let active_flag = a11y_active_flag.clone();
1629 Box::new(move || {
1630 log::info!("Accessibility activated");
1631 active_flag.store(true, SeqCst);
1632 activation_sender.send_blocking(()).log_err();
1633 Some(initial_tree.clone())
1634 })
1635 },
1636 action: Box::new(move |request| {
1637 action_sender.send_blocking(request).log_err();
1638 }),
1639 deactivation: {
1640 let active_flag = a11y_active_flag.clone();
1641 Box::new(move || {
1642 log::info!("Accessibility deactivated");
1643 active_flag.store(false, SeqCst);
1644 deactivation_sender.send_blocking(()).log_err();
1645 })
1646 },
1647 });
1648
1649 let mut async_cx = cx.to_async();
1655 cx.foreground_executor()
1656 .spawn(async move {
1657 while activation_receiver.recv().await.is_ok() {
1658 handle
1659 .update(&mut async_cx, |_, window, _| window.refresh())
1660 .log_err();
1661 }
1662 })
1663 .detach();
1664
1665 let mut async_cx = cx.to_async();
1666 cx.foreground_executor()
1667 .spawn(async move {
1668 while deactivation_receiver.recv().await.is_ok() {
1669 handle
1670 .update(&mut async_cx, |_, window, _| window.refresh())
1671 .log_err();
1672 }
1673 })
1674 .detach();
1675
1676 let mut async_cx = cx.to_async();
1677 cx.foreground_executor()
1678 .spawn(async move {
1679 while let Ok(request) = action_receiver.recv().await {
1680 handle
1681 .update(&mut async_cx, |_, window, cx| {
1682 window.handle_a11y_action(request, cx);
1683 })
1684 .log_err();
1685 }
1686 })
1687 .detach();
1688 }
1689
1690 platform_window.on_close(Box::new({
1691 let window_id = handle.window_id();
1692 let mut cx = cx.to_async();
1693 move || {
1694 let _ = handle.update(&mut cx, |_, window, _| window.remove_window());
1695 let _ = cx.update(|cx| {
1696 SystemWindowTabController::remove_tab(cx, window_id);
1697 });
1698 }
1699 }));
1700 platform_window.on_request_frame(Box::new({
1701 let mut cx = cx.to_async();
1702 let invalidator = invalidator.clone();
1703 let active = active.clone();
1704 let needs_present = needs_present.clone();
1705 let next_frame_callbacks = next_frame_callbacks.clone();
1706 let input_rate_tracker = input_rate_tracker.clone();
1707 let mut deferred_force_render = false;
1708 move |request_frame_options| {
1709 #[cfg(feature = "profiler")]
1710 let _foreground_turn = profiler::journal::foreground_turn();
1711 if draw_in_progress() {
1727 log::debug!("deferring re-entrant window draw request");
1728 deferred_force_render |= request_frame_options.force_render;
1729 return;
1730 }
1731 let force_render =
1735 mem::take(&mut deferred_force_render) || request_frame_options.force_render;
1736
1737 let thermal_state = handle
1738 .update(&mut cx, |_, _, cx| cx.thermal_state())
1739 .log_err();
1740
1741 let min_frame_interval = if request_frame_options.require_presentation
1745 || (!request_frame_options.force_render
1746 && next_frame_callbacks.borrow().is_empty())
1747 {
1748 None
1749 } else if !active.get() && !input_rate_tracker.borrow_mut().is_high_rate() {
1750 inactive_frame_interval
1751 } else if let Some(ThermalState::Critical | ThermalState::Serious) = thermal_state {
1752 Some(Duration::from_micros(16667))
1753 } else {
1754 None
1755 };
1756
1757 let now = Instant::now();
1758 if let Some(min_interval) = min_frame_interval {
1759 if let Some(last_frame) = last_frame_time.get()
1760 && now.duration_since(last_frame) < min_interval
1761 {
1762 deferred_force_render |= force_render;
1764 handle
1766 .update(&mut cx, |_, window, _| {
1767 window.platform_window.schedule_frame();
1768 })
1769 .log_err();
1770 invalidator.wake_platform();
1775 return;
1776 }
1777 }
1778 last_frame_time.set(Some(now));
1779
1780 let pending_next_frame_callbacks = next_frame_callbacks.take();
1781 if !pending_next_frame_callbacks.is_empty() {
1782 handle
1783 .update(&mut cx, |_, window, cx| {
1784 for callback in pending_next_frame_callbacks {
1785 callback(window, cx);
1786 }
1787 })
1788 .log_err();
1789 }
1790
1791 let needs_present = request_frame_options.require_presentation
1795 || needs_present.get()
1796 || input_rate_tracker.borrow_mut().is_high_rate();
1797
1798 if invalidator.is_dirty() || force_render {
1799 measure("frame duration", || {
1800 handle
1801 .update(&mut cx, |_, window, cx| {
1802 if force_render {
1803 window.refresh();
1806 }
1807 let arena_clear_needed = window.draw(cx);
1808 window.present();
1809 arena_clear_needed.clear(cx);
1810 })
1811 .log_err();
1812 })
1813 } else if needs_present {
1814 handle
1815 .update(&mut cx, |_, window, _| window.present())
1816 .log_err();
1817 }
1818
1819 handle
1820 .update(&mut cx, |_, window, _| {
1821 if window.invalidator.is_dirty()
1822 || !window.next_frame_callbacks.borrow().is_empty()
1823 {
1824 window.platform_window.schedule_frame();
1825 }
1826 })
1827 .log_err();
1828
1829 if invalidator.is_dirty() || !next_frame_callbacks.borrow().is_empty() {
1835 invalidator.wake_platform();
1836 }
1837 }
1838 }));
1839 invalidator.set_platform_waker(platform_window.frame_waker());
1840 platform_window.on_visual_viewport_changed(Box::new({
1841 let mut cx = cx.to_async();
1842 move || {
1843 handle
1844 .update(&mut cx, |_, window, _| window.refresh())
1845 .log_err();
1846 }
1847 }));
1848 platform_window.on_insets_changed(Box::new({
1849 let mut cx = cx.to_async();
1850 move |_| {
1851 handle
1852 .update(&mut cx, |_, window, _| window.refresh())
1853 .log_err();
1854 }
1855 }));
1856 platform_window.on_resize(Box::new({
1857 let mut cx = cx.to_async();
1858 move |_, _| {
1859 handle
1860 .update(&mut cx, |_, window, cx| window.bounds_changed(cx))
1861 .log_err();
1862 }
1863 }));
1864 platform_window.on_moved(Box::new({
1865 let mut cx = cx.to_async();
1866 move || {
1867 handle
1868 .update(&mut cx, |_, window, cx| window.bounds_changed(cx))
1869 .log_err();
1870 }
1871 }));
1872 platform_window.on_appearance_changed(Box::new({
1873 let cx = cx.to_async();
1874 let foreground_executor = cx.foreground_executor().clone();
1875 move || {
1876 let mut cx = cx.clone();
1877 foreground_executor
1880 .spawn(async move {
1881 handle
1882 .update(&mut cx, |_, window, cx| window.appearance_changed(cx))
1883 .log_err();
1884 })
1885 .detach();
1886 }
1887 }));
1888 platform_window.on_button_layout_changed(Box::new({
1889 let mut cx = cx.to_async();
1890 move || {
1891 handle
1892 .update(&mut cx, |_, window, cx| window.button_layout_changed(cx))
1893 .log_err();
1894 }
1895 }));
1896 platform_window.on_active_status_change(Box::new({
1897 let mut cx = cx.to_async();
1898 move |active| {
1899 handle
1900 .update(&mut cx, |_, window, cx| {
1901 window.active.set(active);
1902 window.modifiers = window.platform_window.modifiers();
1903 window.capslock = window.platform_window.capslock();
1904 window
1905 .activation_observers
1906 .clone()
1907 .retain(&(), |callback| callback(window, cx));
1908
1909 window.bounds_changed(cx);
1910 window.refresh();
1911
1912 SystemWindowTabController::update_last_active(cx, window.handle.id);
1913 })
1914 .log_err();
1915 }
1916 }));
1917 platform_window.on_visibility_change(Box::new({
1918 let mut cx = cx.to_async();
1919 move |_| {
1920 handle
1921 .update(&mut cx, |_, window, cx| {
1922 window.refresh_visibility(cx);
1923 })
1924 .log_err();
1925 }
1926 }));
1927 platform_window.on_hover_status_change(Box::new({
1928 let mut cx = cx.to_async();
1929 move |active| {
1930 handle
1931 .update(&mut cx, |_, window, _| {
1932 window.hovered.set(active);
1933 window.refresh();
1934 })
1935 .log_err();
1936 }
1937 }));
1938 platform_window.on_input({
1939 let mut cx = cx.to_async();
1940 Box::new(move |event| {
1941 handle
1942 .update(&mut cx, |_, window, cx| window.dispatch_event(event, cx))
1943 .log_err()
1944 .unwrap_or(DispatchEventResult::default())
1945 })
1946 });
1947 platform_window.on_hit_test_window_control({
1948 let mut cx = cx.to_async();
1949 Box::new(move || {
1950 handle
1951 .update(&mut cx, |_, window, _cx| {
1952 for (area, hitbox) in &window.rendered_frame.window_control_hitboxes {
1953 if window.mouse_hit_test.ids.contains(&hitbox.id) {
1954 return Some(*area);
1955 }
1956 }
1957 None
1958 })
1959 .log_err()
1960 .unwrap_or(None)
1961 })
1962 });
1963 platform_window.on_move_tab_to_new_window({
1964 let mut cx = cx.to_async();
1965 Box::new(move || {
1966 handle
1967 .update(&mut cx, |_, _window, cx| {
1968 SystemWindowTabController::move_tab_to_new_window(cx, handle.window_id());
1969 })
1970 .log_err();
1971 })
1972 });
1973 platform_window.on_merge_all_windows({
1974 let mut cx = cx.to_async();
1975 Box::new(move || {
1976 handle
1977 .update(&mut cx, |_, _window, cx| {
1978 SystemWindowTabController::merge_all_windows(cx, handle.window_id());
1979 })
1980 .log_err();
1981 })
1982 });
1983 platform_window.on_select_next_tab({
1984 let mut cx = cx.to_async();
1985 Box::new(move || {
1986 handle
1987 .update(&mut cx, |_, _window, cx| {
1988 SystemWindowTabController::select_next_tab(cx, handle.window_id());
1989 })
1990 .log_err();
1991 })
1992 });
1993 platform_window.on_select_previous_tab({
1994 let mut cx = cx.to_async();
1995 Box::new(move || {
1996 handle
1997 .update(&mut cx, |_, _window, cx| {
1998 SystemWindowTabController::select_previous_tab(cx, handle.window_id())
1999 })
2000 .log_err();
2001 })
2002 });
2003 platform_window.on_toggle_tab_bar({
2004 let mut cx = cx.to_async();
2005 Box::new(move || {
2006 handle
2007 .update(&mut cx, |_, window, cx| {
2008 let tab_bar_visible = window.platform_window.tab_bar_visible();
2009 SystemWindowTabController::set_visible(cx, tab_bar_visible);
2010 })
2011 .log_err();
2012 })
2013 });
2014
2015 if let Some(app_id) = app_id {
2016 platform_window.set_app_id(&app_id);
2017 }
2018
2019 platform_window.map_window().unwrap();
2020
2021 Ok(Window {
2022 handle,
2023 invalidator,
2024 removed: false,
2025 platform_window,
2026 display_id,
2027 is_resizable,
2028 is_minimizable,
2029 sprite_atlas,
2030 text_system,
2031 text_rendering_mode: cx.text_rendering_mode.clone(),
2032 rem_size: px(16.),
2033 rem_size_override_stack: SmallVec::new(),
2034 viewport_size: content_size,
2035 layout_engine: Some(TaffyLayoutEngine::new()),
2036 root: None,
2037 element_id_stack: SmallVec::default(),
2038 text_style_stack: Vec::new(),
2039 rendered_entity_stack: Vec::new(),
2040 element_offset_stack: Vec::new(),
2041 content_mask_stack: Vec::new(),
2042 element_opacity: 1.0,
2043 requested_autoscroll: None,
2044 last_text_input_configuration: None,
2045 focused_text_input_active: false,
2046 rendered_frame: Frame::new(DispatchTree::new(cx.keymap.clone(), cx.actions.clone())),
2047 next_frame: Frame::new(DispatchTree::new(cx.keymap.clone(), cx.actions.clone())),
2048 next_frame_callbacks,
2049 next_hitbox_id: HitboxId(0),
2050 next_tooltip_id: TooltipId::default(),
2051 tooltip_bounds: None,
2052 dirty_views: FxHashSet::default(),
2053 focus_listeners: SubscriberSet::new(),
2054 focus_lost_listeners: SubscriberSet::new(),
2055 focus_lost_path: SmallVec::new(),
2056 default_prevented: true,
2057 mouse_position,
2058 mouse_hit_test: HitTest::default(),
2059 modifiers,
2060 capslock,
2061 scale_factor,
2062 bounds_observers: SubscriberSet::new(),
2063 appearance,
2064 appearance_observers: SubscriberSet::new(),
2065 button_layout_observers: SubscriberSet::new(),
2066 active,
2067 visibility,
2068 visibility_observers: SubscriberSet::new(),
2069 hovered,
2070 needs_present,
2071 input_rate_tracker,
2072 #[cfg(feature = "profiler")]
2073 window_profiler: profiler::WindowProfiler::new(handle.window_id())?,
2074 last_input_modality: InputModality::Mouse,
2075 touch_gestures: TouchGestureRecognizer::new(
2076 cx.platform
2077 .gestures()
2078 .map_or_else(GestureTuning::default, |gestures| gestures.tuning()),
2079 ),
2080 touch_prediction_enabled: true,
2081 long_press_timer: None,
2082 long_press_capture: None,
2083 refreshing: false,
2084 activation_observers: SubscriberSet::new(),
2085 focus: None,
2086 focus_enabled: true,
2087 focus_generation: 0,
2088 pending_input: None,
2089 pending_modifier: ModifierState::default(),
2090 pending_input_observers: SubscriberSet::new(),
2091 prompt: None,
2092 client_inset: None,
2093 image_cache_stack: Vec::new(),
2094 captured_hitbox: None,
2095 #[cfg(any(feature = "inspector", debug_assertions))]
2096 inspector: None,
2097 #[cfg(feature = "profiler")]
2098 debug_frame_overlay: crate::debug_overlay::DebugFrameOverlay::new(),
2099 a11y: A11y::new(
2100 a11y_active_flag,
2101 accessibility_force_disabled,
2102 initial_window_title,
2103 ),
2104 })
2105 }
2106
2107 pub(crate) fn new_focus_listener(
2108 &self,
2109 value: AnyWindowFocusListener,
2110 ) -> (Subscription, impl FnOnce() + use<>) {
2111 self.focus_listeners.insert((), value)
2112 }
2113}
2114
2115#[derive(Clone, Debug, Default, PartialEq, Eq)]
2116#[expect(missing_docs)]
2117pub struct DispatchEventResult {
2118 pub propagate: bool,
2119 pub default_prevented: bool,
2120}
2121
2122#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
2126#[repr(C)]
2127pub struct ContentMask<P: Clone + Debug + Default + PartialEq> {
2128 pub bounds: Bounds<P>,
2130}
2131
2132impl ContentMask<Pixels> {
2133 pub fn scale(&self, factor: f32) -> ContentMask<ScaledPixels> {
2135 ContentMask {
2136 bounds: self.bounds.scale(factor),
2137 }
2138 }
2139
2140 pub fn intersect(&self, other: &Self) -> Self {
2142 let bounds = self.bounds.intersect(&other.bounds);
2143 ContentMask { bounds }
2144 }
2145}
2146
2147impl Window {
2148 fn mark_view_dirty(&mut self, view_id: EntityId) {
2149 for view_id in self
2152 .rendered_frame
2153 .dispatch_tree
2154 .view_path_reversed(view_id)
2155 {
2156 if !self.dirty_views.insert(view_id) {
2157 break;
2158 }
2159 }
2160 }
2161
2162 pub(crate) fn refresh_visibility(&mut self, cx: &mut App) {
2163 let visibility = self.platform_window.visibility();
2164 if self.visibility != visibility {
2165 self.visibility = visibility;
2166 #[cfg(feature = "profiler")]
2167 profiler::journal::record_window_visibility(self.handle.window_id(), visibility);
2168 self.visibility_observers
2169 .clone()
2170 .retain(&(), |callback| callback(visibility, self, cx));
2171 }
2172 #[cfg(feature = "profiler")]
2173 if self.invalidator.is_dirty() || self.needs_present.get() {
2174 profiler::journal::record_frame_pending(self.handle.window_id(), Instant::now());
2175 }
2176 }
2177
2178 pub fn visibility(&self) -> WindowVisibility {
2181 self.visibility
2182 }
2183
2184 pub fn is_visible(&self) -> bool {
2190 self.visibility.is_visible()
2191 }
2192
2193 pub fn observe_window_visibility(
2195 &self,
2196 mut callback: impl FnMut(WindowVisibility, &mut Window, &mut App) + 'static,
2197 ) -> Subscription {
2198 let (subscription, activate) = self.visibility_observers.insert(
2199 (),
2200 Box::new(move |visibility, window, cx| {
2201 callback(visibility, window, cx);
2202 true
2203 }),
2204 );
2205 activate();
2206 subscription
2207 }
2208
2209 pub fn observe_window_appearance(
2211 &self,
2212 mut callback: impl FnMut(&mut Window, &mut App) + 'static,
2213 ) -> Subscription {
2214 let (subscription, activate) = self.appearance_observers.insert(
2215 (),
2216 Box::new(move |window, cx| {
2217 callback(window, cx);
2218 true
2219 }),
2220 );
2221 activate();
2222 subscription
2223 }
2224
2225 pub fn observe_button_layout_changed(
2227 &self,
2228 mut callback: impl FnMut(&mut Window, &mut App) + 'static,
2229 ) -> Subscription {
2230 let (subscription, activate) = self.button_layout_observers.insert(
2231 (),
2232 Box::new(move |window, cx| {
2233 callback(window, cx);
2234 true
2235 }),
2236 );
2237 activate();
2238 subscription
2239 }
2240
2241 pub fn replace_root<E>(
2243 &mut self,
2244 cx: &mut App,
2245 build_view: impl FnOnce(&mut Window, &mut Context<E>) -> E,
2246 ) -> Entity<E>
2247 where
2248 E: 'static + Render,
2249 {
2250 let view = cx.new(|cx| build_view(self, cx));
2251 self.root = Some(view.clone().into());
2252 self.refresh();
2253 view
2254 }
2255
2256 pub fn root<E>(&self) -> Option<Option<Entity<E>>>
2258 where
2259 E: 'static + Render,
2260 {
2261 self.root
2262 .as_ref()
2263 .map(|view| view.clone().downcast::<E>().ok())
2264 }
2265
2266 pub fn window_handle(&self) -> AnyWindowHandle {
2268 self.handle
2269 }
2270
2271 pub fn refresh(&mut self) {
2273 if self.invalidator.not_drawing() {
2274 self.refreshing = true;
2275 self.invalidator.set_dirty(true);
2276 }
2277 }
2278
2279 pub fn remove_window(&mut self) {
2281 self.removed = true;
2282 }
2283
2284 pub fn focused(&self, cx: &App) -> Option<FocusHandle> {
2286 self.focus
2287 .and_then(|id| FocusHandle::for_id(id, &cx.focus_handles))
2288 }
2289
2290 pub fn focus_lost_restore_target(&self, cx: &App) -> Option<FocusHandle> {
2294 let (_leaf, ancestors) = self.focus_lost_path.split_last()?;
2295 ancestors.iter().rev().find_map(|id| {
2296 self.rendered_frame.dispatch_tree.focusable_node_id(*id)?;
2297 FocusHandle::for_id(*id, &cx.focus_handles)
2298 })
2299 }
2300
2301 pub fn focus(&mut self, handle: &FocusHandle, cx: &mut App) {
2303 if !self.focus_enabled || self.focus == Some(handle.id) {
2304 return;
2305 }
2306
2307 self.focus = Some(handle.id);
2308 self.focus_generation = self.focus_generation.wrapping_add(1);
2309 self.clear_pending_keystrokes(cx);
2310
2311 self.refresh();
2312 }
2313
2314 pub fn blur(&mut self, cx: &mut App) {
2316 self.clear_pending_keystrokes(cx);
2317
2318 if !self.focus_enabled {
2319 return;
2320 }
2321
2322 if self.focus.is_some() {
2323 self.focus_generation = self.focus_generation.wrapping_add(1);
2324 }
2325 self.focus = None;
2326 self.refresh();
2327 }
2328
2329 pub fn disable_focus(&mut self, cx: &mut App) {
2331 self.blur(cx);
2332 self.focus_enabled = false;
2333 }
2334
2335 pub fn focus_next(&mut self, cx: &mut App) {
2337 if !self.focus_enabled {
2338 return;
2339 }
2340
2341 if let Some(handle) = self.rendered_frame.tab_stops.next(self.focus.as_ref()) {
2342 self.focus(&handle, cx)
2343 }
2344 }
2345
2346 pub fn focus_prev(&mut self, cx: &mut App) {
2348 if !self.focus_enabled {
2349 return;
2350 }
2351
2352 if let Some(handle) = self.rendered_frame.tab_stops.prev(self.focus.as_ref()) {
2353 self.focus(&handle, cx)
2354 }
2355 }
2356
2357 pub fn text_system(&self) -> &Arc<WindowTextSystem> {
2359 &self.text_system
2360 }
2361
2362 pub fn text_style(&self) -> TextStyle {
2364 let mut style = TextStyle::default();
2365 for refinement in &self.text_style_stack {
2366 style.refine(refinement);
2367 }
2368 style
2369 }
2370
2371 pub fn is_maximized(&self) -> bool {
2375 self.platform_window.is_maximized()
2376 }
2377
2378 pub fn request_decorations(&self, decorations: WindowDecorations) {
2380 self.platform_window.request_decorations(decorations);
2381 }
2382
2383 pub fn set_exclusive_zone(&self, zone: Pixels) {
2389 self.platform_window.set_exclusive_zone(zone);
2390 }
2391
2392 #[cfg(all(target_os = "linux", feature = "wayland"))]
2397 pub fn set_exclusive_edge(&self, edge: crate::layer_shell::Anchor) {
2398 self.platform_window.set_exclusive_edge(edge);
2399 }
2400
2401 pub fn start_window_resize(&self, edge: ResizeEdge) {
2403 if self.is_resizable {
2404 self.platform_window.start_window_resize(edge);
2405 }
2406 }
2407
2408 pub fn set_input_region(&self, region: Option<&[Bounds<Pixels>]>) {
2415 self.platform_window.set_input_region(region);
2416 }
2417
2418 pub fn window_bounds(&self) -> WindowBounds {
2421 self.platform_window.window_bounds()
2422 }
2423
2424 pub fn inner_window_bounds(&self) -> WindowBounds {
2426 self.platform_window.inner_window_bounds()
2427 }
2428
2429 pub fn native_window_state(&self) -> Option<Vec<u8>> {
2432 self.platform_window.native_window_state()
2433 }
2434
2435 pub fn restore_native_window_state(&self, state: &[u8]) {
2438 self.platform_window.restore_native_window_state(state);
2439 }
2440
2441 pub fn dispatch_action(&mut self, action: Box<dyn Action>, cx: &mut App) {
2443 let focus_id = self.focused(cx).map(|handle| handle.id);
2444
2445 let window = self.handle;
2446 cx.defer(move |cx| {
2447 window
2448 .update(cx, |_, window, cx| {
2449 let node_id = window.focus_node_id_in_rendered_frame(focus_id);
2450 window.dispatch_action_on_node(node_id, action.as_ref(), cx);
2451 })
2452 .log_err();
2453 })
2454 }
2455
2456 pub(crate) fn dispatch_keystroke_observers(
2457 &mut self,
2458 keystroke: &Keystroke,
2459 action: Option<&dyn Action>,
2460 context_stack: Vec<KeyContext>,
2461 cx: &mut App,
2462 ) {
2463 cx.keystroke_observers.clone().retain(&(), move |callback| {
2464 (callback)(
2465 &KeystrokeEvent {
2466 keystroke: keystroke.clone(),
2467 action: action.map(|action| action.boxed_clone()),
2468 context_stack: context_stack.clone(),
2469 },
2470 self,
2471 cx,
2472 )
2473 });
2474 }
2475
2476 pub(crate) fn dispatch_keystroke_interceptors(
2477 &mut self,
2478 keystroke: &Keystroke,
2479 context_stack: Vec<KeyContext>,
2480 cx: &mut App,
2481 ) {
2482 cx.keystroke_interceptors
2483 .clone()
2484 .retain(&(), move |callback| {
2485 (callback)(
2486 &KeystrokeEvent {
2487 keystroke: keystroke.clone(),
2488 action: None,
2489 context_stack: context_stack.clone(),
2490 },
2491 self,
2492 cx,
2493 )
2494 });
2495 }
2496
2497 pub fn defer(&self, cx: &mut App, f: impl FnOnce(&mut Window, &mut App) + 'static) {
2500 let handle = self.handle;
2501 cx.defer(move |cx| {
2502 handle.update(cx, |_, window, cx| f(window, cx)).ok();
2503 });
2504 }
2505
2506 pub fn observe<T: 'static>(
2510 &mut self,
2511 observed: &Entity<T>,
2512 cx: &mut App,
2513 mut on_notify: impl FnMut(Entity<T>, &mut Window, &mut App) + 'static,
2514 ) -> Subscription {
2515 let entity_id = observed.entity_id();
2516 let observed = observed.downgrade();
2517 let window_handle = self.handle;
2518 cx.new_observer(
2519 entity_id,
2520 Box::new(move |cx| {
2521 window_handle
2522 .update(cx, |_, window, cx| {
2523 if let Some(handle) = observed.upgrade() {
2524 on_notify(handle, window, cx);
2525 true
2526 } else {
2527 false
2528 }
2529 })
2530 .unwrap_or(false)
2531 }),
2532 )
2533 }
2534
2535 pub fn subscribe<Emitter, Evt>(
2539 &mut self,
2540 entity: &Entity<Emitter>,
2541 cx: &mut App,
2542 mut on_event: impl FnMut(Entity<Emitter>, &Evt, &mut Window, &mut App) + 'static,
2543 ) -> Subscription
2544 where
2545 Emitter: EventEmitter<Evt>,
2546 Evt: 'static,
2547 {
2548 let entity_id = entity.entity_id();
2549 let handle = entity.downgrade();
2550 let window_handle = self.handle;
2551 cx.new_subscription(
2552 entity_id,
2553 (
2554 TypeId::of::<Evt>(),
2555 Box::new(move |event, cx| {
2556 window_handle
2557 .update(cx, |_, window, cx| {
2558 if let Some(entity) = handle.upgrade() {
2559 let event = event.downcast_ref().expect("invalid event type");
2560 on_event(entity, event, window, cx);
2561 true
2562 } else {
2563 false
2564 }
2565 })
2566 .unwrap_or(false)
2567 }),
2568 ),
2569 )
2570 }
2571
2572 pub fn observe_release<T>(
2574 &self,
2575 entity: &Entity<T>,
2576 cx: &mut App,
2577 mut on_release: impl FnOnce(&mut T, &mut Window, &mut App) + 'static,
2578 ) -> Subscription
2579 where
2580 T: 'static,
2581 {
2582 let entity_id = entity.entity_id();
2583 let window_handle = self.handle;
2584 let (subscription, activate) = cx.release_listeners.insert(
2585 entity_id,
2586 Box::new(move |entity, cx| {
2587 let entity = entity.downcast_mut().expect("invalid entity type");
2588 let _ = window_handle.update(cx, |_, window, cx| on_release(entity, window, cx));
2589 }),
2590 );
2591 activate();
2592 subscription
2593 }
2594
2595 pub fn to_async(&self, cx: &App) -> AsyncWindowContext {
2598 AsyncWindowContext::new_context(cx.to_async(), self.handle)
2599 }
2600
2601 pub fn on_next_frame(&self, callback: impl FnOnce(&mut Window, &mut App) + 'static) {
2603 RefCell::borrow_mut(&self.next_frame_callbacks).push(Box::new(callback));
2604 self.platform_window.schedule_frame();
2605 self.invalidator.wake_platform();
2608 }
2609
2610 pub fn request_animation_frame(&self) {
2623 let entity = self.current_view();
2624 self.on_next_frame(move |_, cx| cx.notify(entity));
2625 }
2626
2627 #[cfg(any(test, feature = "test-support"))]
2632 pub fn simulate_next_frame(&mut self, cx: &mut App) -> usize {
2633 let callbacks = self.next_frame_callbacks.take();
2634 let count = callbacks.len();
2635 for callback in callbacks {
2636 callback(self, cx);
2637 }
2638 count
2639 }
2640
2641 #[track_caller]
2645 pub fn spawn<AsyncFn, R>(&self, cx: &App, f: AsyncFn) -> Task<R>
2646 where
2647 R: 'static,
2648 AsyncFn: AsyncFnOnce(&mut AsyncWindowContext) -> R + 'static,
2649 {
2650 let handle = self.handle;
2651 cx.spawn(async move |app| {
2652 let mut async_window_cx = AsyncWindowContext::new_context(app.clone(), handle);
2653 f(&mut async_window_cx).await
2654 })
2655 }
2656
2657 #[track_caller]
2661 pub fn spawn_with_priority<AsyncFn, R>(
2662 &self,
2663 priority: Priority,
2664 cx: &App,
2665 f: AsyncFn,
2666 ) -> Task<R>
2667 where
2668 R: 'static,
2669 AsyncFn: AsyncFnOnce(&mut AsyncWindowContext) -> R + 'static,
2670 {
2671 let handle = self.handle;
2672 cx.spawn_with_priority(priority, async move |app| {
2673 let mut async_window_cx = AsyncWindowContext::new_context(app.clone(), handle);
2674 f(&mut async_window_cx).await
2675 })
2676 }
2677
2678 pub fn bounds_changed(&mut self, cx: &mut App) {
2684 self.scale_factor = self.platform_window.scale_factor();
2685 self.viewport_size = self.platform_window.content_size();
2686 self.display_id = self.platform_window.display().map(|display| display.id());
2687 self.mouse_position = self.platform_window.mouse_position();
2688
2689 self.refresh();
2690
2691 self.bounds_observers
2692 .clone()
2693 .retain(&(), |callback| callback(self, cx));
2694 }
2695
2696 pub fn bounds(&self) -> Bounds<Pixels> {
2698 self.platform_window.bounds()
2699 }
2700
2701 #[cfg(any(test, feature = "test-support"))]
2705 pub fn render_to_image(&self) -> anyhow::Result<image::RgbaImage> {
2706 self.platform_window
2707 .render_to_image(&self.rendered_frame.scene)
2708 }
2709
2710 #[cfg(any(test, feature = "test-support"))]
2715 pub fn painted_quads(&self) -> Vec<Quad> {
2716 self.rendered_frame.scene.quads.clone()
2717 }
2718
2719 #[cfg(any(test, feature = "test-support"))]
2721 pub fn painted_underlines(&self) -> Vec<Underline> {
2722 self.rendered_frame.scene.underlines.clone()
2723 }
2724
2725 pub fn resize(&mut self, size: Size<Pixels>) {
2727 self.platform_window.resize(size);
2728 }
2729
2730 pub fn is_fullscreen(&self) -> bool {
2732 self.platform_window.is_fullscreen()
2733 }
2734
2735 pub fn is_simple_fullscreen(&self) -> bool {
2739 self.platform_window.is_simple_fullscreen()
2740 }
2741
2742 pub(crate) fn appearance_changed(&mut self, cx: &mut App) {
2743 self.appearance = self.platform_window.appearance();
2744
2745 self.appearance_observers
2746 .clone()
2747 .retain(&(), |callback| callback(self, cx));
2748 }
2749
2750 pub(crate) fn button_layout_changed(&mut self, cx: &mut App) {
2751 self.button_layout_observers
2752 .clone()
2753 .retain(&(), |callback| callback(self, cx));
2754 }
2755
2756 pub fn appearance(&self) -> WindowAppearance {
2758 self.appearance
2759 }
2760
2761 pub fn viewport_size(&self) -> Size<Pixels> {
2763 self.viewport_size
2764 }
2765
2766 pub fn visual_viewport_bounds(&self) -> Bounds<Pixels> {
2772 self.platform_window.visual_viewport_bounds()
2773 }
2774
2775 pub fn fully_visible_bounds(&self) -> Bounds<Pixels> {
2780 let insets = self.platform_window.insets().effective();
2781 let viewport = self.viewport_size();
2782 let left = insets.left.max(Pixels::ZERO).min(viewport.width);
2783 let top = insets.top.max(Pixels::ZERO).min(viewport.height);
2784 let right = (viewport.width - insets.right.max(Pixels::ZERO)).max(left);
2785 let bottom = (viewport.height - insets.bottom.max(Pixels::ZERO)).max(top);
2786 let safe_bounds = Bounds::from_corners(point(left, top), point(right, bottom));
2787 let mut visible = safe_bounds.intersect(&self.visual_viewport_bounds());
2788 visible.size.width = visible.size.width.max(Pixels::ZERO);
2789 visible.size.height = visible.size.height.max(Pixels::ZERO);
2790 visible
2791 }
2792
2793 pub fn request_virtual_keyboard(&self) {
2798 self.platform_window.show_soft_keyboard();
2799 }
2800
2801 pub fn dismiss_virtual_keyboard(&self) {
2803 self.platform_window.hide_soft_keyboard();
2804 }
2805
2806 pub fn is_window_active(&self) -> bool {
2808 self.active.get()
2809 }
2810
2811 pub fn is_window_hovered(&self) -> bool {
2815 if cfg!(any(
2816 target_os = "windows",
2817 target_os = "linux",
2818 target_os = "freebsd"
2819 )) {
2820 self.hovered.get()
2821 } else {
2822 self.is_window_active()
2823 }
2824 }
2825
2826 pub fn zoom_window(&self) {
2828 self.platform_window.zoom();
2829 }
2830
2831 pub fn show_window_menu(&self, position: Point<Pixels>) {
2833 self.platform_window.show_window_menu(position)
2834 }
2835
2836 pub fn start_window_move(&self) {
2841 self.platform_window.start_window_move()
2842 }
2843
2844 pub fn set_client_inset(&mut self, inset: Pixels) {
2846 self.client_inset = Some(inset);
2847 self.platform_window.set_client_inset(inset);
2848 }
2849
2850 pub fn client_inset(&self) -> Option<Pixels> {
2852 self.client_inset
2853 }
2854
2855 pub fn window_decorations(&self) -> Decorations {
2857 self.platform_window.window_decorations()
2858 }
2859
2860 pub fn is_resizable(&self) -> bool {
2862 self.is_resizable
2863 }
2864
2865 pub fn is_minimizable(&self) -> bool {
2867 self.is_minimizable
2868 }
2869
2870 pub fn window_controls(&self) -> WindowControls {
2872 self.platform_window.window_controls()
2873 }
2874
2875 pub fn set_window_title(&mut self, title: &str) {
2877 self.platform_window.set_title(title);
2878 self.a11y.set_window_title(title.to_string());
2879 }
2880
2881 #[cfg(target_os = "macos")]
2883 pub fn set_traffic_light_position(&self, position: Point<Pixels>) {
2884 self.platform_window.set_traffic_light_position(position);
2885 }
2886
2887 pub fn set_app_id(&mut self, app_id: &str) {
2889 self.platform_window.set_app_id(app_id);
2890 }
2891
2892 pub fn set_background_appearance(&self, background_appearance: WindowBackgroundAppearance) {
2894 self.platform_window
2895 .set_background_appearance(background_appearance);
2896 }
2897
2898 pub fn set_window_edited(&mut self, edited: bool) {
2900 self.platform_window.set_edited(edited);
2901 }
2902
2903 pub fn set_document_path(&self, path: Option<&std::path::Path>) {
2906 self.platform_window.set_document_path(path);
2907 }
2908
2909 pub fn display(&self, cx: &App) -> Option<Rc<dyn PlatformDisplay>> {
2911 cx.platform
2912 .displays()
2913 .into_iter()
2914 .find(|display| Some(display.id()) == self.display_id)
2915 }
2916
2917 pub fn show_character_palette(&self) {
2919 self.platform_window.show_character_palette();
2920 }
2921
2922 pub fn scale_factor(&self) -> f32 {
2926 self.scale_factor
2927 }
2928
2929 #[cfg(any(test, feature = "test-support"))]
2931 pub fn set_scale_factor(&mut self, scale_factor: f32) {
2932 self.scale_factor = scale_factor;
2933 self.refresh();
2934 }
2935
2936 pub fn rem_size(&self) -> Pixels {
2939 self.rem_size_override_stack
2940 .last()
2941 .copied()
2942 .unwrap_or(self.rem_size)
2943 }
2944
2945 pub fn set_rem_size(&mut self, rem_size: impl Into<Pixels>) {
2948 self.rem_size = rem_size.into();
2949 }
2950
2951 pub fn with_global_id<R>(
2954 &mut self,
2955 element_id: ElementId,
2956 f: impl FnOnce(&GlobalElementId, &mut Self) -> R,
2957 ) -> R {
2958 self.with_id(element_id, |this| {
2959 let global_id = GlobalElementId(Arc::from(&*this.element_id_stack));
2960
2961 f(&global_id, this)
2962 })
2963 }
2964
2965 #[inline]
2967 pub fn with_id<R>(
2968 &mut self,
2969 element_id: impl Into<ElementId>,
2970 f: impl FnOnce(&mut Self) -> R,
2971 ) -> R {
2972 self.element_id_stack.push(element_id.into());
2973 let result = f(self);
2974 self.element_id_stack.pop();
2975 result
2976 }
2977
2978 #[inline]
2984 pub fn with_rem_size<F, R>(&mut self, rem_size: Option<impl Into<Pixels>>, f: F) -> R
2985 where
2986 F: FnOnce(&mut Self) -> R,
2987 {
2988 self.invalidator.debug_assert_paint_or_prepaint();
2989
2990 if let Some(rem_size) = rem_size {
2991 self.rem_size_override_stack.push(rem_size.into());
2992 let result = f(self);
2993 self.rem_size_override_stack.pop();
2994 result
2995 } else {
2996 f(self)
2997 }
2998 }
2999
3000 pub fn line_height(&self) -> Pixels {
3002 self.text_style().line_height_in_pixels(self.rem_size())
3003 }
3004
3005 #[inline]
3007 pub fn pixel_snap(&self, value: Pixels) -> Pixels {
3008 px(round_to_device_pixel(value.0, self.scale_factor()) / self.scale_factor())
3009 }
3010
3011 #[inline]
3013 pub fn pixel_snap_f64(&self, value: f64) -> f64 {
3014 let scale_factor = f64::from(self.scale_factor());
3015 round_half_toward_zero_f64(value * scale_factor) / scale_factor
3016 }
3017
3018 #[inline]
3020 pub fn pixel_snap_bounds(&self, bounds: Bounds<Pixels>) -> Bounds<Pixels> {
3021 bounds.map(|c| self.pixel_snap(c))
3022 }
3023
3024 #[inline]
3026 pub fn pixel_snap_point(&self, position: Point<Pixels>) -> Point<Pixels> {
3027 position.map(|c| self.pixel_snap(c))
3028 }
3029
3030 pub fn underline_bounds(
3032 &self,
3033 origin: Point<Pixels>,
3034 width: Pixels,
3035 style: &UnderlineStyle,
3036 ) -> Bounds<ScaledPixels> {
3037 let scale_factor = self.scale_factor();
3038 let thickness = self.snap_stroke(style.thickness);
3039 let height = if style.wavy {
3040 ScaledPixels(thickness.0 * 3.)
3041 } else {
3042 thickness
3043 };
3044 Bounds {
3045 origin: origin.map(|c| ScaledPixels(round_to_device_pixel(c.0, scale_factor))),
3046 size: size(self.snap_stroke(width), height),
3047 }
3048 }
3049
3050 pub fn paint_underline_with_exclusions(
3052 &mut self,
3053 origin: Point<Pixels>,
3054 width: Pixels,
3055 style: &UnderlineStyle,
3056 exclusions: &[Range<ScaledPixels>],
3057 ) {
3058 self.invalidator.debug_assert_paint();
3059 let underline = self.underline(origin, width, style);
3060 if exclusions.is_empty() {
3061 self.next_frame.scene.insert_primitive(underline);
3062 return;
3063 }
3064
3065 let bounds = underline.bounds.intersect(&underline.content_mask.bounds);
3066 if bounds.is_empty() {
3067 return;
3068 }
3069
3070 let mut exclusions = exclusions
3071 .iter()
3072 .filter_map(|span| {
3073 let start = span.start.max(bounds.left());
3074 let end = span.end.min(bounds.right());
3075 (start < end).then_some(start..end)
3076 })
3077 .collect::<SmallVec<[_; 4]>>();
3078 if exclusions.is_empty() {
3079 self.next_frame.scene.insert_primitive(underline);
3080 return;
3081 }
3082 exclusions.sort_unstable_by_key(|span| span.start);
3083
3084 let mut paint_span = |start, end| {
3085 self.next_frame.scene.insert_primitive(Underline {
3086 content_mask: ContentMask {
3087 bounds: Bounds::from_corners(
3088 point(start, bounds.top()),
3089 point(end, bounds.bottom()),
3090 ),
3091 },
3092 ..underline
3093 });
3094 };
3095 let mut start = bounds.left();
3096 for exclusion in exclusions {
3097 if start < exclusion.start {
3098 paint_span(start, exclusion.start);
3099 }
3100 start = start.max(exclusion.end);
3101 }
3102 if start < bounds.right() {
3103 paint_span(start, bounds.right());
3104 }
3105 }
3106
3107 fn underline(&self, origin: Point<Pixels>, width: Pixels, style: &UnderlineStyle) -> Underline {
3108 Underline {
3109 order: 0,
3110 pad: 0,
3111 bounds: self.underline_bounds(origin, width, style),
3112 content_mask: self.snapped_content_mask(),
3113 color: style
3114 .color
3115 .unwrap_or_default()
3116 .opacity(self.element_opacity()),
3117 thickness: self.snap_stroke(style.thickness),
3118 wavy: style.wavy.into(),
3119 }
3120 }
3121
3122 #[inline]
3123 fn snap_bounds(&self, bounds: Bounds<Pixels>) -> Bounds<ScaledPixels> {
3124 let scale_factor = self.scale_factor();
3125 let left = round_to_device_pixel(bounds.left().0, scale_factor);
3126 let top = round_to_device_pixel(bounds.top().0, scale_factor);
3127 let right = round_to_device_pixel(bounds.right().0, scale_factor).max(left);
3128 let bottom = round_to_device_pixel(bounds.bottom().0, scale_factor).max(top);
3129 Bounds::from_corners(
3130 point(ScaledPixels(left), ScaledPixels(top)),
3131 point(ScaledPixels(right), ScaledPixels(bottom)),
3132 )
3133 }
3134
3135 #[inline]
3137 fn snap_stroke(&self, value: Pixels) -> ScaledPixels {
3138 ScaledPixels(round_stroke_to_device_pixel(value.0, self.scale_factor()))
3139 }
3140
3141 #[inline]
3142 fn snap_border_widths(&self, edges: Edges<Pixels>) -> Edges<ScaledPixels> {
3143 edges.map(|e| self.snap_stroke(*e))
3144 }
3145
3146 #[inline]
3148 fn cover_bounds(&self, bounds: Bounds<Pixels>) -> Bounds<ScaledPixels> {
3149 let scale_factor = self.scale_factor();
3150 let left = floor_to_device_pixel(bounds.left().0, scale_factor);
3151 let top = floor_to_device_pixel(bounds.top().0, scale_factor);
3152 let right = ceil_to_device_pixel(bounds.right().0, scale_factor).max(left);
3153 let bottom = ceil_to_device_pixel(bounds.bottom().0, scale_factor).max(top);
3154 Bounds::from_corners(
3155 point(ScaledPixels(left), ScaledPixels(top)),
3156 point(ScaledPixels(right), ScaledPixels(bottom)),
3157 )
3158 }
3159
3160 #[inline]
3161 fn snapped_content_mask(&self) -> ContentMask<ScaledPixels> {
3162 ContentMask {
3163 bounds: self.cover_bounds(self.content_mask().bounds),
3164 }
3165 }
3166
3167 pub fn prevent_default(&mut self) {
3170 self.default_prevented = true;
3171 }
3172
3173 pub fn default_prevented(&self) -> bool {
3175 self.default_prevented
3176 }
3177
3178 pub fn is_action_available(&self, action: &dyn Action, cx: &App) -> bool {
3180 let node_id =
3181 self.focus_node_id_in_rendered_frame(self.focused(cx).map(|handle| handle.id));
3182 self.rendered_frame
3183 .dispatch_tree
3184 .is_action_available(action, node_id)
3185 }
3186
3187 pub fn is_action_available_in(&self, action: &dyn Action, focus_handle: &FocusHandle) -> bool {
3189 let node_id = self.focus_node_id_in_rendered_frame(Some(focus_handle.id));
3190 self.rendered_frame
3191 .dispatch_tree
3192 .is_action_available(action, node_id)
3193 }
3194
3195 pub fn mouse_position(&self) -> Point<Pixels> {
3197 self.mouse_position
3198 }
3199
3200 pub fn capture_pointer(&mut self, hitbox_id: HitboxId) {
3207 self.captured_hitbox = Some(hitbox_id);
3208 }
3209
3210 pub fn release_pointer(&mut self) {
3212 self.captured_hitbox = None;
3213 }
3214
3215 pub fn captured_hitbox(&self) -> Option<HitboxId> {
3217 self.captured_hitbox
3218 }
3219
3220 pub fn capture_long_press<T: 'static>(&mut self, entity: &Entity<T>) {
3226 self.long_press_capture = Some(entity.entity_id());
3227 }
3228
3229 pub fn has_long_press_capture<T: 'static>(&self, entity: &Entity<T>) -> bool {
3231 self.long_press_capture == Some(entity.entity_id())
3232 }
3233
3234 pub fn modifiers(&self) -> Modifiers {
3236 self.modifiers
3237 }
3238
3239 pub fn last_input_was_keyboard(&self) -> bool {
3242 self.last_input_modality == InputModality::Keyboard
3243 }
3244
3245 pub(crate) fn last_input_was_touch(&self) -> bool {
3246 self.last_input_modality == InputModality::Touch
3247 }
3248
3249 pub fn capslock(&self) -> Capslock {
3251 self.capslock
3252 }
3253
3254 #[profiling::function]
3257 pub fn draw(&mut self, cx: &mut App) -> ArenaClearNeeded {
3258 #[cfg(feature = "profiler")]
3261 let frame_dirty = self.invalidator.take_frame_dirty();
3262 #[cfg(feature = "profiler")]
3263 self.window_profiler.begin_draw();
3264
3265 let arena_scope = ElementArenaScope::enter(&cx.element_arena);
3268
3269 if self.platform_window.prepare_frame() {
3270 self.refresh();
3271 }
3272 self.invalidate_entities();
3273 cx.entities.clear_accessed();
3274 debug_assert!(self.rendered_entity_stack.is_empty());
3275 self.invalidator.set_dirty(false);
3276 self.requested_autoscroll = None;
3277
3278 if let Some(input_handler) = self.platform_window.take_input_handler() {
3283 if let Some(slot) = self
3284 .rendered_frame
3285 .input_handlers
3286 .iter_mut()
3287 .rev()
3288 .find(|h| h.is_none())
3289 {
3290 *slot = Some(input_handler);
3291 } else {
3292 self.rendered_frame.input_handlers.push(Some(input_handler));
3293 }
3294 }
3295 if !cx.mode.skip_drawing() {
3296 self.draw_roots(cx);
3297 #[cfg(feature = "profiler")]
3298 {
3299 let viewport_size = self.viewport_size;
3300 let scale_factor = self.scale_factor();
3301 self.debug_frame_overlay.paint(
3302 &mut self.next_frame.scene,
3303 viewport_size,
3304 scale_factor,
3305 );
3306 }
3307 }
3308 self.dirty_views.clear();
3309 self.next_frame.window_active = self.active.get();
3310
3311 let focused_text_input_active = if let Some(mut input_handler) = self
3317 .next_frame
3318 .input_handlers
3319 .iter_mut()
3320 .rev()
3321 .find_map(|h| h.take())
3322 {
3323 let accepts_text_input = input_handler.accepts_text_input(self, cx);
3324 self.platform_window.set_input_handler(input_handler);
3325 accepts_text_input
3326 } else {
3327 false
3328 };
3329 self.apply_text_input_configuration(cx);
3330 if focused_text_input_active != self.focused_text_input_active {
3331 self.focused_text_input_active = focused_text_input_active;
3332 self.platform_window
3333 .text_input_state_changed(if focused_text_input_active {
3334 TextInputStateChange::FocusGained
3335 } else {
3336 TextInputStateChange::FocusLost
3337 });
3338 }
3339
3340 self.layout_engine.as_mut().unwrap().clear();
3341 self.text_system().finish_frame();
3342 self.next_frame.finish(&mut self.rendered_frame);
3343
3344 self.invalidator.set_phase(DrawPhase::Focus);
3345 let previous_focus_path = self.rendered_frame.focus_path();
3346 let previous_window_active = self.rendered_frame.window_active;
3347 mem::swap(&mut self.rendered_frame, &mut self.next_frame);
3348 self.next_frame.clear();
3349 let current_focus_path = self.rendered_frame.focus_path();
3350 let current_window_active = self.rendered_frame.window_active;
3351 let mut focus_before_listeners = self.focus;
3352
3353 if previous_focus_path != current_focus_path
3354 || previous_window_active != current_window_active
3355 {
3356 if !previous_focus_path.is_empty() && current_focus_path.is_empty() {
3357 self.focus_lost_path = previous_focus_path.clone();
3358 self.focus_lost_listeners
3359 .clone()
3360 .retain(&(), |listener| listener(self, cx));
3361 self.focus_lost_path = SmallVec::new();
3362 focus_before_listeners = self.focus;
3367 }
3368
3369 let event = WindowFocusEvent {
3370 previous_focus_path: if previous_window_active {
3371 previous_focus_path
3372 } else {
3373 Default::default()
3374 },
3375 current_focus_path: if current_window_active {
3376 current_focus_path
3377 } else {
3378 Default::default()
3379 },
3380 };
3381 self.focus_listeners
3382 .clone()
3383 .retain(&(), |listener| listener(&event, self, cx));
3384 }
3385
3386 debug_assert!(self.rendered_entity_stack.is_empty());
3387 self.record_entities_accessed(cx);
3388 self.reset_cursor_style(cx);
3389 self.refreshing = false;
3390 self.invalidator.set_phase(DrawPhase::None);
3391 if self.focus != focus_before_listeners {
3396 self.refresh();
3397 }
3398 self.needs_present.set(true);
3399
3400 #[cfg(feature = "profiler")]
3401 {
3402 let draw_duration = self
3403 .window_profiler
3404 .end_draw(frame_dirty.dirty_at, frame_dirty.invalidations);
3405 self.debug_frame_overlay.record_frame(draw_duration);
3406 }
3407
3408 arena_scope.exit(&cx.element_arena)
3411 }
3412
3413 fn record_entities_accessed(&mut self, cx: &mut App) {
3414 let mut entities_ref = cx.entities.accessed_entities.get_mut();
3415 let mut entities = mem::take(entities_ref.deref_mut());
3416 let handle = self.handle;
3417 cx.record_entities_accessed(
3418 handle,
3419 self.invalidator.clone(),
3421 &entities,
3422 );
3423 let mut entities_ref = cx.entities.accessed_entities.get_mut();
3424 mem::swap(&mut entities, entities_ref.deref_mut());
3425 }
3426
3427 fn invalidate_entities(&mut self) {
3428 let mut views = self.invalidator.take_views();
3429 for entity in views.drain() {
3430 self.mark_view_dirty(entity);
3431 }
3432 self.invalidator.replace_views(views);
3433 }
3434
3435 #[profiling::function]
3436 fn present(&mut self) {
3437 #[cfg(feature = "profiler")]
3438 let _foreground_turn = profiler::journal::foreground_turn();
3439 #[cfg(feature = "profiler")]
3440 let present_start = Instant::now();
3441 self.platform_window.draw(&self.rendered_frame.scene);
3442 #[cfg(feature = "profiler")]
3443 self.window_profiler.record_present(
3444 present_start,
3445 Instant::now(),
3446 self.active.get(),
3447 !self.next_frame_callbacks.borrow().is_empty(),
3448 );
3449 self.needs_present.set(false);
3450 profiling::finish_frame!();
3451 }
3452
3453 #[cfg(all(test, feature = "profiler"))]
3455 pub fn present_if_needed(&mut self) {
3456 if self.needs_present.get() {
3457 self.present();
3458 }
3459 }
3460
3461 #[cfg(feature = "profiler")]
3463 pub fn input_latency_snapshot(&self) -> profiler::InputLatencySnapshot {
3464 self.window_profiler.input_latency_snapshot()
3465 }
3466
3467 #[cfg(feature = "profiler")]
3469 pub fn frame_duration_snapshot(&self) -> profiler::FrameDurationSnapshot {
3470 self.window_profiler.frame_duration_snapshot()
3471 }
3472
3473 #[cfg(feature = "profiler")]
3475 pub fn debug_frame_overlay_mode(&self) -> DebugFrameOverlayMode {
3476 self.debug_frame_overlay.mode()
3477 }
3478
3479 #[cfg(feature = "profiler")]
3481 pub fn set_debug_frame_overlay_mode(&mut self, mode: DebugFrameOverlayMode) {
3482 self.debug_frame_overlay.set_mode(mode);
3483 self.refresh();
3484 }
3485
3486 #[cfg(feature = "profiler")]
3489 pub fn cycle_debug_frame_overlay_mode(&mut self) {
3490 self.set_debug_frame_overlay_mode(self.debug_frame_overlay.mode().next());
3491 }
3492
3493 #[cfg(feature = "profiler")]
3496 pub fn reset_debug_frame_overlay_stats(&mut self) {
3497 self.debug_frame_overlay.reset_stats();
3498 self.refresh();
3499 }
3500
3501 fn draw_roots(&mut self, cx: &mut App) {
3502 self.invalidator.set_phase(DrawPhase::Prepaint);
3503 self.tooltip_bounds.take();
3504
3505 self.a11y.sync_active_flag();
3506 if self.a11y.is_active() {
3507 self.a11y.begin_frame();
3508 }
3509
3510 let _inspector_width: Pixels = rems(30.0).to_pixels(self.rem_size());
3511 let root_size = {
3512 #[cfg(any(feature = "inspector", debug_assertions))]
3513 {
3514 if self.inspector.is_some() {
3515 let mut size = self.viewport_size;
3516 size.width = (size.width - _inspector_width).max(px(0.0));
3517 size
3518 } else {
3519 self.viewport_size
3520 }
3521 }
3522 #[cfg(not(any(feature = "inspector", debug_assertions)))]
3523 {
3524 self.viewport_size
3525 }
3526 };
3527
3528 let scale_factor = self.scale_factor();
3532 let mut root_element = self.root.as_ref().unwrap().clone().into_any_element();
3533 let root_layout_id = root_element.request_layout(self, cx);
3534 self.layout_engine
3535 .as_mut()
3536 .unwrap()
3537 .stretch_auto_size_to_fill(root_layout_id, root_size, scale_factor);
3538 root_element.prepaint_as_root(Point::default(), root_size.into(), self, cx);
3539
3540 #[cfg(any(feature = "inspector", debug_assertions))]
3541 let inspector_element = self.prepaint_inspector(_inspector_width, cx);
3542
3543 self.prepaint_deferred_draws(cx);
3544
3545 let mut prompt_element = None;
3546 let mut active_drag_element = None;
3547 let mut tooltip_element = None;
3548 if let Some(prompt) = self.prompt.take() {
3549 let mut element = prompt.view.any_view().into_any_element();
3550 let prompt_layout_id = element.request_layout(self, cx);
3551 self.layout_engine
3552 .as_mut()
3553 .unwrap()
3554 .stretch_auto_size_to_fill(prompt_layout_id, root_size, scale_factor);
3555 element.prepaint_as_root(Point::default(), root_size.into(), self, cx);
3556 prompt_element = Some(element);
3557 self.prompt = Some(prompt);
3558 } else if let Some(active_drag) = cx.active_drag.take() {
3559 let mut element = active_drag.view.clone().into_any_element();
3560 let offset = self.mouse_position() - active_drag.cursor_offset;
3561 element.prepaint_as_root(offset, AvailableSpace::min_size(), self, cx);
3562 active_drag_element = Some(element);
3563 cx.active_drag = Some(active_drag);
3564 } else {
3565 tooltip_element = self.prepaint_tooltip(cx);
3566 }
3567
3568 self.mouse_hit_test = self.next_frame.hit_test(self.mouse_position);
3569
3570 self.invalidator.set_phase(DrawPhase::Paint);
3572 root_element.paint(self, cx);
3573
3574 #[cfg(any(feature = "inspector", debug_assertions))]
3575 self.paint_inspector(inspector_element, cx);
3576
3577 self.paint_deferred_draws(cx);
3578
3579 if let Some(mut prompt_element) = prompt_element {
3580 prompt_element.paint(self, cx);
3581 } else if let Some(mut drag_element) = active_drag_element {
3582 drag_element.paint(self, cx);
3583 } else if let Some(mut tooltip_element) = tooltip_element {
3584 tooltip_element.paint(self, cx);
3585 }
3586
3587 #[cfg(any(feature = "inspector", debug_assertions))]
3588 self.paint_inspector_hitbox(cx);
3589
3590 let a11y_active_start_of_frame = self.a11y.is_active();
3592 self.a11y.sync_active_flag();
3593 let a11y_active_end_of_frame = self.a11y.is_active();
3594
3595 let should_send_a11y_update = a11y_active_start_of_frame && a11y_active_end_of_frame;
3596
3597 if a11y_active_start_of_frame {
3598 let frame_info = crate::window::a11y::debug::FrameDebugInfo {
3601 viewport_size: self.viewport_size,
3602 scale_factor: self.scale_factor,
3603 tab_stop_count: self.next_frame.tab_stops.tab_stop_count(),
3604 };
3605 let tree_update = self.a11y.end_frame(frame_info);
3607
3608 if should_send_a11y_update {
3609 log::debug!(
3610 "Sending a11y tree update: {} nodes",
3611 tree_update.nodes.len()
3612 );
3613 self.platform_window.a11y_tree_update(tree_update);
3614 }
3615 }
3616 }
3617
3618 fn prepaint_tooltip(&mut self, cx: &mut App) -> Option<AnyElement> {
3619 for tooltip_request_index in (0..self.next_frame.tooltip_requests.len()).rev() {
3621 let Some(Some(tooltip_request)) = self
3622 .next_frame
3623 .tooltip_requests
3624 .get(tooltip_request_index)
3625 .cloned()
3626 else {
3627 log::error!("Unexpectedly absent TooltipRequest");
3628 continue;
3629 };
3630 let mut element = tooltip_request.tooltip.view.clone().into_any_element();
3631 let mouse_position = tooltip_request.tooltip.mouse_position;
3632 let tooltip_size = element.layout_as_root(AvailableSpace::min_size(), self, cx);
3633
3634 let mut tooltip_bounds =
3635 Bounds::new(mouse_position + point(px(1.), px(1.)), tooltip_size);
3636 let window_bounds = Bounds {
3637 origin: Point::default(),
3638 size: self.viewport_size(),
3639 };
3640
3641 if tooltip_bounds.right() > window_bounds.right() {
3642 let new_x = mouse_position.x - tooltip_bounds.size.width - px(1.);
3643 if new_x >= Pixels::ZERO {
3644 tooltip_bounds.origin.x = new_x;
3645 } else {
3646 tooltip_bounds.origin.x = cmp::max(
3647 Pixels::ZERO,
3648 tooltip_bounds.origin.x - tooltip_bounds.right() - window_bounds.right(),
3649 );
3650 }
3651 }
3652
3653 if tooltip_bounds.bottom() > window_bounds.bottom() {
3654 let new_y = mouse_position.y - tooltip_bounds.size.height - px(1.);
3655 if new_y >= Pixels::ZERO {
3656 tooltip_bounds.origin.y = new_y;
3657 } else {
3658 tooltip_bounds.origin.y = cmp::max(
3659 Pixels::ZERO,
3660 tooltip_bounds.origin.y - tooltip_bounds.bottom() - window_bounds.bottom(),
3661 );
3662 }
3663 }
3664
3665 let is_visible =
3669 (tooltip_request.tooltip.check_visible_and_update)(tooltip_bounds, self, cx);
3670 if !is_visible {
3671 continue;
3672 }
3673
3674 self.with_absolute_element_offset(tooltip_bounds.origin, |window| {
3675 element.prepaint(window, cx)
3676 });
3677
3678 self.tooltip_bounds = Some(TooltipBounds {
3679 id: tooltip_request.id,
3680 bounds: tooltip_bounds,
3681 });
3682 return Some(element);
3683 }
3684 None
3685 }
3686
3687 fn prepaint_deferred_draws(&mut self, cx: &mut App) {
3688 assert_eq!(self.element_id_stack.len(), 0);
3689
3690 let mut round_start = 0;
3701 let mut depth = 0;
3702 loop {
3703 let round_end = self.next_frame.deferred_draws.len();
3704 if round_start == round_end {
3705 break;
3706 }
3707 assert!(depth < 10, "Exceeded maximum (10) deferred depth");
3709 depth += 1;
3710
3711 let mut traversal_order = (round_start..round_end).collect::<SmallVec<[usize; 8]>>();
3713 traversal_order.sort_by_key(|ix| self.next_frame.deferred_draws[*ix].priority);
3714
3715 for deferred_draw_ix in traversal_order {
3716 let (element, parent_node, current_view, rem_size, absolute_offset, prepaint_range) = {
3717 let deferred_draw = &mut self.next_frame.deferred_draws[deferred_draw_ix];
3718 self.element_id_stack
3719 .clone_from(&deferred_draw.element_id_stack);
3720 self.text_style_stack
3721 .clone_from(&deferred_draw.text_style_stack);
3722 (
3723 deferred_draw.element.take(),
3724 deferred_draw.parent_node,
3725 deferred_draw.current_view,
3726 deferred_draw.rem_size,
3727 deferred_draw.absolute_offset,
3728 deferred_draw.prepaint_range.clone(),
3729 )
3730 };
3731 self.next_frame.dispatch_tree.set_active_node(parent_node);
3732
3733 let prepaint_start = self.prepaint_index();
3734 if let Some(mut element) = element {
3735 self.with_rendered_view(current_view, |window| {
3736 window.with_rem_size(Some(rem_size), |window| {
3737 window.with_absolute_element_offset(absolute_offset, |window| {
3738 element.prepaint(window, cx);
3739 });
3740 });
3741 });
3742 self.next_frame.deferred_draws[deferred_draw_ix].element = Some(element);
3743 } else {
3744 self.reuse_prepaint(prepaint_range);
3745 }
3746 let prepaint_end = self.prepaint_index();
3747 self.next_frame.deferred_draws[deferred_draw_ix].prepaint_range =
3748 prepaint_start..prepaint_end;
3749 }
3750
3751 self.element_id_stack.clear();
3752 self.text_style_stack.clear();
3753 round_start = round_end;
3754 }
3755 }
3756
3757 fn paint_deferred_draws(&mut self, cx: &mut App) {
3758 assert_eq!(self.element_id_stack.len(), 0);
3759
3760 if self.next_frame.deferred_draws.len() == 0 {
3763 return;
3764 }
3765
3766 let traversal_order = self.deferred_draw_traversal_order();
3767 let mut deferred_draws = mem::take(&mut self.next_frame.deferred_draws);
3768 for deferred_draw_ix in traversal_order {
3769 let mut deferred_draw = &mut deferred_draws[deferred_draw_ix];
3770 self.element_id_stack
3771 .clone_from(&deferred_draw.element_id_stack);
3772 self.next_frame
3773 .dispatch_tree
3774 .set_active_node(deferred_draw.parent_node);
3775
3776 let paint_start = self.paint_index();
3777 let content_mask = deferred_draw.content_mask;
3778 if let Some(element) = deferred_draw.element.as_mut() {
3779 self.with_rendered_view(deferred_draw.current_view, |window| {
3780 window.with_content_mask(content_mask, |window| {
3781 window.with_rem_size(Some(deferred_draw.rem_size), |window| {
3782 element.paint(window, cx);
3783 });
3784 })
3785 })
3786 } else {
3787 self.reuse_paint(deferred_draw.paint_range.clone());
3788 }
3789 let paint_end = self.paint_index();
3790 deferred_draw.paint_range = paint_start..paint_end;
3791 }
3792 self.next_frame.deferred_draws = deferred_draws;
3793 self.element_id_stack.clear();
3794 }
3795
3796 fn deferred_draw_traversal_order(&mut self) -> SmallVec<[usize; 8]> {
3797 let deferred_count = self.next_frame.deferred_draws.len();
3798 let mut sorted_indices = (0..deferred_count).collect::<SmallVec<[_; 8]>>();
3799 sorted_indices.sort_by_key(|ix| self.next_frame.deferred_draws[*ix].priority);
3800 sorted_indices
3801 }
3802
3803 pub(crate) fn prepaint_index(&self) -> PrepaintStateIndex {
3804 PrepaintStateIndex {
3805 hitboxes_index: self.next_frame.hitboxes.len(),
3806 tooltips_index: self.next_frame.tooltip_requests.len(),
3807 deferred_draws_index: self.next_frame.deferred_draws.len(),
3808 dispatch_tree_index: self.next_frame.dispatch_tree.len(),
3809 accessed_element_states_index: self.next_frame.accessed_element_states.len(),
3810 line_layout_index: self.text_system.layout_index(),
3811 }
3812 }
3813
3814 pub(crate) fn reuse_prepaint(&mut self, range: Range<PrepaintStateIndex>) {
3815 self.next_frame.hitboxes.extend(
3816 self.rendered_frame.hitboxes[range.start.hitboxes_index..range.end.hitboxes_index]
3817 .iter()
3818 .cloned(),
3819 );
3820 self.next_frame.tooltip_requests.extend(
3821 self.rendered_frame.tooltip_requests
3822 [range.start.tooltips_index..range.end.tooltips_index]
3823 .iter_mut()
3824 .map(|request| request.take()),
3825 );
3826 self.next_frame.accessed_element_states.extend(
3827 self.rendered_frame.accessed_element_states[range.start.accessed_element_states_index
3828 ..range.end.accessed_element_states_index]
3829 .iter()
3830 .map(|(id, type_id)| (id.clone(), *type_id)),
3831 );
3832 self.text_system
3833 .reuse_layouts(range.start.line_layout_index..range.end.line_layout_index);
3834
3835 let reused_subtree = self.next_frame.dispatch_tree.reuse_subtree(
3836 range.start.dispatch_tree_index..range.end.dispatch_tree_index,
3837 &mut self.rendered_frame.dispatch_tree,
3838 self.focus,
3839 );
3840
3841 if reused_subtree.contains_focus() {
3842 self.next_frame.focus = self.focus;
3843 }
3844
3845 self.next_frame.deferred_draws.extend(
3846 self.rendered_frame.deferred_draws
3847 [range.start.deferred_draws_index..range.end.deferred_draws_index]
3848 .iter()
3849 .map(|deferred_draw| DeferredDraw {
3850 current_view: deferred_draw.current_view,
3851 parent_node: reused_subtree.refresh_node_id(deferred_draw.parent_node),
3852 element_id_stack: deferred_draw.element_id_stack.clone(),
3853 text_style_stack: deferred_draw.text_style_stack.clone(),
3854 content_mask: deferred_draw.content_mask,
3855 rem_size: deferred_draw.rem_size,
3856 priority: deferred_draw.priority,
3857 element: None,
3858 absolute_offset: deferred_draw.absolute_offset,
3859 prepaint_range: deferred_draw.prepaint_range.clone(),
3860 paint_range: deferred_draw.paint_range.clone(),
3861 }),
3862 );
3863 }
3864
3865 pub(crate) fn paint_index(&self) -> PaintIndex {
3866 PaintIndex {
3867 scene_index: self.next_frame.scene.len(),
3868 #[cfg(any(test, feature = "test-support"))]
3869 debug_bounds_index: self.next_frame.debug_bounds_records.len(),
3870 mouse_listeners_index: self.next_frame.mouse_listeners.len(),
3871 input_handlers_index: self.next_frame.input_handlers.len(),
3872 cursor_styles_index: self.next_frame.cursor_styles.len(),
3873 accessed_element_states_index: self.next_frame.accessed_element_states.len(),
3874 tab_handle_index: self.next_frame.tab_stops.paint_index(),
3875 line_layout_index: self.text_system.layout_index(),
3876 }
3877 }
3878
3879 pub(crate) fn reuse_paint(&mut self, range: Range<PaintIndex>) {
3880 #[cfg(any(test, feature = "test-support"))]
3882 for (selector, bounds) in &self.rendered_frame.debug_bounds_records
3883 [range.start.debug_bounds_index..range.end.debug_bounds_index]
3884 {
3885 self.next_frame
3886 .record_debug_bounds(selector.clone(), *bounds);
3887 }
3888 self.next_frame.cursor_styles.extend(
3889 self.rendered_frame.cursor_styles
3890 [range.start.cursor_styles_index..range.end.cursor_styles_index]
3891 .iter()
3892 .cloned(),
3893 );
3894 self.next_frame.input_handlers.extend(
3895 self.rendered_frame.input_handlers
3896 [range.start.input_handlers_index..range.end.input_handlers_index]
3897 .iter_mut()
3898 .map(|handler| handler.take()),
3899 );
3900 self.next_frame.mouse_listeners.extend(
3901 self.rendered_frame.mouse_listeners
3902 [range.start.mouse_listeners_index..range.end.mouse_listeners_index]
3903 .iter_mut()
3904 .map(|listener| listener.take()),
3905 );
3906 self.next_frame.accessed_element_states.extend(
3907 self.rendered_frame.accessed_element_states[range.start.accessed_element_states_index
3908 ..range.end.accessed_element_states_index]
3909 .iter()
3910 .map(|(id, type_id)| (id.clone(), *type_id)),
3911 );
3912 self.next_frame.tab_stops.replay(
3913 &self.rendered_frame.tab_stops.insertion_history
3914 [range.start.tab_handle_index..range.end.tab_handle_index],
3915 );
3916
3917 self.text_system
3918 .reuse_layouts(range.start.line_layout_index..range.end.line_layout_index);
3919 self.next_frame.scene.replay(
3920 range.start.scene_index..range.end.scene_index,
3921 &self.rendered_frame.scene,
3922 );
3923 }
3924
3925 pub fn with_text_style<F, R>(&mut self, style: Option<TextStyleRefinement>, f: F) -> R
3929 where
3930 F: FnOnce(&mut Self) -> R,
3931 {
3932 self.invalidator.debug_assert_paint_or_prepaint();
3933 if let Some(style) = style {
3934 self.text_style_stack.push(style);
3935 let result = f(self);
3936 self.text_style_stack.pop();
3937 result
3938 } else {
3939 f(self)
3940 }
3941 }
3942
3943 pub fn set_cursor_style(&mut self, style: CursorStyle, hitbox: &Hitbox) {
3946 self.invalidator.debug_assert_paint();
3947 self.next_frame.cursor_styles.push(CursorStyleRequest {
3948 hitbox_id: Some(hitbox.id),
3949 style,
3950 });
3951 }
3952
3953 pub fn set_window_cursor_style(&mut self, style: CursorStyle) {
3958 self.invalidator.debug_assert_paint();
3959 self.next_frame.cursor_styles.push(CursorStyleRequest {
3960 hitbox_id: None,
3961 style,
3962 })
3963 }
3964
3965 pub fn set_tooltip(&mut self, tooltip: AnyTooltip) -> TooltipId {
3968 self.invalidator.debug_assert_prepaint();
3969 let id = TooltipId(post_inc(&mut self.next_tooltip_id.0));
3970 self.next_frame
3971 .tooltip_requests
3972 .push(Some(TooltipRequest { id, tooltip }));
3973 id
3974 }
3975
3976 #[inline]
3981 pub fn with_content_mask<R>(
3982 &mut self,
3983 mask: Option<ContentMask<Pixels>>,
3984 f: impl FnOnce(&mut Self) -> R,
3985 ) -> R {
3986 self.invalidator.debug_assert_paint_or_prepaint();
3987 if let Some(mask) = mask {
3988 let mask = mask.intersect(&self.content_mask());
3989 self.content_mask_stack.push(mask);
3990 let result = f(self);
3991 self.content_mask_stack.pop();
3992 result
3993 } else {
3994 f(self)
3995 }
3996 }
3997
3998 pub fn with_element_offset<R>(
4001 &mut self,
4002 offset: Point<Pixels>,
4003 f: impl FnOnce(&mut Self) -> R,
4004 ) -> R {
4005 self.invalidator.debug_assert_prepaint();
4006
4007 if offset.is_zero() {
4008 return f(self);
4009 };
4010
4011 let abs_offset = self.element_offset() + offset;
4012 self.with_absolute_element_offset(abs_offset, f)
4013 }
4014
4015 pub fn with_absolute_element_offset<R>(
4019 &mut self,
4020 offset: Point<Pixels>,
4021 f: impl FnOnce(&mut Self) -> R,
4022 ) -> R {
4023 self.invalidator.debug_assert_prepaint();
4024 self.element_offset_stack.push(offset);
4025 let result = f(self);
4026 self.element_offset_stack.pop();
4027 result
4028 }
4029
4030 pub(crate) fn with_element_opacity<R>(
4031 &mut self,
4032 opacity: Option<f32>,
4033 f: impl FnOnce(&mut Self) -> R,
4034 ) -> R {
4035 self.invalidator.debug_assert_paint_or_prepaint();
4036
4037 let Some(opacity) = opacity else {
4038 return f(self);
4039 };
4040
4041 let previous_opacity = self.element_opacity;
4042 self.element_opacity = previous_opacity * opacity;
4043 let result = f(self);
4044 self.element_opacity = previous_opacity;
4045 result
4046 }
4047
4048 pub fn transact<T, U>(&mut self, f: impl FnOnce(&mut Self) -> Result<T, U>) -> Result<T, U> {
4054 self.invalidator.debug_assert_prepaint();
4055 let index = self.prepaint_index();
4056 let result = f(self);
4057 if result.is_err() {
4058 self.next_frame.hitboxes.truncate(index.hitboxes_index);
4059 self.next_frame
4060 .tooltip_requests
4061 .truncate(index.tooltips_index);
4062 self.next_frame
4063 .deferred_draws
4064 .truncate(index.deferred_draws_index);
4065 self.next_frame
4066 .dispatch_tree
4067 .truncate(index.dispatch_tree_index);
4068 self.next_frame
4069 .accessed_element_states
4070 .truncate(index.accessed_element_states_index);
4071 self.text_system.truncate_layouts(index.line_layout_index);
4072 }
4073 result
4074 }
4075
4076 pub fn request_autoscroll(&mut self, bounds: Bounds<Pixels>) {
4082 self.invalidator.debug_assert_prepaint();
4083 self.requested_autoscroll = Some(bounds);
4084 }
4085
4086 pub fn take_autoscroll(&mut self) -> Option<Bounds<Pixels>> {
4089 self.invalidator.debug_assert_prepaint();
4090 self.requested_autoscroll.take()
4091 }
4092
4093 pub fn use_asset<A: Asset>(&mut self, source: &A::Source, cx: &mut App) -> Option<A::Output> {
4099 cx.asset_entry::<A>(source).use_by(self.current_view())
4100 }
4101
4102 pub fn get_asset<A: Asset>(&mut self, source: &A::Source, cx: &mut App) -> Option<A::Output> {
4108 cx.fetch_asset::<A>(source)
4109 }
4110 pub fn element_offset(&self) -> Point<Pixels> {
4113 self.invalidator.debug_assert_prepaint();
4114 self.element_offset_stack
4115 .last()
4116 .copied()
4117 .unwrap_or_default()
4118 }
4119
4120 #[inline]
4123 pub(crate) fn element_opacity(&self) -> f32 {
4124 self.invalidator.debug_assert_paint_or_prepaint();
4125 self.element_opacity
4126 }
4127
4128 pub fn content_mask(&self) -> ContentMask<Pixels> {
4130 self.invalidator.debug_assert_paint_or_prepaint();
4131 self.content_mask_stack
4132 .last()
4133 .cloned()
4134 .unwrap_or_else(|| ContentMask {
4135 bounds: Bounds {
4136 origin: Point::default(),
4137 size: self.viewport_size,
4138 },
4139 })
4140 }
4141
4142 pub fn with_element_namespace<R>(
4145 &mut self,
4146 element_id: impl Into<ElementId>,
4147 f: impl FnOnce(&mut Self) -> R,
4148 ) -> R {
4149 self.element_id_stack.push(element_id.into());
4150 let result = f(self);
4151 self.element_id_stack.pop();
4152 result
4153 }
4154
4155 pub fn use_keyed_state<S: 'static>(
4157 &mut self,
4158 key: impl Into<ElementId>,
4159 cx: &mut App,
4160 init: impl FnOnce(&mut Self, &mut Context<S>) -> S,
4161 ) -> Entity<S> {
4162 let current_view = self.current_view();
4163 self.with_global_id(key.into(), |global_id, window| {
4164 window.with_element_state(global_id, |state: Option<Entity<S>>, window| {
4165 if let Some(state) = state {
4166 (state.clone(), state)
4167 } else {
4168 let new_state = cx.new(|cx| init(window, cx));
4169 Self::observe_keyed_state(&new_state, current_view, cx);
4170 (new_state.clone(), new_state)
4171 }
4172 })
4173 })
4174 }
4175
4176 #[track_caller]
4182 pub fn use_state<S: 'static>(
4183 &mut self,
4184 cx: &mut App,
4185 init: impl FnOnce(&mut Self, &mut Context<S>) -> S,
4186 ) -> Entity<S> {
4187 self.use_keyed_state(
4188 ElementId::CodeLocation(*core::panic::Location::caller()),
4189 cx,
4190 init,
4191 )
4192 }
4193
4194 #[inline(always)]
4199 pub fn with_element_state<S, R>(
4200 &mut self,
4201 global_id: &GlobalElementId,
4202 f: impl FnOnce(Option<S>, &mut Self) -> (R, S),
4203 ) -> R
4204 where
4205 S: 'static,
4206 {
4207 self.invalidator.debug_assert_paint_or_prepaint();
4208
4209 let (key, state) = self.take_element_state(global_id, TypeId::of::<S>());
4210
4211 if let Some(any) = state {
4212 let ElementStateBox {
4213 inner,
4214 #[cfg(debug_assertions)]
4215 type_name,
4216 } = any;
4217 let mut state_box = inner
4219 .downcast::<Option<S>>()
4220 .map_err(|_| {
4221 #[cfg(debug_assertions)]
4222 {
4223 anyhow::anyhow!(
4224 "invalid element state type for id, requested {:?}, actual: {:?}",
4225 std::any::type_name::<S>(),
4226 type_name
4227 )
4228 }
4229
4230 #[cfg(not(debug_assertions))]
4231 {
4232 anyhow::anyhow!(
4233 "invalid element state type for id, requested {:?}",
4234 std::any::type_name::<S>(),
4235 )
4236 }
4237 })
4238 .unwrap();
4239
4240 let state = state_box.take().expect(
4241 "reentrant call to with_element_state for the same state type and element id",
4242 );
4243 let (result, state) = f(Some(state), self);
4244 state_box.replace(state);
4245 self.insert_element_state(
4246 key,
4247 ElementStateBox {
4248 inner: state_box,
4249 #[cfg(debug_assertions)]
4250 type_name,
4251 },
4252 );
4253 result
4254 } else {
4255 let (result, state) = f(None, self);
4256 self.insert_element_state(
4257 key,
4258 ElementStateBox {
4259 inner: Box::new(Some(state)),
4260 #[cfg(debug_assertions)]
4261 type_name: std::any::type_name::<S>(),
4262 },
4263 );
4264 result
4265 }
4266 }
4267
4268 pub fn with_optional_element_state<S, R>(
4275 &mut self,
4276 global_id: Option<&GlobalElementId>,
4277 f: impl FnOnce(Option<Option<S>>, &mut Self) -> (R, Option<S>),
4278 ) -> R
4279 where
4280 S: 'static,
4281 {
4282 self.invalidator.debug_assert_paint_or_prepaint();
4283
4284 if let Some(global_id) = global_id {
4285 self.with_element_state(global_id, |state, cx| {
4286 let (result, state) = f(Some(state), cx);
4287 let state =
4288 state.expect("you must return some state when you pass some element id");
4289 (result, state)
4290 })
4291 } else {
4292 let (result, state) = f(None, self);
4293 debug_assert!(
4294 state.is_none(),
4295 "you must not return an element state when passing None for the global id"
4296 );
4297 result
4298 }
4299 }
4300
4301 #[inline]
4303 pub fn with_tab_group<R>(&mut self, index: Option<isize>, f: impl FnOnce(&mut Self) -> R) -> R {
4304 if let Some(index) = index {
4305 self.next_frame.tab_stops.begin_group(index);
4306 let result = f(self);
4307 self.next_frame.tab_stops.end_group();
4308 result
4309 } else {
4310 f(self)
4311 }
4312 }
4313
4314 pub fn defer_draw(
4323 &mut self,
4324 element: AnyElement,
4325 absolute_offset: Point<Pixels>,
4326 priority: usize,
4327 content_mask: Option<ContentMask<Pixels>>,
4328 ) {
4329 self.invalidator.debug_assert_prepaint();
4330 let parent_node = self.next_frame.dispatch_tree.active_node_id().unwrap();
4331 self.next_frame.deferred_draws.push(DeferredDraw {
4332 current_view: self.current_view(),
4333 parent_node,
4334 element_id_stack: self.element_id_stack.clone(),
4335 text_style_stack: self.text_style_stack.clone(),
4336 content_mask,
4337 rem_size: self.rem_size(),
4338 priority,
4339 element: Some(element),
4340 absolute_offset,
4341 prepaint_range: PrepaintStateIndex::default()..PrepaintStateIndex::default(),
4342 paint_range: PaintIndex::default()..PaintIndex::default(),
4343 });
4344 }
4345
4346 pub fn paint_layer<R>(&mut self, bounds: Bounds<Pixels>, f: impl FnOnce(&mut Self) -> R) -> R {
4352 self.invalidator.debug_assert_paint();
4353
4354 let content_mask = self.content_mask();
4355 let clipped_bounds = bounds.intersect(&content_mask.bounds);
4356 if !clipped_bounds.is_empty() {
4357 self.next_frame
4358 .scene
4359 .push_layer(self.cover_bounds(clipped_bounds));
4360 }
4361
4362 let result = f(self);
4363
4364 if !clipped_bounds.is_empty() {
4365 self.next_frame.scene.pop_layer();
4366 }
4367
4368 result
4369 }
4370
4371 pub fn paint_drop_shadows(
4377 &mut self,
4378 bounds: Bounds<Pixels>,
4379 corner_radii: Corners<Pixels>,
4380 shadows: &[BoxShadow],
4381 ) {
4382 self.invalidator.debug_assert_paint();
4383
4384 let scale_factor = self.scale_factor();
4385 let content_mask = self.snapped_content_mask();
4386 let opacity = self.element_opacity();
4387 let element_bounds = self.cover_bounds(bounds);
4388 let element_corner_radii = corner_radii.scale(scale_factor);
4389 for shadow in shadows {
4390 if shadow.inset {
4391 continue;
4392 }
4393 let shadow_bounds = (bounds + shadow.offset).dilate(shadow.spread_radius);
4394 self.next_frame.scene.insert_primitive(Shadow {
4395 order: 0,
4396 blur_radius: shadow.blur_radius.scale(scale_factor),
4397 bounds: self.cover_bounds(shadow_bounds),
4398 content_mask,
4399 corner_radii: corner_radii.scale(scale_factor),
4400 color: shadow.color.opacity(opacity),
4401 element_bounds,
4402 element_corner_radii,
4403 inset: 0,
4404 pad: 0,
4405 });
4406 }
4407 }
4408
4409 pub fn paint_inset_shadows(
4413 &mut self,
4414 bounds: Bounds<Pixels>,
4415 corner_radii: Corners<Pixels>,
4416 shadows: &[BoxShadow],
4417 ) {
4418 self.invalidator.debug_assert_paint();
4419
4420 let scale_factor = self.scale_factor();
4421 let content_mask = self.snapped_content_mask();
4422 let opacity = self.element_opacity();
4423 let element_bounds = self.cover_bounds(bounds);
4424 let element_corner_radii = corner_radii.scale(scale_factor);
4425 for shadow in shadows {
4426 if !shadow.inset {
4427 continue;
4428 }
4429 let hole = (bounds + shadow.offset).dilate(-shadow.spread_radius);
4430 let zero = Pixels::ZERO;
4433 let hole_corner_radii = Corners {
4434 top_left: (corner_radii.top_left - shadow.spread_radius).max(zero),
4435 top_right: (corner_radii.top_right - shadow.spread_radius).max(zero),
4436 bottom_right: (corner_radii.bottom_right - shadow.spread_radius).max(zero),
4437 bottom_left: (corner_radii.bottom_left - shadow.spread_radius).max(zero),
4438 };
4439 self.next_frame.scene.insert_primitive(Shadow {
4440 order: 0,
4441 blur_radius: shadow.blur_radius.scale(scale_factor),
4442 bounds: self.cover_bounds(hole),
4443 content_mask,
4444 corner_radii: hole_corner_radii.scale(scale_factor),
4445 color: shadow.color.opacity(opacity),
4446 element_bounds,
4447 element_corner_radii,
4448 inset: 1,
4449 pad: 0,
4450 });
4451 }
4452 }
4453
4454 fn largest_border_interior(quad: &Quad) -> Bounds<ScaledPixels> {
4455 let radii = &quad.corner_radii;
4456 let widths = &quad.border_widths;
4457 let edge_radii = Edges {
4458 top: radii.top_left.max(radii.top_right),
4459 right: radii.top_right.max(radii.bottom_right),
4460 bottom: radii.bottom_left.max(radii.bottom_right),
4461 left: radii.top_left.max(radii.bottom_left),
4462 };
4463
4464 let antialias_inset = point(ScaledPixels(1.0), ScaledPixels(1.0));
4465 let inset_bounds = |top_left_inset, bottom_right_inset| {
4466 Bounds::from_corners(
4467 quad.bounds.origin + top_left_inset + antialias_inset,
4468 quad.bounds.bottom_right() - bottom_right_inset - antialias_inset,
4469 )
4470 };
4471
4472 let horizontal_band = inset_bounds(
4475 point(widths.left, widths.top.max(edge_radii.top)),
4476 point(widths.right, widths.bottom.max(edge_radii.bottom)),
4477 );
4478 let vertical_band = inset_bounds(
4479 point(widths.left.max(edge_radii.left), widths.top),
4480 point(widths.right.max(edge_radii.right), widths.bottom),
4481 );
4482
4483 let area = |bounds: &Bounds<ScaledPixels>| {
4484 bounds.size.width.0.max(0.) * bounds.size.height.0.max(0.)
4485 };
4486 if area(&horizontal_band) >= area(&vertical_band) {
4487 horizontal_band
4488 } else {
4489 vertical_band
4490 }
4491 }
4492
4493 pub fn paint_quad(&mut self, quad: PaintQuad) {
4503 self.invalidator.debug_assert_paint();
4504
4505 let opacity = self.element_opacity();
4506 let snapped_bounds = self.snap_bounds(quad.bounds);
4507 let snapped_border_widths = self.snap_border_widths(quad.border_widths);
4508 let quad = Quad {
4509 order: 0,
4510 bounds: snapped_bounds,
4511 content_mask: self.snapped_content_mask(),
4512 background: quad.background.opacity(opacity),
4513 border_color: quad.border_color.opacity(opacity),
4514 corner_radii: quad.corner_radii.scale(self.scale_factor()),
4515 border_widths: snapped_border_widths,
4516 border_style: quad.border_style,
4517 };
4518
4519 if !quad.background.is_transparent() {
4520 self.next_frame.scene.insert_primitive(quad);
4521 return;
4522 }
4523
4524 let outer_bounds = quad.bounds;
4527 let inner_bounds = Self::largest_border_interior(&quad);
4528
4529 if inner_bounds.is_empty() {
4530 self.next_frame.scene.insert_primitive(quad);
4531 return;
4532 }
4533
4534 let strips = [
4535 Bounds::from_corners(
4537 outer_bounds.origin,
4538 point(outer_bounds.right(), inner_bounds.top()),
4539 ),
4540 Bounds::from_corners(
4542 point(outer_bounds.left(), inner_bounds.bottom()),
4543 outer_bounds.bottom_right(),
4544 ),
4545 Bounds::from_corners(
4547 point(outer_bounds.left(), inner_bounds.top()),
4548 inner_bounds.bottom_left(),
4549 ),
4550 Bounds::from_corners(
4552 inner_bounds.top_right(),
4553 point(outer_bounds.right(), inner_bounds.bottom()),
4554 ),
4555 ];
4556
4557 for strip in strips {
4558 let content_mask_bounds = quad.content_mask.bounds.intersect(&strip);
4559 if !content_mask_bounds.is_empty() {
4560 self.next_frame.scene.insert_primitive(Quad {
4561 content_mask: ContentMask {
4562 bounds: content_mask_bounds,
4563 },
4564 ..quad
4565 });
4566 }
4567 }
4568 }
4569
4570 pub fn paint_path(&mut self, mut path: Path<Pixels>, color: impl Into<Background>) {
4574 self.invalidator.debug_assert_paint();
4575
4576 let scale_factor = self.scale_factor();
4577 let content_mask = self.content_mask();
4578 let opacity = self.element_opacity();
4579 path.content_mask = content_mask;
4580 let color: Background = color.into();
4581 path.color = color.opacity(opacity);
4582 self.next_frame
4583 .scene
4584 .insert_primitive(path.scale(scale_factor));
4585 }
4586
4587 pub fn paint_underline(
4591 &mut self,
4592 origin: Point<Pixels>,
4593 width: Pixels,
4594 style: &UnderlineStyle,
4595 ) {
4596 self.invalidator.debug_assert_paint();
4597 let underline = self.underline(origin, width, style);
4598 self.next_frame.scene.insert_primitive(underline);
4599 }
4600
4601 pub fn paint_strikethrough(
4605 &mut self,
4606 origin: Point<Pixels>,
4607 width: Pixels,
4608 style: &StrikethroughStyle,
4609 ) {
4610 self.invalidator.debug_assert_paint();
4611
4612 let scale_factor = self.scale_factor();
4613 let height = style.thickness;
4614 let bounds = Bounds {
4615 origin: origin.map(|c| ScaledPixels(round_to_device_pixel(c.0, scale_factor))),
4616 size: size(self.snap_stroke(width), self.snap_stroke(height)),
4617 };
4618 let opacity = self.element_opacity();
4619
4620 self.next_frame.scene.insert_primitive(Underline {
4621 order: 0,
4622 pad: 0,
4623 bounds,
4624 content_mask: self.snapped_content_mask(),
4625 thickness: self.snap_stroke(style.thickness),
4626 color: style.color.unwrap_or_default().opacity(opacity),
4627 wavy: false.into(),
4628 });
4629 }
4630
4631 pub fn paint_glyph(
4640 &mut self,
4641 origin: Point<Pixels>,
4642 font_id: FontId,
4643 glyph_id: GlyphId,
4644 font_size: Pixels,
4645 color: Hsla,
4646 ) -> Result<()> {
4647 self.invalidator.debug_assert_paint();
4648
4649 let element_opacity = self.element_opacity();
4650 let scale_factor = self.scale_factor();
4651 let glyph_origin = origin.scale(scale_factor);
4652
4653 let quantized_origin = Point::new(
4654 round_half_toward_zero(glyph_origin.x.0 * SUBPIXEL_VARIANTS_X as f32)
4655 / SUBPIXEL_VARIANTS_X as f32,
4656 round_half_toward_zero(glyph_origin.y.0 * SUBPIXEL_VARIANTS_Y as f32)
4657 / SUBPIXEL_VARIANTS_Y as f32,
4658 );
4659 let subpixel_variant = Point::new(
4660 (quantized_origin.x.fract() * SUBPIXEL_VARIANTS_X as f32) as u8,
4661 (quantized_origin.y.fract() * SUBPIXEL_VARIANTS_Y as f32) as u8,
4662 );
4663 let integer_origin = quantized_origin.map(|c| ScaledPixels(c.trunc()));
4664 let subpixel_rendering = self.should_use_subpixel_rendering(font_id, font_size);
4665 let dilation = self.text_system().glyph_dilation_for_color(color);
4666 let params = RenderGlyphParams {
4667 font_id,
4668 glyph_id,
4669 font_size,
4670 subpixel_variant,
4671 scale_factor,
4672 is_emoji: false,
4673 subpixel_rendering,
4674 dilation,
4675 };
4676
4677 let raster_bounds = self.text_system().raster_bounds(¶ms)?;
4678 if !raster_bounds.is_zero() {
4679 let tile = self
4680 .sprite_atlas
4681 .get_or_insert_with(params.clone().into(), &mut || {
4682 let (size, bytes) = self.text_system().rasterize_glyph(¶ms)?;
4683 Ok(Some((size, Cow::Owned(bytes))))
4684 })?
4685 .expect("Callback above only errors or returns Some");
4686 let bounds = Bounds {
4687 origin: integer_origin + raster_bounds.origin.map(Into::into),
4688 size: tile.bounds.size.map(Into::into),
4689 };
4690 let content_mask = self.snapped_content_mask();
4691
4692 if subpixel_rendering {
4693 self.next_frame.scene.insert_primitive(SubpixelSprite {
4694 order: 0,
4695 pad: 0,
4696 bounds,
4697 content_mask,
4698 color: color.opacity(element_opacity),
4699 tile,
4700 transformation: TransformationMatrix::unit(),
4701 });
4702 } else {
4703 self.next_frame.scene.insert_primitive(MonochromeSprite {
4704 order: 0,
4705 pad: 0,
4706 bounds,
4707 content_mask,
4708 color: color.opacity(element_opacity),
4709 tile,
4710 transformation: TransformationMatrix::unit(),
4711 });
4712 }
4713 }
4714 Ok(())
4715 }
4716
4717 fn should_use_subpixel_rendering(&self, font_id: FontId, font_size: Pixels) -> bool {
4718 if self.platform_window.background_appearance() != WindowBackgroundAppearance::Opaque {
4719 return false;
4720 }
4721
4722 if !self.platform_window.is_subpixel_rendering_supported() {
4723 return false;
4724 }
4725
4726 let mode = match self.text_rendering_mode.get() {
4727 TextRenderingMode::PlatformDefault => self
4728 .text_system()
4729 .recommended_rendering_mode(font_id, font_size),
4730 mode => mode,
4731 };
4732
4733 mode == TextRenderingMode::Subpixel
4734 }
4735
4736 pub fn paint_emoji(
4745 &mut self,
4746 origin: Point<Pixels>,
4747 font_id: FontId,
4748 glyph_id: GlyphId,
4749 font_size: Pixels,
4750 ) -> Result<()> {
4751 self.invalidator.debug_assert_paint();
4752
4753 let scale_factor = self.scale_factor();
4754 let glyph_origin = origin.scale(scale_factor);
4755 let integer_origin = glyph_origin.map(|c| ScaledPixels(round_half_toward_zero(c.0)));
4756 let params = RenderGlyphParams {
4757 font_id,
4758 glyph_id,
4759 font_size,
4760 subpixel_variant: Default::default(),
4761 scale_factor,
4762 is_emoji: true,
4763 subpixel_rendering: false,
4764 dilation: 0,
4765 };
4766
4767 let raster_bounds = self.text_system().raster_bounds(¶ms)?;
4768 if !raster_bounds.is_zero() {
4769 let tile = self
4770 .sprite_atlas
4771 .get_or_insert_with(params.clone().into(), &mut || {
4772 let (size, bytes) = self.text_system().rasterize_glyph(¶ms)?;
4773 Ok(Some((size, Cow::Owned(bytes))))
4774 })?
4775 .expect("Callback above only errors or returns Some");
4776
4777 let bounds = Bounds {
4778 origin: integer_origin + raster_bounds.origin.map(Into::into),
4779 size: tile.bounds.size.map(Into::into),
4780 };
4781 let content_mask = self.snapped_content_mask();
4782 let opacity = self.element_opacity();
4783
4784 self.next_frame.scene.insert_primitive(PolychromeSprite {
4785 order: 0,
4786 pad: 0,
4787 grayscale: false.into(),
4788 bounds,
4789 corner_radii: Default::default(),
4790 content_mask,
4791 tile,
4792 opacity,
4793 });
4794 }
4795 Ok(())
4796 }
4797
4798 pub fn paint_svg(
4802 &mut self,
4803 bounds: Bounds<Pixels>,
4804 path: SharedString,
4805 mut data: Option<&[u8]>,
4806 transformation: TransformationMatrix,
4807 color: Hsla,
4808 cx: &App,
4809 ) -> Result<()> {
4810 self.invalidator.debug_assert_paint();
4811
4812 let element_opacity = self.element_opacity();
4813 let bounds = self.snap_bounds(bounds);
4814
4815 let params = RenderSvgParams {
4816 path,
4817 size: bounds.size.map(|pixels| {
4818 DevicePixels::from((pixels.0 * SMOOTH_SVG_SCALE_FACTOR).ceil() as i32)
4819 }),
4820 };
4821
4822 let Some(tile) =
4823 self.sprite_atlas
4824 .get_or_insert_with(params.clone().into(), &mut || {
4825 let Some((size, bytes)) = cx.svg_renderer.render_alpha_mask(¶ms, data)?
4826 else {
4827 return Ok(None);
4828 };
4829 Ok(Some((size, Cow::Owned(bytes))))
4830 })?
4831 else {
4832 return Ok(());
4833 };
4834 let content_mask = self.snapped_content_mask();
4835 let svg_bounds = Bounds {
4836 origin: bounds.center()
4837 - Point::new(
4838 ScaledPixels(tile.bounds.size.width.0 as f32 / SMOOTH_SVG_SCALE_FACTOR / 2.),
4839 ScaledPixels(tile.bounds.size.height.0 as f32 / SMOOTH_SVG_SCALE_FACTOR / 2.),
4840 ),
4841 size: tile
4842 .bounds
4843 .size
4844 .map(|value| ScaledPixels(value.0 as f32 / SMOOTH_SVG_SCALE_FACTOR)),
4845 };
4846 let final_bounds = svg_bounds
4847 .map_origin(|value| ScaledPixels(round_half_toward_zero(value.0)))
4848 .map_size(|size| size.ceil());
4849
4850 self.next_frame.scene.insert_primitive(MonochromeSprite {
4851 order: 0,
4852 pad: 0,
4853 bounds: final_bounds,
4854 content_mask,
4855 color: color.opacity(element_opacity),
4856 tile,
4857 transformation,
4858 });
4859
4860 Ok(())
4861 }
4862
4863 pub fn paint_image(
4872 &mut self,
4873 bounds: Bounds<Pixels>,
4874 image_bounds: Bounds<Pixels>,
4875 corner_radii: Corners<Pixels>,
4876 data: Arc<RenderImage>,
4877 frame_index: usize,
4878 grayscale: bool,
4879 ) -> Result<()> {
4880 self.invalidator.debug_assert_paint();
4881
4882 let visible_bounds = bounds.intersect(&image_bounds);
4883 if visible_bounds.size.width <= Pixels::ZERO || visible_bounds.size.height <= Pixels::ZERO {
4884 return Ok(());
4885 }
4886 if image_bounds.size.width <= Pixels::ZERO || image_bounds.size.height <= Pixels::ZERO {
4887 return Ok(());
4888 }
4889
4890 let params = RenderImageParams {
4891 image_id: data.id,
4892 frame_index,
4893 };
4894
4895 let tile = self
4896 .sprite_atlas
4897 .get_or_insert_with(params.into(), &mut || {
4898 Ok(Some((
4899 data.size(frame_index),
4900 Cow::Borrowed(
4901 data.as_bytes(frame_index)
4902 .expect("It's the caller's job to pass a valid frame index"),
4903 ),
4904 )))
4905 })?
4906 .expect("Callback above only returns Some");
4907
4908 let visible_bounds_snapped = self.snap_bounds(visible_bounds);
4909
4910 let sub_tile = if visible_bounds == image_bounds {
4911 tile
4912 } else {
4913 let x_offset_ratio =
4914 (visible_bounds.origin.x - image_bounds.origin.x) / image_bounds.size.width;
4915 let y_offset_ratio =
4916 (visible_bounds.origin.y - image_bounds.origin.y) / image_bounds.size.height;
4917 let width_ratio = visible_bounds.size.width / image_bounds.size.width;
4918 let height_ratio = visible_bounds.size.height / image_bounds.size.height;
4919
4920 let tile_origin_x = tile.bounds.origin.x.0;
4921 let tile_origin_y = tile.bounds.origin.y.0;
4922 let tile_width = tile.bounds.size.width.0;
4923 let tile_height = tile.bounds.size.height.0;
4924
4925 let sub_origin_x = tile_origin_x + (x_offset_ratio * tile_width as f32).round() as i32;
4926 let sub_origin_y = tile_origin_y + (y_offset_ratio * tile_height as f32).round() as i32;
4927 let sub_width = (width_ratio * tile_width as f32).round() as i32;
4928 let sub_height = (height_ratio * tile_height as f32).round() as i32;
4929
4930 let max_x = tile_origin_x + tile_width;
4931 let max_y = tile_origin_y + tile_height;
4932
4933 let clamped_origin_x = sub_origin_x.clamp(tile_origin_x, max_x);
4934 let clamped_origin_y = sub_origin_y.clamp(tile_origin_y, max_y);
4935 let clamped_width = sub_width.min(max_x - clamped_origin_x).max(0);
4936 let clamped_height = sub_height.min(max_y - clamped_origin_y).max(0);
4937
4938 AtlasTile {
4939 bounds: Bounds {
4940 origin: point(
4941 DevicePixels(clamped_origin_x),
4942 DevicePixels(clamped_origin_y),
4943 ),
4944 size: size(DevicePixels(clamped_width), DevicePixels(clamped_height)),
4945 },
4946 ..tile
4947 }
4948 };
4949
4950 let content_mask = self.snapped_content_mask();
4951 let corner_radii = corner_radii
4952 .clamp_radii_for_quad_size(visible_bounds.size)
4953 .scale(self.scale_factor());
4954 let opacity = self.element_opacity();
4955
4956 self.next_frame.scene.insert_primitive(PolychromeSprite {
4957 order: 0,
4958 pad: 0,
4959 grayscale: grayscale.into(),
4960 bounds: visible_bounds_snapped,
4961 content_mask,
4962 corner_radii,
4963 tile: sub_tile,
4964 opacity,
4965 });
4966 Ok(())
4967 }
4968
4969 #[cfg(target_os = "macos")]
4973 pub fn paint_surface(&mut self, bounds: Bounds<Pixels>, image_buffer: CVPixelBuffer) {
4974 use crate::PaintSurface;
4975
4976 self.invalidator.debug_assert_paint();
4977
4978 let bounds = self.snap_bounds(bounds);
4979 let content_mask = self.snapped_content_mask();
4980 self.next_frame.scene.insert_primitive(PaintSurface {
4981 order: 0,
4982 bounds,
4983 content_mask,
4984 image_buffer,
4985 });
4986 }
4987
4988 pub fn drop_image(&mut self, data: Arc<RenderImage>) -> Result<()> {
4990 for frame_index in 0..data.frame_count() {
4991 let params = RenderImageParams {
4992 image_id: data.id,
4993 frame_index,
4994 };
4995
4996 self.sprite_atlas.remove(¶ms.clone().into());
4997 }
4998
4999 Ok(())
5000 }
5001
5002 #[cfg(any(test, feature = "test-support"))]
5004 pub fn has_image_atlas_entry(&self, data: &RenderImage) -> bool {
5005 data.frame_count() > 0
5006 && (0..data.frame_count()).all(|frame_index| {
5007 self.sprite_atlas.contains(
5008 &RenderImageParams {
5009 image_id: data.id,
5010 frame_index,
5011 }
5012 .into(),
5013 )
5014 })
5015 }
5016
5017 #[must_use]
5023 pub fn request_layout(
5024 &mut self,
5025 style: Style,
5026 children: impl IntoIterator<Item = LayoutId>,
5027 cx: &mut App,
5028 ) -> LayoutId {
5029 self.invalidator.debug_assert_prepaint();
5030
5031 cx.layout_id_buffer.clear();
5032 cx.layout_id_buffer.extend(children);
5033 let rem_size = self.rem_size();
5034 let scale_factor = self.scale_factor();
5035
5036 self.layout_engine.as_mut().unwrap().request_layout(
5037 style,
5038 rem_size,
5039 scale_factor,
5040 &cx.layout_id_buffer,
5041 )
5042 }
5043
5044 pub fn request_measured_layout<F>(&mut self, style: Style, measure: F) -> LayoutId
5053 where
5054 F: Fn(Size<Option<Pixels>>, Size<AvailableSpace>, &mut Window, &mut App) -> Size<Pixels>
5055 + 'static,
5056 {
5057 self.invalidator.debug_assert_prepaint();
5058
5059 let rem_size = self.rem_size();
5060 let scale_factor = self.scale_factor();
5061 self.layout_engine
5062 .as_mut()
5063 .unwrap()
5064 .request_measured_layout(style, rem_size, scale_factor, measure)
5065 }
5066
5067 pub fn compute_layout(
5073 &mut self,
5074 layout_id: LayoutId,
5075 available_space: Size<AvailableSpace>,
5076 cx: &mut App,
5077 ) {
5078 self.invalidator.debug_assert_prepaint();
5079
5080 let mut layout_engine = self.layout_engine.take().unwrap();
5081 layout_engine.compute_layout(layout_id, available_space, self, cx);
5082 self.layout_engine = Some(layout_engine);
5083 }
5084
5085 pub fn layout_bounds(&mut self, layout_id: LayoutId) -> Bounds<Pixels> {
5090 self.invalidator.debug_assert_prepaint();
5091
5092 let scale_factor = self.scale_factor();
5093 let mut bounds = self
5094 .layout_engine
5095 .as_mut()
5096 .unwrap()
5097 .layout_bounds(layout_id, scale_factor)
5098 .map(Into::into);
5099 let snapped_offset = self.pixel_snap_point(self.element_offset());
5100 bounds.origin += snapped_offset;
5101 bounds
5102 }
5103
5104 pub fn insert_hitbox(&mut self, bounds: Bounds<Pixels>, behavior: HitboxBehavior) -> Hitbox {
5110 self.invalidator.debug_assert_prepaint();
5111
5112 let content_mask = self.content_mask();
5113 let mut id = self.next_hitbox_id;
5114 self.next_hitbox_id = self.next_hitbox_id.next();
5115 let hitbox = Hitbox {
5116 id,
5117 bounds,
5118 content_mask,
5119 behavior,
5120 };
5121 self.next_frame.hitboxes.push(hitbox.clone());
5122 hitbox
5123 }
5124
5125 pub fn insert_window_control_hitbox(&mut self, area: WindowControlArea, hitbox: Hitbox) {
5129 self.invalidator.debug_assert_paint();
5130 self.next_frame.window_control_hitboxes.push((area, hitbox));
5131 }
5132
5133 pub fn set_key_context(&mut self, context: KeyContext) {
5138 self.invalidator.debug_assert_paint();
5139 self.next_frame.dispatch_tree.set_key_context(context);
5140 }
5141
5142 pub fn set_focus_handle(&mut self, focus_handle: &FocusHandle, _: &App) {
5147 self.invalidator.debug_assert_prepaint();
5148 if focus_handle.is_focused(self) {
5149 self.next_frame.focus = Some(focus_handle.id);
5150 }
5151 self.next_frame.dispatch_tree.set_focus_id(focus_handle.id);
5152 }
5153
5154 pub fn set_view_id(&mut self, view_id: EntityId) {
5160 self.invalidator.debug_assert_prepaint();
5161 self.next_frame.dispatch_tree.set_view_id(view_id);
5162 }
5163
5164 pub fn current_view(&self) -> EntityId {
5166 self.invalidator.debug_assert_paint_or_prepaint();
5167 self.rendered_entity_stack.last().copied().unwrap()
5168 }
5169
5170 #[inline]
5171 pub(crate) fn with_rendered_view<R>(
5172 &mut self,
5173 id: EntityId,
5174 f: impl FnOnce(&mut Self) -> R,
5175 ) -> R {
5176 self.rendered_entity_stack.push(id);
5177 let result = f(self);
5178 self.rendered_entity_stack.pop();
5179 result
5180 }
5181
5182 pub fn with_image_cache<F, R>(&mut self, image_cache: Option<AnyImageCache>, f: F) -> R
5184 where
5185 F: FnOnce(&mut Self) -> R,
5186 {
5187 if let Some(image_cache) = image_cache {
5188 self.image_cache_stack.push(image_cache);
5189 let result = f(self);
5190 self.image_cache_stack.pop();
5191 result
5192 } else {
5193 f(self)
5194 }
5195 }
5196
5197 pub fn handle_input(
5206 &mut self,
5207 focus_handle: &FocusHandle,
5208 input_handler: impl InputHandler,
5209 cx: &App,
5210 ) {
5211 self.invalidator.debug_assert_paint();
5212
5213 if focus_handle.is_focused(self) {
5214 let cx = self.to_async(cx);
5215 self.next_frame
5216 .input_handlers
5217 .push(Some(PlatformInputHandler::new(cx, Box::new(input_handler))));
5218 }
5219 }
5220
5221 fn apply_text_input_configuration(&mut self, cx: &mut App) {
5226 let configuration = match self.platform_window.take_input_handler() {
5227 Some(mut input_handler) => {
5228 let configuration = input_handler.text_input_configuration(self, cx);
5229 self.platform_window.set_input_handler(input_handler);
5230 configuration
5231 }
5232 None => TextInputConfiguration::default(),
5233 };
5234 if self.last_text_input_configuration.as_ref() != Some(&configuration) {
5235 self.platform_window
5236 .set_text_input_configuration(configuration.clone());
5237 self.last_text_input_configuration = Some(configuration);
5238 }
5239 }
5240
5241 pub fn on_mouse_event<Event: MouseEvent>(
5247 &mut self,
5248 mut listener: impl FnMut(&Event, DispatchPhase, &mut Window, &mut App) + 'static,
5249 ) {
5250 self.invalidator.debug_assert_paint();
5251
5252 self.next_frame.mouse_listeners.push(Some(Box::new(
5253 move |event: &dyn Any, phase: DispatchPhase, window: &mut Window, cx: &mut App| {
5254 if let Some(event) = event.downcast_ref() {
5255 listener(event, phase, window, cx)
5256 }
5257 },
5258 )));
5259 }
5260
5261 pub fn on_key_event<Event: KeyEvent>(
5270 &mut self,
5271 listener: impl Fn(&Event, DispatchPhase, &mut Window, &mut App) + 'static,
5272 ) {
5273 self.invalidator.debug_assert_paint();
5274
5275 self.next_frame.dispatch_tree.on_key_event(Rc::new(
5276 move |event: &dyn Any, phase, window: &mut Window, cx: &mut App| {
5277 if let Some(event) = event.downcast_ref::<Event>() {
5278 listener(event, phase, window, cx)
5279 }
5280 },
5281 ));
5282 }
5283
5284 pub fn on_modifiers_changed(
5291 &mut self,
5292 listener: impl Fn(&ModifiersChangedEvent, &mut Window, &mut App) + 'static,
5293 ) {
5294 self.invalidator.debug_assert_paint();
5295
5296 self.next_frame.dispatch_tree.on_modifiers_changed(Rc::new(
5297 move |event: &ModifiersChangedEvent, window: &mut Window, cx: &mut App| {
5298 listener(event, window, cx)
5299 },
5300 ));
5301 }
5302
5303 pub fn on_focus_in(
5307 &mut self,
5308 handle: &FocusHandle,
5309 cx: &mut App,
5310 mut listener: impl FnMut(&mut Window, &mut App) + 'static,
5311 ) -> Subscription {
5312 let focus_id = handle.id;
5313 let (subscription, activate) =
5314 self.new_focus_listener(Box::new(move |event, window, cx| {
5315 if event.is_focus_in(focus_id) {
5316 listener(window, cx);
5317 }
5318 true
5319 }));
5320 cx.defer(move |_| activate());
5321 subscription
5322 }
5323
5324 pub fn on_focus_out(
5327 &mut self,
5328 handle: &FocusHandle,
5329 cx: &mut App,
5330 mut listener: impl FnMut(FocusOutEvent, &mut Window, &mut App) + 'static,
5331 ) -> Subscription {
5332 let focus_id = handle.id;
5333 let (subscription, activate) =
5334 self.new_focus_listener(Box::new(move |event, window, cx| {
5335 if let Some(blurred_id) = event.previous_focus_path.last().copied()
5336 && event.is_focus_out(focus_id)
5337 {
5338 let event = FocusOutEvent {
5339 blurred: WeakFocusHandle {
5340 id: blurred_id,
5341 handles: Arc::downgrade(&cx.focus_handles),
5342 },
5343 };
5344 listener(event, window, cx)
5345 }
5346 true
5347 }));
5348 cx.defer(move |_| activate());
5349 subscription
5350 }
5351
5352 fn reset_cursor_style(&self, cx: &mut App) {
5353 if self.is_window_hovered() {
5355 let style = self
5356 .rendered_frame
5357 .cursor_style(self)
5358 .unwrap_or(CursorStyle::Arrow);
5359 cx.platform.set_cursor_style(style);
5360 }
5361 }
5362
5363 pub fn dispatch_keystroke(&mut self, keystroke: Keystroke, cx: &mut App) -> bool {
5366 let keystroke = keystroke.with_simulated_ime();
5367 let result = self.dispatch_event(
5368 PlatformInput::KeyDown(KeyDownEvent {
5369 keystroke: keystroke.clone(),
5370 is_held: false,
5371 prefer_character_input: false,
5372 }),
5373 cx,
5374 );
5375 if !result.propagate {
5376 return true;
5377 }
5378
5379 if let Some(input) = keystroke.key_char
5380 && let Some(mut input_handler) = self.platform_window.take_input_handler()
5381 {
5382 input_handler.dispatch_input(&input, self, cx);
5383 self.platform_window.set_input_handler(input_handler);
5384 return true;
5385 }
5386
5387 false
5388 }
5389
5390 pub fn keystroke_text_for(&self, action: &dyn Action) -> String {
5393 self.highest_precedence_binding_for_action(action)
5394 .map(|binding| {
5395 binding
5396 .keystrokes()
5397 .iter()
5398 .map(ToString::to_string)
5399 .collect::<Vec<_>>()
5400 .join(" ")
5401 })
5402 .unwrap_or_else(|| action.name().to_string())
5403 }
5404
5405 #[profiling::function]
5407 pub fn dispatch_event(&mut self, event: PlatformInput, cx: &mut App) -> DispatchEventResult {
5408 #[cfg(feature = "profiler")]
5409 self.window_profiler.begin_input(event.kind_name());
5410 let update_count_before = self.invalidator.update_count();
5411 let old_modality = self.last_input_modality;
5415 self.last_input_modality = match &event {
5416 PlatformInput::KeyDown(_) => InputModality::Keyboard,
5417 PlatformInput::MouseMove(_) | PlatformInput::MouseDown(_) => InputModality::Mouse,
5418 PlatformInput::Touch(_) => InputModality::Touch,
5419 _ => self.last_input_modality,
5420 };
5421 if self.last_input_modality != old_modality {
5422 self.refresh();
5423 }
5424
5425 cx.propagate_event = true;
5427 self.default_prevented = false;
5429
5430 let event = match event {
5431 PlatformInput::MouseMove(mouse_move) => {
5434 self.mouse_position = mouse_move.position;
5435 self.modifiers = mouse_move.modifiers;
5436 PlatformInput::MouseMove(mouse_move)
5437 }
5438 PlatformInput::MouseDown(mouse_down) => {
5439 self.mouse_position = mouse_down.position;
5440 self.modifiers = mouse_down.modifiers;
5441 PlatformInput::MouseDown(mouse_down)
5442 }
5443 PlatformInput::MouseUp(mouse_up) => {
5444 self.mouse_position = mouse_up.position;
5445 self.modifiers = mouse_up.modifiers;
5446 PlatformInput::MouseUp(mouse_up)
5447 }
5448 PlatformInput::MousePressure(mouse_pressure) => {
5449 PlatformInput::MousePressure(mouse_pressure)
5450 }
5451 PlatformInput::MouseExited(mouse_exited) => {
5452 self.modifiers = mouse_exited.modifiers;
5453 PlatformInput::MouseExited(mouse_exited)
5454 }
5455 PlatformInput::ModifiersChanged(modifiers_changed) => {
5456 self.modifiers = modifiers_changed.modifiers;
5457 self.capslock = modifiers_changed.capslock;
5458 PlatformInput::ModifiersChanged(modifiers_changed)
5459 }
5460 PlatformInput::ScrollWheel(scroll_wheel) => {
5461 self.mouse_position = scroll_wheel.position;
5462 self.modifiers = scroll_wheel.modifiers;
5463 PlatformInput::ScrollWheel(scroll_wheel)
5464 }
5465 PlatformInput::Pinch(pinch) => {
5466 self.mouse_position = pinch.position;
5467 self.modifiers = pinch.modifiers;
5468 PlatformInput::Pinch(pinch)
5469 }
5470 PlatformInput::FileDrop(file_drop) => match file_drop {
5473 FileDropEvent::Entered { position, paths } => {
5474 self.mouse_position = position;
5475 let source_window = self.handle.window_id();
5476 if !cx.restore_platform_drag(source_window) && cx.active_drag.is_none() {
5477 cx.active_drag = Some(AnyDrag {
5478 value: Arc::new(paths.clone()),
5479 view: cx.new(|_| paths).into(),
5480 cursor_offset: position,
5481 cursor_style: None,
5482 external_payload_source: None,
5483 });
5484 }
5485 PlatformInput::MouseMove(MouseMoveEvent {
5486 position,
5487 pressed_button: Some(MouseButton::Left),
5488 modifiers: Modifiers::default(),
5489 })
5490 }
5491 FileDropEvent::Pending { position } => {
5492 self.mouse_position = position;
5493 PlatformInput::MouseMove(MouseMoveEvent {
5494 position,
5495 pressed_button: Some(MouseButton::Left),
5496 modifiers: Modifiers::default(),
5497 })
5498 }
5499 FileDropEvent::Submit { position } => {
5500 cx.activate(true);
5501 self.mouse_position = position;
5502 PlatformInput::MouseUp(MouseUpEvent {
5503 button: MouseButton::Left,
5504 position,
5505 modifiers: Modifiers::default(),
5506 click_count: 1,
5507 })
5508 }
5509 FileDropEvent::Exited => {
5510 if !cx.hand_restored_drag_to_platform(self.handle.window_id()) {
5511 cx.active_drag.take();
5512 }
5513 self.refresh();
5514 PlatformInput::FileDrop(FileDropEvent::Exited)
5515 }
5516 FileDropEvent::Ended => {
5517 cx.end_platform_drag(self.handle.window_id());
5518 self.refresh();
5519 PlatformInput::FileDrop(FileDropEvent::Ended)
5520 }
5521 },
5522 PlatformInput::Touch(touch) => PlatformInput::Touch(touch),
5523 PlatformInput::LongPress(long_press) => {
5524 self.mouse_position = if long_press.phase == crate::TouchPhase::Started {
5525 long_press.start_position
5526 } else {
5527 long_press.position
5528 };
5529 if long_press.phase == crate::TouchPhase::Started {
5530 self.long_press_capture = None;
5531 }
5532 PlatformInput::LongPress(long_press)
5533 }
5534 PlatformInput::TouchDrag(touch_drag) => {
5535 self.mouse_position = touch_drag.start_position;
5536 PlatformInput::TouchDrag(touch_drag)
5537 }
5538 PlatformInput::KeyDown(_) | PlatformInput::KeyUp(_) => event,
5539 };
5540
5541 if let Some(any_mouse_event) = event.mouse_event() {
5542 self.dispatch_mouse_event(any_mouse_event, cx);
5543 } else if let Some(any_key_event) = event.keyboard_event() {
5544 self.dispatch_key_event(any_key_event, cx);
5545 } else if let Some(touch_event) = event.touch_event() {
5546 self.dispatch_touch_event(touch_event, cx);
5547 }
5548 if let PlatformInput::LongPress(long_press) = &event {
5549 match long_press.phase {
5550 crate::TouchPhase::Started if !self.default_prevented => {
5551 self.long_press_capture = None;
5552 }
5553 crate::TouchPhase::Ended | crate::TouchPhase::Cancelled => {
5554 self.long_press_capture = None;
5555 }
5556 crate::TouchPhase::Started | crate::TouchPhase::Moved => {}
5557 }
5558 }
5559
5560 self.promote_external_drag_to_platform(&event, cx);
5563
5564 let caused_invalidation = self.invalidator.update_count() > update_count_before;
5565 if caused_invalidation {
5566 self.input_rate_tracker.borrow_mut().record_input();
5567 }
5568 #[cfg(feature = "profiler")]
5569 self.window_profiler.end_input(caused_invalidation);
5570
5571 DispatchEventResult {
5572 propagate: cx.propagate_event,
5573 default_prevented: self.default_prevented,
5574 }
5575 }
5576
5577 fn promote_external_drag_to_platform(&mut self, event: &PlatformInput, cx: &mut App) {
5578 let PlatformInput::MouseMove(mouse_move) = event else {
5579 return;
5580 };
5581 if mouse_move.pressed_button != Some(MouseButton::Left) {
5582 return;
5583 }
5584 if Bounds::new(Point::default(), self.viewport_size).contains(&mouse_move.position) {
5585 return;
5586 }
5587 if !self.platform_window.can_start_external_drag() {
5588 return;
5589 }
5590 let Some(payload_source) = cx
5591 .active_drag
5592 .as_mut()
5593 .and_then(|drag| drag.external_payload_source.take())
5594 else {
5595 return;
5596 };
5597 let Some(payload) = payload_source(self, cx) else {
5598 return;
5599 };
5600 if self.platform_window.start_external_drag(&payload)
5601 && cx.hand_active_drag_to_platform(self.handle.window_id())
5602 {
5603 self.refresh();
5604 }
5605 }
5606
5607 pub fn touch_prediction_enabled(&self) -> bool {
5611 self.touch_prediction_enabled
5612 }
5613
5614 pub fn set_touch_prediction_enabled(&mut self, enabled: bool) {
5618 self.touch_prediction_enabled = enabled;
5619 }
5620
5621 fn dispatch_touch_event(&mut self, event: &TouchEvent, cx: &mut App) {
5625 let mut event = event.clone();
5626 if !self.touch_prediction_enabled {
5627 event.predicted_position = None;
5628 }
5629 let recognized_gestures = self.touch_gestures.handle_event(&event);
5630 if event.phase == crate::TouchPhase::Started
5631 && let Some(touch_drag) = self.touch_gestures.offer_touch_drag(event.id)
5632 {
5633 self.dispatch_recognized_touch_gesture(touch_drag, cx);
5634 }
5635 if event.phase == crate::TouchPhase::Started
5636 && self.touch_gestures.pending_long_press().is_some()
5637 {
5638 self.long_press_capture = None;
5639 }
5640 let mut tapped = false;
5641 for gesture in recognized_gestures {
5642 tapped |= matches!(gesture, RecognizedTouchGesture::Tap { .. });
5643 self.dispatch_recognized_touch_gesture(gesture, cx);
5644 }
5645 if event.phase == crate::TouchPhase::Started {
5646 self.schedule_long_press_timer(cx);
5647 } else if self.touch_gestures.pending_long_press().is_none() {
5648 self.long_press_timer.take();
5649 }
5650 if tapped && self.invalidator.is_dirty() {
5656 self.draw(cx).clear(cx);
5657 }
5658 if self.touch_gestures.has_momentum() {
5659 self.schedule_touch_momentum_tick();
5660 }
5661 }
5662
5663 fn dispatch_recognized_touch_gesture(&mut self, gesture: RecognizedTouchGesture, cx: &mut App) {
5664 match gesture {
5665 RecognizedTouchGesture::Scroll(scroll_wheel) => {
5666 self.mouse_position = scroll_wheel.position;
5667 cx.propagate_event = true;
5668 self.dispatch_mouse_event(&scroll_wheel, cx);
5669 }
5670 RecognizedTouchGesture::Tap { down, up } => {
5671 self.mouse_position = up.position;
5672 cx.propagate_event = true;
5673 self.dispatch_mouse_event(&down, cx);
5674 cx.propagate_event = true;
5675 self.dispatch_mouse_event(&up, cx);
5676 }
5677 RecognizedTouchGesture::TouchDrag(touch_drag) => {
5678 self.mouse_position = touch_drag.start_position;
5679 cx.propagate_event = true;
5680 self.default_prevented = false;
5681 let started = touch_drag.phase == crate::TouchPhase::Started;
5682 self.dispatch_mouse_event(&touch_drag, cx);
5683 if started {
5684 self.touch_gestures
5685 .resolve_touch_drag(self.default_prevented);
5686 }
5687 }
5688 RecognizedTouchGesture::LongPress(long_press) => {
5689 self.mouse_position = if long_press.phase == crate::TouchPhase::Started {
5690 long_press.start_position
5691 } else {
5692 long_press.position
5693 };
5694 cx.propagate_event = true;
5695 self.default_prevented = false;
5696 let started = long_press.phase == crate::TouchPhase::Started;
5697 let ended = matches!(
5698 long_press.phase,
5699 crate::TouchPhase::Ended | crate::TouchPhase::Cancelled
5700 );
5701 self.dispatch_mouse_event(&long_press, cx);
5702 if started {
5703 let claimed = self.default_prevented;
5704 self.touch_gestures.resolve_long_press(claimed);
5705 if !claimed {
5706 self.long_press_capture = None;
5707 }
5708 }
5709 if ended {
5710 self.long_press_capture = None;
5711 }
5712 }
5713 }
5714 }
5715
5716 fn schedule_long_press_timer(&mut self, cx: &mut App) {
5717 self.long_press_timer.take();
5718 let Some((touch_id, duration)) = self.touch_gestures.pending_long_press() else {
5719 return;
5720 };
5721 self.long_press_timer = Some(self.spawn(cx, async move |cx| {
5722 cx.background_executor.timer(duration).await;
5723 cx.update(move |window, cx| {
5724 window.long_press_timer.take();
5725 if let Some(gesture) = window.touch_gestures.offer_long_press(touch_id) {
5726 window.dispatch_recognized_touch_gesture(gesture, cx);
5727 }
5728 })
5729 .log_err();
5730 }));
5731 }
5732
5733 fn schedule_touch_momentum_tick(&mut self) {
5734 self.on_next_frame(|window, cx| {
5735 if let Some(gesture) = window.touch_gestures.tick_momentum() {
5736 window.dispatch_recognized_touch_gesture(gesture, cx);
5737 }
5738 if window.touch_gestures.has_momentum() {
5739 window.schedule_touch_momentum_tick();
5740 }
5741 });
5742 }
5743
5744 fn dispatch_mouse_event(&mut self, event: &dyn Any, cx: &mut App) {
5745 let hit_test = self.rendered_frame.hit_test(self.mouse_position());
5746 if hit_test != self.mouse_hit_test {
5747 self.mouse_hit_test = hit_test;
5748 self.reset_cursor_style(cx);
5749 }
5750
5751 #[cfg(any(feature = "inspector", debug_assertions))]
5752 if self.is_inspector_picking(cx) {
5753 self.handle_inspector_mouse_event(event, cx);
5754 return;
5756 }
5757
5758 let mut mouse_listeners = mem::take(&mut self.rendered_frame.mouse_listeners);
5759
5760 for listener in &mut mouse_listeners {
5763 let listener = listener.as_mut().unwrap();
5764 listener(event, DispatchPhase::Capture, self, cx);
5765 if !cx.propagate_event {
5766 break;
5767 }
5768 }
5769
5770 if cx.propagate_event {
5772 for listener in mouse_listeners.iter_mut().rev() {
5773 let listener = listener.as_mut().unwrap();
5774 listener(event, DispatchPhase::Bubble, self, cx);
5775 if !cx.propagate_event {
5776 break;
5777 }
5778 }
5779 }
5780
5781 self.rendered_frame.mouse_listeners = mouse_listeners;
5782
5783 if cx.has_active_drag() {
5784 if event.is::<MouseMoveEvent>() {
5785 self.refresh();
5788 } else if event.is::<MouseUpEvent>() {
5789 cx.active_drag = None;
5792 self.refresh();
5793 }
5794 }
5795
5796 if event.is::<MouseUpEvent>() && self.captured_hitbox.is_some() {
5798 self.captured_hitbox = None;
5799 }
5800 }
5801
5802 fn dispatch_key_event(&mut self, event: &dyn Any, cx: &mut App) {
5803 if self.invalidator.is_dirty() {
5804 self.draw(cx).clear(cx);
5805 }
5806
5807 let node_id = self.focus_node_id_in_rendered_frame(self.focus);
5808 let dispatch_path = self.rendered_frame.dispatch_tree.dispatch_path(node_id);
5809
5810 let mut keystroke: Option<Keystroke> = None;
5811
5812 if let Some(event) = event.downcast_ref::<ModifiersChangedEvent>() {
5813 if event.modifiers.number_of_modifiers() == 0
5814 && self.pending_modifier.modifiers.number_of_modifiers() == 1
5815 && !self.pending_modifier.saw_other_input
5816 {
5817 let key = match self.pending_modifier.modifiers {
5818 modifiers if modifiers.shift => Some("shift"),
5819 modifiers if modifiers.control => Some("control"),
5820 modifiers if modifiers.alt => Some("alt"),
5821 modifiers if modifiers.platform => Some("platform"),
5822 modifiers if modifiers.function => Some("function"),
5823 _ => None,
5824 };
5825 if let Some(key) = key {
5826 keystroke = Some(Keystroke {
5827 key: key.to_string(),
5828 key_char: None,
5829 modifiers: Modifiers::default(),
5830 });
5831 }
5832 }
5833
5834 if self.pending_modifier.modifiers.number_of_modifiers() == 0
5835 && event.modifiers.number_of_modifiers() == 1
5836 {
5837 self.pending_modifier.saw_other_input = false
5838 } else if event.modifiers.number_of_modifiers() > 1 {
5839 self.pending_modifier.saw_other_input = true
5840 }
5841 self.pending_modifier.modifiers = event.modifiers
5842 } else if let Some(key_down_event) = event.downcast_ref::<KeyDownEvent>() {
5843 self.pending_modifier.saw_other_input = true;
5844 keystroke = Some(key_down_event.keystroke.clone());
5845 if key_down_event.keystroke.key_char.is_some()
5846 && matches!(
5847 cx.cursor_hide_mode,
5848 CursorHideMode::OnTyping | CursorHideMode::OnTypingAndAction
5849 )
5850 {
5851 cx.platform.hide_cursor_until_mouse_moves();
5852 }
5853 }
5854
5855 let Some(keystroke) = keystroke else {
5856 self.finish_dispatch_key_event(event, None, dispatch_path, self.context_stack(), cx);
5857 return;
5858 };
5859
5860 cx.propagate_event = true;
5861 self.dispatch_keystroke_interceptors(&keystroke, self.context_stack(), cx);
5862 if !cx.propagate_event {
5863 self.finish_dispatch_key_event(
5864 event,
5865 Some(&keystroke),
5866 dispatch_path,
5867 self.context_stack(),
5868 cx,
5869 );
5870 return;
5871 }
5872
5873 let mut currently_pending = self.pending_input.take().unwrap_or_default();
5874 if currently_pending.focus.is_some() && currently_pending.focus != self.focus {
5875 currently_pending = PendingInput::default();
5876 }
5877
5878 let match_result = self.rendered_frame.dispatch_tree.dispatch_key(
5879 currently_pending.keystrokes,
5880 keystroke.clone(),
5881 &dispatch_path,
5882 );
5883
5884 if !match_result.to_replay.is_empty() {
5885 self.replay_pending_input(match_result.to_replay, cx);
5886 cx.propagate_event = true;
5887 }
5888
5889 if !match_result.pending.is_empty() {
5890 let previous_timeout = currently_pending.timeout.take();
5891 currently_pending.keystrokes = match_result.pending;
5892 currently_pending.focus = self.focus;
5893
5894 let text_input_requires_timeout = event
5895 .downcast_ref::<KeyDownEvent>()
5896 .filter(|key_down| key_down.keystroke.key_char.is_some())
5897 .and_then(|_| self.platform_window.take_input_handler())
5898 .map_or(false, |mut input_handler| {
5899 let accepts = input_handler.accepts_text_input(self, cx);
5900 self.platform_window.set_input_handler(input_handler);
5901 accepts
5902 });
5903
5904 let needs_timeout = previous_timeout.is_some()
5905 || match_result.pending_has_binding
5906 || text_input_requires_timeout;
5907 currently_pending.timeout = if needs_timeout {
5908 match previous_timeout {
5909 Some(mut timeout) if timeout.is_paused() => {
5910 timeout.reset_duration(PENDING_INPUT_TIMEOUT);
5911 Some(timeout)
5912 }
5913 previous_timeout => {
5914 drop(previous_timeout);
5915 Some(self.new_pending_input_timeout(PENDING_INPUT_TIMEOUT, cx))
5916 }
5917 }
5918 } else {
5919 None
5920 };
5921 self.pending_input = Some(currently_pending);
5922 self.pending_input_changed(cx);
5923 cx.propagate_event = false;
5924 return;
5925 }
5926
5927 let skip_bindings = event
5928 .downcast_ref::<KeyDownEvent>()
5929 .filter(|key_down_event| key_down_event.prefer_character_input)
5930 .map(|_| {
5931 self.platform_window
5932 .take_input_handler()
5933 .map_or(false, |mut input_handler| {
5934 let accepts = input_handler.accepts_text_input(self, cx);
5935 self.platform_window.set_input_handler(input_handler);
5936 accepts
5939 })
5940 })
5941 .unwrap_or(false);
5942
5943 if !skip_bindings {
5944 for binding in match_result.bindings {
5945 self.dispatch_action_on_node(node_id, binding.action.as_ref(), cx);
5946 if !cx.propagate_event {
5947 self.dispatch_keystroke_observers(
5948 &keystroke,
5949 Some(binding.action.as_ref()),
5950 match_result.context_stack,
5951 cx,
5952 );
5953 self.pending_input_changed(cx);
5954 return;
5955 }
5956 }
5957 }
5958
5959 self.finish_dispatch_key_event(
5960 event,
5961 Some(&keystroke),
5962 dispatch_path,
5963 match_result.context_stack,
5964 cx,
5965 );
5966 self.pending_input_changed(cx);
5967 }
5968
5969 fn new_pending_input_timeout(&self, duration: Duration, cx: &App) -> PendingInputTimeout {
5970 let (started_at, task) = self.start_pending_input_timeout(duration, cx);
5971 PendingInputTimeout {
5972 duration,
5973 remaining: duration,
5974 state: PendingInputTimeoutState::Running { started_at, task },
5975 }
5976 }
5977
5978 fn start_pending_input_timeout(&self, remaining: Duration, cx: &App) -> (Instant, Task<()>) {
5979 let started_at = cx.background_executor().now();
5980 let task = self.spawn(cx, async move |cx| {
5981 cx.background_executor.timer(remaining).await;
5982 cx.update(move |window, cx| {
5983 let Some(currently_pending) = window
5984 .pending_input
5985 .take()
5986 .filter(|pending| pending.focus == window.focus)
5987 else {
5988 return;
5989 };
5990
5991 let node_id = window.focus_node_id_in_rendered_frame(window.focus);
5992 let dispatch_path = window.rendered_frame.dispatch_tree.dispatch_path(node_id);
5993
5994 let to_replay = window
5995 .rendered_frame
5996 .dispatch_tree
5997 .flush_dispatch(currently_pending.keystrokes, &dispatch_path);
5998
5999 window.pending_input_changed(cx);
6000 window.replay_pending_input(to_replay, cx)
6001 })
6002 .log_err();
6003 });
6004 (started_at, task)
6005 }
6006
6007 fn finish_dispatch_key_event(
6008 &mut self,
6009 event: &dyn Any,
6010 recognized_keystroke: Option<&Keystroke>,
6011 dispatch_path: SmallVec<[DispatchNodeId; 32]>,
6012 context_stack: Vec<KeyContext>,
6013 cx: &mut App,
6014 ) {
6015 self.dispatch_key_down_up_event(event, &dispatch_path, cx);
6016 if !cx.propagate_event {
6017 return;
6018 }
6019
6020 self.dispatch_modifiers_changed_event(event, &dispatch_path, cx);
6021 if !cx.propagate_event {
6022 return;
6023 }
6024
6025 if let Some(keystroke) = recognized_keystroke {
6026 self.dispatch_keystroke_observers(keystroke, None, context_stack, cx);
6027 }
6028 }
6029
6030 pub(crate) fn pending_input_changed(&mut self, cx: &mut App) {
6031 self.pending_input_observers
6032 .clone()
6033 .retain(&(), |callback| callback(self, cx));
6034 }
6035
6036 fn defer_pending_input_changed(&self, cx: &mut App) {
6037 let window_handle = self.handle;
6040 cx.defer(move |cx| {
6041 window_handle
6042 .update(cx, |_, window, cx| {
6043 window.pending_input_changed(cx);
6044 })
6045 .ok();
6046 });
6047 }
6048
6049 fn dispatch_key_down_up_event(
6050 &mut self,
6051 event: &dyn Any,
6052 dispatch_path: &SmallVec<[DispatchNodeId; 32]>,
6053 cx: &mut App,
6054 ) {
6055 for node_id in dispatch_path {
6057 let node = self.rendered_frame.dispatch_tree.node(*node_id);
6058
6059 for key_listener in node.key_listeners.clone() {
6060 key_listener(event, DispatchPhase::Capture, self, cx);
6061 if !cx.propagate_event {
6062 return;
6063 }
6064 }
6065 }
6066
6067 for node_id in dispatch_path.iter().rev() {
6069 let node = self.rendered_frame.dispatch_tree.node(*node_id);
6071 for key_listener in node.key_listeners.clone() {
6072 key_listener(event, DispatchPhase::Bubble, self, cx);
6073 if !cx.propagate_event {
6074 return;
6075 }
6076 }
6077 }
6078 }
6079
6080 fn dispatch_modifiers_changed_event(
6081 &mut self,
6082 event: &dyn Any,
6083 dispatch_path: &SmallVec<[DispatchNodeId; 32]>,
6084 cx: &mut App,
6085 ) {
6086 let Some(event) = event.downcast_ref::<ModifiersChangedEvent>() else {
6087 return;
6088 };
6089 for node_id in dispatch_path.iter().rev() {
6090 let node = self.rendered_frame.dispatch_tree.node(*node_id);
6091 for listener in node.modifiers_changed_listeners.clone() {
6092 listener(event, self, cx);
6093 if !cx.propagate_event {
6094 return;
6095 }
6096 }
6097 }
6098 }
6099
6100 pub fn has_pending_keystrokes(&self) -> bool {
6102 self.pending_input().is_some()
6103 }
6104
6105 #[cfg(test)]
6106 pub(crate) fn pending_input_is_none(&self) -> bool {
6107 self.pending_input.is_none()
6108 }
6109
6110 pub(crate) fn clear_pending_keystrokes(&mut self, cx: &mut App) {
6111 if self.pending_input.take().is_some() {
6112 self.defer_pending_input_changed(cx);
6113 }
6114 }
6115
6116 pub fn pending_input(&self) -> Option<PendingInputStatus<'_>> {
6119 self.pending_input
6120 .as_ref()
6121 .filter(|pending_input| pending_input.focus == self.focus)
6122 .map(|pending_input| PendingInputStatus {
6123 keystrokes: pending_input.keystrokes.as_slice(),
6124 timeout: pending_input
6125 .timeout
6126 .as_ref()
6127 .map(PendingInputTimeout::status),
6128 })
6129 }
6130
6131 pub fn set_pending_input_timeout_paused<T: 'static>(
6136 &mut self,
6137 owner: &Entity<T>,
6138 paused: bool,
6139 cx: &mut App,
6140 ) -> bool {
6141 let owner_id = owner.entity_id();
6142 if !paused {
6143 return self.resume_pending_input_timeout(owner_id, cx);
6144 }
6145
6146 let timeout = self
6147 .pending_input
6148 .as_ref()
6149 .filter(|pending_input| pending_input.focus == self.focus)
6150 .and_then(|pending_input| pending_input.timeout.as_ref());
6151 let Some(timeout) = timeout else {
6152 return false;
6153 };
6154 if timeout.is_paused() {
6155 return false;
6156 }
6157
6158 let release_subscription = self.observe_release(owner, cx, move |_, window, cx| {
6159 window.resume_pending_input_timeout(owner_id, cx);
6160 });
6161 let now = cx.background_executor().now();
6162 let changed = self
6163 .pending_input
6164 .as_mut()
6165 .filter(|pending_input| pending_input.focus == self.focus)
6166 .and_then(|pending_input| pending_input.timeout.as_mut())
6167 .is_some_and(|timeout| {
6168 timeout.pause(
6169 PendingInputTimeoutPause {
6170 owner_id,
6171 _release_subscription: release_subscription,
6172 },
6173 now,
6174 )
6175 });
6176
6177 if changed {
6178 self.defer_pending_input_changed(cx);
6179 }
6180 changed
6181 }
6182
6183 fn resume_pending_input_timeout(&mut self, owner_id: EntityId, cx: &mut App) -> bool {
6184 let Some(remaining) = self
6185 .pending_input
6186 .as_ref()
6187 .and_then(|pending_input| pending_input.timeout.as_ref())
6188 .filter(|timeout| timeout.pause_owner_id() == Some(owner_id))
6189 .map(|timeout| timeout.remaining)
6190 else {
6191 return false;
6192 };
6193
6194 let (started_at, task) = self.start_pending_input_timeout(remaining, cx);
6195 let changed = self
6196 .pending_input
6197 .as_mut()
6198 .and_then(|pending_input| pending_input.timeout.as_mut())
6199 .is_some_and(|timeout| timeout.resume(owner_id, started_at, task));
6200
6201 if changed {
6202 self.defer_pending_input_changed(cx);
6203 }
6204 changed
6205 }
6206
6207 pub fn pending_input_keystrokes(&self) -> Option<&[Keystroke]> {
6209 self.pending_input()
6210 .map(|pending_input| pending_input.keystrokes())
6211 }
6212
6213 fn replay_pending_input(&mut self, replays: SmallVec<[Replay; 1]>, cx: &mut App) {
6214 let node_id = self.focus_node_id_in_rendered_frame(self.focus);
6215 let dispatch_path = self.rendered_frame.dispatch_tree.dispatch_path(node_id);
6216
6217 'replay: for replay in replays {
6218 let event = KeyDownEvent {
6219 keystroke: replay.keystroke.clone(),
6220 is_held: false,
6221 prefer_character_input: true,
6222 };
6223
6224 cx.propagate_event = true;
6225 for binding in replay.bindings {
6226 self.dispatch_action_on_node(node_id, binding.action.as_ref(), cx);
6227 if !cx.propagate_event {
6228 self.dispatch_keystroke_observers(
6229 &replay.keystroke,
6230 Some(binding.action.as_ref()),
6231 Vec::default(),
6232 cx,
6233 );
6234 continue 'replay;
6235 }
6236 }
6237
6238 self.dispatch_key_down_up_event(&event, &dispatch_path, cx);
6239 if !cx.propagate_event {
6240 continue 'replay;
6241 }
6242 if let Some(input) = replay.keystroke.key_char.as_ref().cloned()
6243 && let Some(mut input_handler) = self.platform_window.take_input_handler()
6244 {
6245 input_handler.dispatch_input(&input, self, cx);
6246 self.platform_window.set_input_handler(input_handler)
6247 }
6248 }
6249 }
6250
6251 fn focus_node_id_in_rendered_frame(&self, focus_id: Option<FocusId>) -> DispatchNodeId {
6252 focus_id
6253 .and_then(|focus_id| {
6254 self.rendered_frame
6255 .dispatch_tree
6256 .focusable_node_id(focus_id)
6257 })
6258 .unwrap_or_else(|| self.rendered_frame.dispatch_tree.root_node_id())
6259 }
6260
6261 fn dispatch_action_on_node(
6262 &mut self,
6263 node_id: DispatchNodeId,
6264 action: &dyn Action,
6265 cx: &mut App,
6266 ) {
6267 self.dispatch_action_on_node_inner(node_id, action, cx);
6268
6269 if !cx.propagate_event
6270 && cx.cursor_hide_mode == CursorHideMode::OnTypingAndAction
6271 && self.last_input_was_keyboard()
6272 {
6273 cx.platform.hide_cursor_until_mouse_moves();
6274 }
6275 }
6276
6277 fn dispatch_action_on_node_inner(
6278 &mut self,
6279 node_id: DispatchNodeId,
6280 action: &dyn Action,
6281 cx: &mut App,
6282 ) {
6283 let dispatch_path = self.rendered_frame.dispatch_tree.dispatch_path(node_id);
6284
6285 cx.propagate_event = true;
6287 if let Some(mut global_listeners) = cx
6288 .global_action_listeners
6289 .remove(&action.as_any().type_id())
6290 {
6291 for listener in &global_listeners {
6292 #[cfg(feature = "profiler")]
6293 self.window_profiler.begin_action_handler(action, cx);
6294 listener(action.as_any(), DispatchPhase::Capture, cx);
6295 #[cfg(feature = "profiler")]
6296 self.window_profiler.end_action_handler();
6297 if !cx.propagate_event {
6298 break;
6299 }
6300 }
6301
6302 global_listeners.extend(
6303 cx.global_action_listeners
6304 .remove(&action.as_any().type_id())
6305 .unwrap_or_default(),
6306 );
6307
6308 cx.global_action_listeners
6309 .insert(action.as_any().type_id(), global_listeners);
6310 }
6311
6312 if !cx.propagate_event {
6313 return;
6314 }
6315
6316 for node_id in &dispatch_path {
6318 let node = self.rendered_frame.dispatch_tree.node(*node_id);
6319 for DispatchActionListener {
6320 action_type,
6321 listener,
6322 } in node.action_listeners.clone()
6323 {
6324 let any_action = action.as_any();
6325 if action_type == any_action.type_id() {
6326 #[cfg(feature = "profiler")]
6327 self.window_profiler.begin_action_handler(action, cx);
6328 listener(any_action, DispatchPhase::Capture, self, cx);
6329 #[cfg(feature = "profiler")]
6330 self.window_profiler.end_action_handler();
6331
6332 if !cx.propagate_event {
6333 return;
6334 }
6335 }
6336 }
6337 }
6338
6339 for node_id in dispatch_path.iter().rev() {
6341 let node = self.rendered_frame.dispatch_tree.node(*node_id);
6342 for DispatchActionListener {
6343 action_type,
6344 listener,
6345 } in node.action_listeners.clone()
6346 {
6347 let any_action = action.as_any();
6348 if action_type == any_action.type_id() {
6349 cx.propagate_event = false; #[cfg(feature = "profiler")]
6351 self.window_profiler.begin_action_handler(action, cx);
6352 listener(any_action, DispatchPhase::Bubble, self, cx);
6353 #[cfg(feature = "profiler")]
6354 self.window_profiler.end_action_handler();
6355
6356 if !cx.propagate_event {
6357 return;
6358 }
6359 }
6360 }
6361 }
6362
6363 if let Some(mut global_listeners) = cx
6365 .global_action_listeners
6366 .remove(&action.as_any().type_id())
6367 {
6368 for listener in global_listeners.iter().rev() {
6369 cx.propagate_event = false; #[cfg(feature = "profiler")]
6372 self.window_profiler.begin_action_handler(action, cx);
6373 listener(action.as_any(), DispatchPhase::Bubble, cx);
6374 #[cfg(feature = "profiler")]
6375 self.window_profiler.end_action_handler();
6376 if !cx.propagate_event {
6377 break;
6378 }
6379 }
6380
6381 global_listeners.extend(
6382 cx.global_action_listeners
6383 .remove(&action.as_any().type_id())
6384 .unwrap_or_default(),
6385 );
6386
6387 cx.global_action_listeners
6388 .insert(action.as_any().type_id(), global_listeners);
6389 }
6390 }
6391
6392 pub fn observe_global<G: Global>(
6395 &mut self,
6396 cx: &mut App,
6397 f: impl Fn(&mut Window, &mut App) + 'static,
6398 ) -> Subscription {
6399 let window_handle = self.handle;
6400 let (subscription, activate) = cx.global_observers.insert(
6401 TypeId::of::<G>(),
6402 Box::new(move |cx| {
6403 window_handle
6404 .update(cx, |_, window, cx| f(window, cx))
6405 .is_ok()
6406 }),
6407 );
6408 cx.defer(move |_| activate());
6409 subscription
6410 }
6411
6412 pub fn activate_window(&self) {
6414 self.platform_window.activate();
6415 }
6416
6417 pub fn request_attention(&self) {
6419 self.platform_window.request_attention();
6420 }
6421
6422 pub fn minimize_window(&self) {
6424 self.platform_window.minimize();
6425 }
6426
6427 pub fn toggle_fullscreen(&self) {
6429 self.platform_window.toggle_fullscreen();
6430 }
6431
6432 pub fn toggle_simple_fullscreen(&self) {
6437 self.platform_window.toggle_simple_fullscreen();
6438 }
6439
6440 pub fn invalidate_character_coordinates(&self) {
6442 self.on_next_frame(|window, cx| {
6443 if let Some(mut input_handler) = window.platform_window.take_input_handler() {
6444 if let Some(bounds) = input_handler.selected_bounds(window, cx) {
6445 window.platform_window.update_ime_position(bounds);
6446 }
6447 window.platform_window.set_input_handler(input_handler);
6448 }
6449 });
6450 }
6451
6452 pub fn prompt<T>(
6456 &mut self,
6457 level: PromptLevel,
6458 message: &str,
6459 detail: Option<&str>,
6460 answers: &[T],
6461 cx: &mut App,
6462 ) -> oneshot::Receiver<usize>
6463 where
6464 T: Clone + Into<PromptButton>,
6465 {
6466 let prompt_builder = cx.prompt_builder.take();
6467 let Some(prompt_builder) = prompt_builder else {
6468 unreachable!("Re-entrant window prompting is not supported by GPUI");
6469 };
6470
6471 let answers = answers
6472 .iter()
6473 .map(|answer| answer.clone().into())
6474 .collect::<Vec<_>>();
6475
6476 let receiver = match &prompt_builder {
6477 PromptBuilder::Default => self
6478 .platform_window
6479 .prompt(level, message, detail, &answers)
6480 .unwrap_or_else(|| {
6481 self.build_custom_prompt(&prompt_builder, level, message, detail, &answers, cx)
6482 }),
6483 PromptBuilder::Custom(_) => {
6484 self.build_custom_prompt(&prompt_builder, level, message, detail, &answers, cx)
6485 }
6486 };
6487
6488 cx.prompt_builder = Some(prompt_builder);
6489
6490 receiver
6491 }
6492
6493 fn build_custom_prompt(
6494 &mut self,
6495 prompt_builder: &PromptBuilder,
6496 level: PromptLevel,
6497 message: &str,
6498 detail: Option<&str>,
6499 answers: &[PromptButton],
6500 cx: &mut App,
6501 ) -> oneshot::Receiver<usize> {
6502 let (sender, receiver) = oneshot::channel();
6503 let handle = PromptHandle::new(sender);
6504 let handle = (prompt_builder)(level, message, detail, answers, handle, self, cx);
6505 self.prompt = Some(handle);
6506 receiver
6507 }
6508
6509 pub fn has_active_prompt(&self) -> bool {
6514 self.prompt.is_some()
6515 }
6516
6517 pub fn context_stack(&self) -> Vec<KeyContext> {
6519 let node_id = self.focus_node_id_in_rendered_frame(self.focus);
6520 let dispatch_tree = &self.rendered_frame.dispatch_tree;
6521 dispatch_tree
6522 .dispatch_path(node_id)
6523 .iter()
6524 .filter_map(move |&node_id| dispatch_tree.node(node_id).context.clone())
6525 .collect()
6526 }
6527
6528 pub fn available_actions(&self, cx: &App) -> Vec<Box<dyn Action>> {
6530 let node_id = self.focus_node_id_in_rendered_frame(self.focus);
6531 let mut actions = self.rendered_frame.dispatch_tree.available_actions(node_id);
6532 for action_type in cx.global_action_listeners.keys() {
6533 if let Err(ix) = actions.binary_search_by_key(action_type, |a| a.as_any().type_id()) {
6534 let action = cx.actions.build_action_type(action_type).ok();
6535 if let Some(action) = action {
6536 actions.insert(ix, action);
6537 }
6538 }
6539 }
6540 actions
6541 }
6542
6543 pub fn bindings_for_action(&self, action: &dyn Action) -> Vec<KeyBinding> {
6546 self.rendered_frame
6547 .dispatch_tree
6548 .bindings_for_action(action, &self.rendered_frame.dispatch_tree.context_stack)
6549 }
6550
6551 pub fn highest_precedence_binding_for_action(&self, action: &dyn Action) -> Option<KeyBinding> {
6554 self.rendered_frame
6555 .dispatch_tree
6556 .highest_precedence_binding_for_action(
6557 action,
6558 &self.rendered_frame.dispatch_tree.context_stack,
6559 )
6560 }
6561
6562 pub fn bindings_for_action_in_context(
6564 &self,
6565 action: &dyn Action,
6566 context: KeyContext,
6567 ) -> Vec<KeyBinding> {
6568 let dispatch_tree = &self.rendered_frame.dispatch_tree;
6569 dispatch_tree.bindings_for_action(action, &[context])
6570 }
6571
6572 pub fn highest_precedence_binding_for_action_in_context(
6575 &self,
6576 action: &dyn Action,
6577 context: KeyContext,
6578 ) -> Option<KeyBinding> {
6579 let dispatch_tree = &self.rendered_frame.dispatch_tree;
6580 dispatch_tree.highest_precedence_binding_for_action(action, &[context])
6581 }
6582
6583 pub fn bindings_for_action_in(
6587 &self,
6588 action: &dyn Action,
6589 focus_handle: &FocusHandle,
6590 ) -> Vec<KeyBinding> {
6591 let dispatch_tree = &self.rendered_frame.dispatch_tree;
6592 let Some(context_stack) = self.context_stack_for_focus_handle(focus_handle) else {
6593 return vec![];
6594 };
6595 dispatch_tree.bindings_for_action(action, &context_stack)
6596 }
6597
6598 pub fn highest_precedence_binding_for_action_in(
6602 &self,
6603 action: &dyn Action,
6604 focus_handle: &FocusHandle,
6605 ) -> Option<KeyBinding> {
6606 let dispatch_tree = &self.rendered_frame.dispatch_tree;
6607 let context_stack = self.context_stack_for_focus_handle(focus_handle)?;
6608 dispatch_tree.highest_precedence_binding_for_action(action, &context_stack)
6609 }
6610
6611 pub fn possible_bindings_for_input(&self, input: &[Keystroke]) -> Vec<KeyBinding> {
6613 self.rendered_frame
6614 .dispatch_tree
6615 .possible_next_bindings_for_input(input, &self.context_stack())
6616 }
6617
6618 fn context_stack_for_focus_handle(
6619 &self,
6620 focus_handle: &FocusHandle,
6621 ) -> Option<Vec<KeyContext>> {
6622 let dispatch_tree = &self.rendered_frame.dispatch_tree;
6623 let node_id = dispatch_tree.focusable_node_id(focus_handle.id)?;
6624 let context_stack: Vec<_> = dispatch_tree
6625 .dispatch_path(node_id)
6626 .into_iter()
6627 .filter_map(|node_id| dispatch_tree.node(node_id).context.clone())
6628 .collect();
6629 Some(context_stack)
6630 }
6631
6632 pub fn listener_for<T: 'static, E>(
6634 &self,
6635 view: &Entity<T>,
6636 f: impl Fn(&mut T, &E, &mut Window, &mut Context<T>) + 'static,
6637 ) -> impl Fn(&E, &mut Window, &mut App) + 'static {
6638 let view = view.downgrade();
6639 move |e: &E, window: &mut Window, cx: &mut App| {
6640 view.update(cx, |view, cx| f(view, e, window, cx)).ok();
6641 }
6642 }
6643
6644 pub fn handler_for<E: 'static, Callback: Fn(&mut E, &mut Window, &mut Context<E>) + 'static>(
6646 &self,
6647 entity: &Entity<E>,
6648 f: Callback,
6649 ) -> impl Fn(&mut Window, &mut App) + 'static {
6650 let entity = entity.downgrade();
6651 move |window: &mut Window, cx: &mut App| {
6652 entity.update(cx, |entity, cx| f(entity, window, cx)).ok();
6653 }
6654 }
6655
6656 pub fn on_window_should_close(
6659 &self,
6660 cx: &App,
6661 f: impl Fn(&mut Window, &mut App) -> bool + 'static,
6662 ) {
6663 let mut cx = self.to_async(cx);
6664 self.platform_window.on_should_close(Box::new(move || {
6665 cx.update(|window, cx| f(window, cx)).unwrap_or(true)
6666 }))
6667 }
6668
6669 pub fn on_action(
6678 &mut self,
6679 action_type: TypeId,
6680 listener: impl Fn(&dyn Any, DispatchPhase, &mut Window, &mut App) + 'static,
6681 ) {
6682 self.invalidator.debug_assert_paint();
6683
6684 self.next_frame
6685 .dispatch_tree
6686 .on_action(action_type, Rc::new(listener));
6687 }
6688
6689 pub fn on_action_when(
6698 &mut self,
6699 condition: bool,
6700 action_type: TypeId,
6701 listener: impl Fn(&dyn Any, DispatchPhase, &mut Window, &mut App) + 'static,
6702 ) {
6703 self.invalidator.debug_assert_paint();
6704
6705 if condition {
6706 self.next_frame
6707 .dispatch_tree
6708 .on_action(action_type, Rc::new(listener));
6709 }
6710 }
6711
6712 pub fn gpu_specs(&self) -> Option<GpuSpecs> {
6715 self.platform_window.gpu_specs()
6716 }
6717
6718 pub fn titlebar_double_click(&self) {
6721 self.platform_window
6722 .titlebar_double_click(self.is_resizable, self.is_minimizable);
6723 }
6724
6725 pub fn window_title(&self) -> String {
6728 self.platform_window.get_title()
6729 }
6730
6731 pub fn tabbed_windows(&self) -> Option<Vec<SystemWindowTab>> {
6734 self.platform_window.tabbed_windows()
6735 }
6736
6737 pub fn tab_bar_visible(&self) -> bool {
6740 self.platform_window.tab_bar_visible()
6741 }
6742
6743 pub fn merge_all_windows(&self) {
6746 self.platform_window.merge_all_windows()
6747 }
6748
6749 pub fn move_tab_to_new_window(&self) {
6752 self.platform_window.move_tab_to_new_window()
6753 }
6754
6755 pub fn toggle_window_tab_overview(&self) {
6758 self.platform_window.toggle_window_tab_overview()
6759 }
6760
6761 pub fn set_tabbing_identifier(&self, tabbing_identifier: Option<String>) {
6764 self.platform_window
6765 .set_tabbing_identifier(tabbing_identifier)
6766 }
6767
6768 pub fn play_system_bell(&self) {
6771 self.platform_window.play_system_bell()
6772 }
6773
6774 pub fn is_a11y_enabled(&self) -> bool {
6781 self.a11y.is_enabled()
6782 }
6783
6784 pub fn is_a11y_active(&self) -> bool {
6795 self.a11y.is_active()
6796 }
6797
6798 pub fn debug_a11y_tree_json(&self) -> Option<String> {
6800 self.a11y.debug_tree_json()
6801 }
6802
6803 pub fn on_a11y_action(
6809 &mut self,
6810 node_id: accesskit::NodeId,
6811 action: accesskit::Action,
6812 listener: impl FnMut(Option<&accesskit::ActionData>, &mut Window, &mut App) + 'static,
6813 ) {
6814 self.a11y
6815 .action_listeners
6816 .entry(node_id)
6817 .or_default()
6818 .push((action, Box::new(listener)));
6819 }
6820
6821 #[cfg(not(target_family = "wasm"))]
6822 pub(crate) fn handle_a11y_action(&mut self, request: accesskit::ActionRequest, cx: &mut App) {
6823 if let Some(mut listeners) = self.a11y.action_listeners.remove(&request.target_node) {
6826 let extra_data = request.data.as_ref();
6827 let mut matched = false;
6828 for (action, listener) in &mut listeners {
6829 if *action == request.action {
6830 listener(extra_data, self, cx);
6831 matched = true;
6832 }
6833 }
6834 self.a11y
6835 .action_listeners
6836 .insert(request.target_node, listeners);
6837 if matched {
6838 return;
6839 }
6840 }
6841
6842 match request.action {
6844 accesskit::Action::Click => {
6845 if let Some(bounds) = self.a11y.node_bounds.get(&request.target_node).copied() {
6846 let center = bounds.center();
6847 let mouse_down = PlatformInput::MouseDown(crate::MouseDownEvent {
6848 button: MouseButton::Left,
6849 position: center,
6850 modifiers: Modifiers::default(),
6851 click_count: 1,
6852 first_mouse: false,
6853 });
6854 let mouse_up = PlatformInput::MouseUp(MouseUpEvent {
6855 button: MouseButton::Left,
6856 position: center,
6857 modifiers: Modifiers::default(),
6858 click_count: 1,
6859 });
6860 self.dispatch_event(mouse_down, cx);
6861 self.dispatch_event(mouse_up, cx);
6862 }
6863 }
6864 accesskit::Action::Focus => {
6865 if let Some(focus_id) = self.a11y.focus_ids.get(&request.target_node).copied()
6866 && let Some(handle) = FocusHandle::for_id(focus_id, &cx.focus_handles)
6867 {
6868 self.focus(&handle, cx);
6869 }
6870 }
6871 accesskit::Action::Blur => {
6872 self.blur(cx);
6873 }
6874 _ => {
6875 log::debug!(
6876 "Unhandled a11y action: {:?} on {:?}",
6877 request.action,
6878 request.target_node
6879 );
6880 }
6881 }
6882 }
6883
6884 #[cfg(any(feature = "inspector", debug_assertions))]
6886 pub fn toggle_inspector(&mut self, cx: &mut App) {
6887 self.inspector = match self.inspector {
6888 None => Some(cx.new(|_| Inspector::new())),
6889 Some(_) => {
6890 self.rendered_frame.next_inspector_instance_ids = FxHashMap::default();
6891 self.rendered_frame.inspector_hitboxes = FxHashMap::default();
6892 self.next_frame.next_inspector_instance_ids = FxHashMap::default();
6893 self.next_frame.inspector_hitboxes = FxHashMap::default();
6894 None
6895 }
6896 };
6897 self.refresh();
6898 }
6899
6900 pub fn is_inspector_picking(&self, _cx: &App) -> bool {
6902 #[cfg(any(feature = "inspector", debug_assertions))]
6903 {
6904 if let Some(inspector) = &self.inspector {
6905 return inspector.read(_cx).is_picking();
6906 }
6907 }
6908 false
6909 }
6910
6911 #[cfg(any(feature = "inspector", debug_assertions))]
6913 pub fn with_inspector_state<T: 'static, R>(
6914 &mut self,
6915 inspector_id: Option<&crate::InspectorElementId>,
6916 cx: &mut App,
6917 f: impl FnOnce(&mut Option<T>, &mut Self) -> R,
6918 ) -> Option<R> {
6919 let inspector_id = inspector_id?;
6920 let inspector = self.inspector.as_ref()?;
6921 if inspector.read(cx).active_element_id() != Some(inspector_id) {
6922 return None;
6923 }
6924 let inspector = inspector.clone();
6925 Some(inspector.update(cx, |inspector, _cx| {
6926 inspector.with_active_element_state(self, f)
6927 }))
6928 }
6929
6930 #[cfg(any(feature = "inspector", debug_assertions))]
6931 pub(crate) fn inspector_enabled(&self) -> bool {
6932 self.inspector.is_some()
6933 }
6934
6935 #[cfg(any(feature = "inspector", debug_assertions))]
6936 pub(crate) fn build_inspector_element_id(
6937 &mut self,
6938 path: crate::InspectorElementPath,
6939 ) -> crate::InspectorElementId {
6940 self.invalidator.debug_assert_paint_or_prepaint();
6941 let path = Rc::new(path);
6942 let next_instance_id = self
6943 .next_frame
6944 .next_inspector_instance_ids
6945 .entry(path.clone())
6946 .or_insert(0);
6947 let instance_id = *next_instance_id;
6948 *next_instance_id += 1;
6949 crate::InspectorElementId { path, instance_id }
6950 }
6951
6952 #[cfg(any(feature = "inspector", debug_assertions))]
6953 fn prepaint_inspector(&mut self, inspector_width: Pixels, cx: &mut App) -> Option<AnyElement> {
6954 if let Some(inspector) = self.inspector.take() {
6955 let mut inspector_element = AnyView::from(inspector.clone()).into_any_element();
6956 inspector_element.prepaint_as_root(
6957 point(self.viewport_size.width - inspector_width, px(0.0)),
6958 size(inspector_width, self.viewport_size.height).into(),
6959 self,
6960 cx,
6961 );
6962 self.inspector = Some(inspector);
6963 Some(inspector_element)
6964 } else {
6965 None
6966 }
6967 }
6968
6969 #[cfg(any(feature = "inspector", debug_assertions))]
6970 fn paint_inspector(&mut self, mut inspector_element: Option<AnyElement>, cx: &mut App) {
6971 if let Some(mut inspector_element) = inspector_element {
6972 inspector_element.paint(self, cx);
6973 };
6974 }
6975
6976 #[cfg(any(feature = "inspector", debug_assertions))]
6979 pub fn insert_inspector_hitbox(
6980 &mut self,
6981 hitbox_id: HitboxId,
6982 inspector_id: Option<&crate::InspectorElementId>,
6983 cx: &App,
6984 ) {
6985 self.invalidator.debug_assert_paint_or_prepaint();
6986 if !self.is_inspector_picking(cx) {
6987 return;
6988 }
6989 if let Some(inspector_id) = inspector_id {
6990 self.next_frame
6991 .inspector_hitboxes
6992 .insert(hitbox_id, inspector_id.clone());
6993 }
6994 }
6995
6996 #[cfg(any(feature = "inspector", debug_assertions))]
6997 fn paint_inspector_hitbox(&mut self, cx: &App) {
6998 if let Some(inspector) = self.inspector.as_ref() {
6999 let inspector = inspector.read(cx);
7000 if let Some((hitbox_id, _)) = self.hovered_inspector_hitbox(inspector, &self.next_frame)
7001 && let Some(hitbox) = self
7002 .next_frame
7003 .hitboxes
7004 .iter()
7005 .find(|hitbox| hitbox.id == hitbox_id)
7006 {
7007 self.paint_quad(crate::fill(hitbox.bounds, crate::rgba(0x61afef4d)));
7008 }
7009 }
7010 }
7011
7012 #[cfg(any(feature = "inspector", debug_assertions))]
7013 fn handle_inspector_mouse_event(&mut self, event: &dyn Any, cx: &mut App) {
7014 let Some(inspector) = self.inspector.clone() else {
7015 return;
7016 };
7017 if event.downcast_ref::<MouseMoveEvent>().is_some() {
7018 inspector.update(cx, |inspector, _cx| {
7019 if let Some((_, inspector_id)) =
7020 self.hovered_inspector_hitbox(inspector, &self.rendered_frame)
7021 {
7022 inspector.hover(inspector_id, self);
7023 }
7024 });
7025 } else if event.downcast_ref::<crate::MouseDownEvent>().is_some() {
7026 inspector.update(cx, |inspector, _cx| {
7027 if let Some((_, inspector_id)) =
7028 self.hovered_inspector_hitbox(inspector, &self.rendered_frame)
7029 {
7030 inspector.select(inspector_id, self);
7031 }
7032 });
7033 } else if let Some(event) = event.downcast_ref::<crate::ScrollWheelEvent>() {
7034 const SCROLL_LINES: f32 = 3.0;
7036 const SCROLL_PIXELS_PER_LAYER: f32 = 36.0;
7037 let delta_y = event
7038 .delta
7039 .pixel_delta(px(SCROLL_PIXELS_PER_LAYER / SCROLL_LINES))
7040 .y;
7041 if let Some(inspector) = self.inspector.clone() {
7042 inspector.update(cx, |inspector, _cx| {
7043 if let Some(depth) = inspector.pick_depth.as_mut() {
7044 *depth += f32::from(delta_y) / SCROLL_PIXELS_PER_LAYER;
7045 let max_depth = self.mouse_hit_test.ids.len() as f32 - 0.5;
7046 if *depth < 0.0 {
7047 *depth = 0.0;
7048 } else if *depth > max_depth {
7049 *depth = max_depth;
7050 }
7051 if let Some((_, inspector_id)) =
7052 self.hovered_inspector_hitbox(inspector, &self.rendered_frame)
7053 {
7054 inspector.set_active_element_id(inspector_id, self);
7055 }
7056 }
7057 });
7058 }
7059 }
7060 }
7061
7062 #[cfg(any(feature = "inspector", debug_assertions))]
7063 fn hovered_inspector_hitbox(
7064 &self,
7065 inspector: &Inspector,
7066 frame: &Frame,
7067 ) -> Option<(HitboxId, crate::InspectorElementId)> {
7068 if let Some(pick_depth) = inspector.pick_depth {
7069 let depth = (pick_depth as i64).try_into().unwrap_or(0);
7070 let max_skipped = self.mouse_hit_test.ids.len().saturating_sub(1);
7071 let skip_count = (depth as usize).min(max_skipped);
7072 for hitbox_id in self.mouse_hit_test.ids.iter().skip(skip_count) {
7073 if let Some(inspector_id) = frame.inspector_hitboxes.get(hitbox_id) {
7074 return Some((*hitbox_id, inspector_id.clone()));
7075 }
7076 }
7077 }
7078 None
7079 }
7080
7081 #[cfg(any(test, feature = "test-support"))]
7084 pub fn set_modifiers(&mut self, modifiers: Modifiers) {
7085 self.modifiers = modifiers;
7086 }
7087
7088 #[cfg(any(test, feature = "test-support"))]
7092 pub fn simulate_mouse_move(&mut self, position: Point<Pixels>, cx: &mut App) {
7093 let event = PlatformInput::MouseMove(MouseMoveEvent {
7094 position,
7095 modifiers: self.modifiers,
7096 pressed_button: None,
7097 });
7098 let _ = self.dispatch_event(event, cx);
7099 }
7100
7101 #[inline(never)]
7102 fn take_element_state(
7103 &mut self,
7104 global_id: &GlobalElementId,
7105 state_type: TypeId,
7106 ) -> ((GlobalElementId, TypeId), Option<ElementStateBox>) {
7107 let key = (global_id.clone(), state_type);
7108 self.next_frame.accessed_element_states.push(key.clone());
7109 let state = self
7110 .next_frame
7111 .element_states
7112 .remove(&key)
7113 .or_else(|| self.rendered_frame.element_states.remove(&key));
7114 (key, state)
7115 }
7116
7117 #[inline(never)]
7118 fn insert_element_state(
7119 &mut self,
7120 key: (GlobalElementId, TypeId),
7121 state: ElementStateBox,
7122 ) -> Option<ElementStateBox> {
7123 self.next_frame.element_states.insert(key, state)
7124 }
7125
7126 #[inline(never)]
7127 fn observe_keyed_state<S: 'static>(state: &Entity<S>, current_view: EntityId, cx: &mut App) {
7128 cx.observe(state, move |_, cx| {
7129 cx.notify(current_view);
7130 })
7131 .detach();
7132 }
7133}
7134
7135slotmap::new_key_type! {
7137 pub struct WindowId;
7139}
7140
7141impl WindowId {
7142 pub fn as_u64(&self) -> u64 {
7144 self.0.as_ffi()
7145 }
7146}
7147
7148impl From<u64> for WindowId {
7149 fn from(value: u64) -> Self {
7150 WindowId(slotmap::KeyData::from_ffi(value))
7151 }
7152}
7153
7154#[derive(Deref, DerefMut)]
7157pub struct WindowHandle<V> {
7158 #[deref]
7159 #[deref_mut]
7160 pub(crate) any_handle: AnyWindowHandle,
7161 state_type: PhantomData<fn(V) -> V>,
7162}
7163
7164impl<V> Debug for WindowHandle<V> {
7165 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
7166 f.debug_struct("WindowHandle")
7167 .field("any_handle", &self.any_handle.id.as_u64())
7168 .finish()
7169 }
7170}
7171
7172impl<V: 'static + Render> WindowHandle<V> {
7173 pub fn new(id: WindowId) -> Self {
7176 WindowHandle {
7177 any_handle: AnyWindowHandle {
7178 id,
7179 state_type: TypeId::of::<V>(),
7180 root_entity_type_name: std::any::type_name::<V>(),
7181 },
7182 state_type: PhantomData,
7183 }
7184 }
7185
7186 #[cfg(any(test, feature = "test-support"))]
7190 pub fn root<C>(&self, cx: &mut C) -> Result<Entity<V>>
7191 where
7192 C: AppContext,
7193 {
7194 cx.update_window(self.any_handle, |root_view, _, _| {
7195 root_view
7196 .downcast::<V>()
7197 .map_err(|_| anyhow!("the type of the window's root view has changed"))
7198 })?
7199 }
7200
7201 pub fn update<C, R>(
7205 &self,
7206 cx: &mut C,
7207 update: impl FnOnce(&mut V, &mut Window, &mut Context<V>) -> R,
7208 ) -> Result<R>
7209 where
7210 C: AppContext,
7211 {
7212 cx.update_window(self.any_handle, |root_view, window, cx| {
7213 let view = root_view
7214 .downcast::<V>()
7215 .map_err(|_| anyhow!("the type of the window's root view has changed"))?;
7216
7217 Ok(view.update(cx, |view, cx| update(view, window, cx)))
7218 })?
7219 }
7220
7221 pub fn read<'a>(&self, cx: &'a App) -> Result<&'a V> {
7225 let x = cx
7226 .windows
7227 .get(self.id)
7228 .and_then(|window| {
7229 window
7230 .as_deref()
7231 .and_then(|window| window.root.clone())
7232 .map(|root_view| root_view.downcast::<V>())
7233 })
7234 .context("window not found")?
7235 .map_err(|_| anyhow!("the type of the window's root view has changed"))?;
7236
7237 Ok(x.read(cx))
7238 }
7239
7240 pub fn read_with<C, R>(&self, cx: &C, read_with: impl FnOnce(&V, &App) -> R) -> Result<R>
7244 where
7245 C: AppContext,
7246 {
7247 cx.read_window(self, |root_view, cx| read_with(root_view.read(cx), cx))
7248 }
7249
7250 pub fn entity<C>(&self, cx: &C) -> Result<Entity<V>>
7254 where
7255 C: AppContext,
7256 {
7257 cx.read_window(self, |root_view, _cx| root_view)
7258 }
7259
7260 pub fn is_active(&self, cx: &mut App) -> Option<bool> {
7265 cx.update_window(self.any_handle, |_, window, _| window.is_window_active())
7266 .ok()
7267 }
7268}
7269
7270impl<V> Copy for WindowHandle<V> {}
7271
7272impl<V> Clone for WindowHandle<V> {
7273 fn clone(&self) -> Self {
7274 *self
7275 }
7276}
7277
7278impl<V> PartialEq for WindowHandle<V> {
7279 fn eq(&self, other: &Self) -> bool {
7280 self.any_handle == other.any_handle
7281 }
7282}
7283
7284impl<V> Eq for WindowHandle<V> {}
7285
7286impl<V> Hash for WindowHandle<V> {
7287 fn hash<H: Hasher>(&self, state: &mut H) {
7288 self.any_handle.hash(state);
7289 }
7290}
7291
7292impl<V: 'static> From<WindowHandle<V>> for AnyWindowHandle {
7293 fn from(val: WindowHandle<V>) -> Self {
7294 val.any_handle
7295 }
7296}
7297
7298#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
7300pub struct AnyWindowHandle {
7301 pub(crate) id: WindowId,
7302 state_type: TypeId,
7303 root_entity_type_name: &'static str,
7304}
7305
7306impl AnyWindowHandle {
7307 pub fn window_id(&self) -> WindowId {
7309 self.id
7310 }
7311
7312 pub fn root_entity_type_name(&self) -> &'static str {
7314 self.root_entity_type_name
7315 }
7316
7317 pub fn downcast<T: 'static>(&self) -> Option<WindowHandle<T>> {
7320 if TypeId::of::<T>() == self.state_type {
7321 Some(WindowHandle {
7322 any_handle: *self,
7323 state_type: PhantomData,
7324 })
7325 } else {
7326 None
7327 }
7328 }
7329
7330 pub fn update<C, R>(
7334 self,
7335 cx: &mut C,
7336 update: impl FnOnce(AnyView, &mut Window, &mut App) -> R,
7337 ) -> Result<R>
7338 where
7339 C: AppContext,
7340 {
7341 cx.update_window(self, update)
7342 }
7343
7344 pub fn read<T, C, R>(self, cx: &C, read: impl FnOnce(Entity<T>, &App) -> R) -> Result<R>
7348 where
7349 C: AppContext,
7350 T: 'static,
7351 {
7352 let view = self
7353 .downcast::<T>()
7354 .context("the type of the window's root view has changed")?;
7355
7356 cx.read_window(&view, read)
7357 }
7358}
7359
7360impl HasWindowHandle for Window {
7361 fn window_handle(&self) -> Result<raw_window_handle::WindowHandle<'_>, HandleError> {
7362 self.platform_window.window_handle()
7363 }
7364}
7365
7366impl HasDisplayHandle for Window {
7367 fn display_handle(
7368 &self,
7369 ) -> std::result::Result<raw_window_handle::DisplayHandle<'_>, HandleError> {
7370 self.platform_window.display_handle()
7371 }
7372}
7373
7374#[derive(Clone, Debug, Eq, PartialEq, Hash)]
7379pub enum ElementId {
7380 View(EntityId),
7382 Integer(u64),
7384 Name(SharedString),
7386 Uuid(Uuid),
7388 FocusHandle(FocusId),
7390 NamedInteger(SharedString, u64),
7392 Path(Arc<std::path::Path>),
7394 CodeLocation(core::panic::Location<'static>),
7396 NamedChild(Arc<ElementId>, SharedString),
7398 OpaqueId([u8; 20]),
7400}
7401
7402impl ElementId {
7403 pub fn named_usize(name: impl Into<SharedString>, integer: usize) -> ElementId {
7405 Self::NamedInteger(name.into(), integer as u64)
7406 }
7407}
7408
7409impl Display for ElementId {
7410 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
7411 match self {
7412 ElementId::View(entity_id) => write!(f, "view-{}", entity_id)?,
7413 ElementId::Integer(ix) => write!(f, "{}", ix)?,
7414 ElementId::Name(name) => write!(f, "{}", name)?,
7415 ElementId::FocusHandle(_) => write!(f, "FocusHandle")?,
7416 ElementId::NamedInteger(s, i) => write!(f, "{}-{}", s, i)?,
7417 ElementId::Uuid(uuid) => write!(f, "{}", uuid)?,
7418 ElementId::Path(path) => write!(f, "{}", path.display())?,
7419 ElementId::CodeLocation(location) => write!(f, "{}", location)?,
7420 ElementId::NamedChild(id, name) => write!(f, "{}-{}", id, name)?,
7421 ElementId::OpaqueId(opaque_id) => write!(f, "{:x?}", opaque_id)?,
7422 }
7423
7424 Ok(())
7425 }
7426}
7427
7428impl TryInto<SharedString> for ElementId {
7429 type Error = anyhow::Error;
7430
7431 fn try_into(self) -> anyhow::Result<SharedString> {
7432 if let ElementId::Name(name) = self {
7433 Ok(name)
7434 } else {
7435 anyhow::bail!("element id is not string")
7436 }
7437 }
7438}
7439
7440impl From<u64> for ElementId {
7441 fn from(id: u64) -> Self {
7442 ElementId::Integer(id)
7443 }
7444}
7445
7446impl From<usize> for ElementId {
7447 fn from(id: usize) -> Self {
7448 ElementId::Integer(id as u64)
7449 }
7450}
7451
7452impl From<i32> for ElementId {
7453 fn from(id: i32) -> Self {
7454 Self::Integer(id as u64)
7455 }
7456}
7457
7458impl From<SharedString> for ElementId {
7459 fn from(name: SharedString) -> Self {
7460 ElementId::Name(name)
7461 }
7462}
7463
7464impl From<String> for ElementId {
7465 fn from(name: String) -> Self {
7466 ElementId::Name(name.into())
7467 }
7468}
7469
7470impl From<Arc<str>> for ElementId {
7471 fn from(name: Arc<str>) -> Self {
7472 ElementId::Name(name.into())
7473 }
7474}
7475
7476impl From<Arc<std::path::Path>> for ElementId {
7477 fn from(path: Arc<std::path::Path>) -> Self {
7478 ElementId::Path(path)
7479 }
7480}
7481
7482impl From<&'static str> for ElementId {
7483 fn from(name: &'static str) -> Self {
7484 ElementId::Name(SharedString::new_static(name))
7485 }
7486}
7487
7488impl<'a> From<&'a FocusHandle> for ElementId {
7489 fn from(handle: &'a FocusHandle) -> Self {
7490 ElementId::FocusHandle(handle.id)
7491 }
7492}
7493
7494impl From<(&'static str, EntityId)> for ElementId {
7495 fn from((name, id): (&'static str, EntityId)) -> Self {
7496 ElementId::NamedInteger(SharedString::new_static(name), id.as_u64())
7497 }
7498}
7499
7500impl From<(&'static str, usize)> for ElementId {
7501 fn from((name, id): (&'static str, usize)) -> Self {
7502 ElementId::NamedInteger(SharedString::new_static(name), id as u64)
7503 }
7504}
7505
7506impl From<(SharedString, usize)> for ElementId {
7507 fn from((name, id): (SharedString, usize)) -> Self {
7508 ElementId::NamedInteger(name, id as u64)
7509 }
7510}
7511
7512impl From<(&'static str, u64)> for ElementId {
7513 fn from((name, id): (&'static str, u64)) -> Self {
7514 ElementId::NamedInteger(SharedString::new_static(name), id)
7515 }
7516}
7517
7518impl From<Uuid> for ElementId {
7519 fn from(value: Uuid) -> Self {
7520 Self::Uuid(value)
7521 }
7522}
7523
7524impl From<(&'static str, u32)> for ElementId {
7525 fn from((name, id): (&'static str, u32)) -> Self {
7526 ElementId::NamedInteger(SharedString::new_static(name), u64::from(id))
7527 }
7528}
7529
7530impl<T: Into<SharedString>> From<(ElementId, T)> for ElementId {
7531 fn from((id, name): (ElementId, T)) -> Self {
7532 ElementId::NamedChild(Arc::new(id), name.into())
7533 }
7534}
7535
7536impl From<&'static core::panic::Location<'static>> for ElementId {
7537 fn from(location: &'static core::panic::Location<'static>) -> Self {
7538 ElementId::CodeLocation(*location)
7539 }
7540}
7541
7542impl From<[u8; 20]> for ElementId {
7543 fn from(opaque_id: [u8; 20]) -> Self {
7544 ElementId::OpaqueId(opaque_id)
7545 }
7546}
7547
7548#[derive(Clone)]
7551pub struct PaintQuad {
7552 pub bounds: Bounds<Pixels>,
7554 pub corner_radii: Corners<Pixels>,
7556 pub background: Background,
7558 pub border_widths: Edges<Pixels>,
7560 pub border_color: Hsla,
7562 pub border_style: BorderStyle,
7564}
7565
7566impl PaintQuad {
7567 pub fn corner_radii(self, corner_radii: impl Into<Corners<Pixels>>) -> Self {
7569 PaintQuad {
7570 corner_radii: corner_radii.into(),
7571 ..self
7572 }
7573 }
7574
7575 pub fn border_widths(self, border_widths: impl Into<Edges<Pixels>>) -> Self {
7577 PaintQuad {
7578 border_widths: border_widths.into(),
7579 ..self
7580 }
7581 }
7582
7583 pub fn border_color(self, border_color: impl Into<Hsla>) -> Self {
7585 PaintQuad {
7586 border_color: border_color.into(),
7587 ..self
7588 }
7589 }
7590
7591 pub fn background(self, background: impl Into<Background>) -> Self {
7593 PaintQuad {
7594 background: background.into(),
7595 ..self
7596 }
7597 }
7598}
7599
7600pub fn quad(
7602 bounds: Bounds<Pixels>,
7603 corner_radii: impl Into<Corners<Pixels>>,
7604 background: impl Into<Background>,
7605 border_widths: impl Into<Edges<Pixels>>,
7606 border_color: impl Into<Hsla>,
7607 border_style: BorderStyle,
7608) -> PaintQuad {
7609 PaintQuad {
7610 bounds,
7611 corner_radii: corner_radii.into(),
7612 background: background.into(),
7613 border_widths: border_widths.into(),
7614 border_color: border_color.into(),
7615 border_style,
7616 }
7617}
7618
7619pub fn fill(bounds: impl Into<Bounds<Pixels>>, background: impl Into<Background>) -> PaintQuad {
7621 PaintQuad {
7622 bounds: bounds.into(),
7623 corner_radii: (0.).into(),
7624 background: background.into(),
7625 border_widths: (0.).into(),
7626 border_color: transparent_black(),
7627 border_style: BorderStyle::default(),
7628 }
7629}
7630
7631pub fn outline(
7633 bounds: impl Into<Bounds<Pixels>>,
7634 border_color: impl Into<Hsla>,
7635 border_style: BorderStyle,
7636) -> PaintQuad {
7637 PaintQuad {
7638 bounds: bounds.into(),
7639 corner_radii: (0.).into(),
7640 background: transparent_black().into(),
7641 border_widths: (1.).into(),
7642 border_color: border_color.into(),
7643 border_style,
7644 }
7645}
7646
7647#[inline(never)]
7648fn with_element_arena_erased(callback: &mut dyn FnMut(&mut Arena)) -> Result<(), AccessError> {
7649 if let Some(arena_pointer) = CURRENT_ELEMENT_ARENA.try_with(Cell::get)? {
7650 let arena_cell = unsafe { &*arena_pointer };
7653 callback(&mut arena_cell.borrow_mut());
7654 Ok(())
7655 } else {
7656 ELEMENT_ARENA.try_with(|arena| callback(&mut arena.borrow_mut()))
7657 }
7658}
7659
7660#[cfg(test)]
7661mod tests {
7662 use std::{
7663 cell::{Cell, RefCell},
7664 path::PathBuf,
7665 rc::Rc,
7666 time::Duration,
7667 };
7668
7669 use crate::{
7670 AnyWindowHandle, AppContext as _, Bounds, ContentMask, Context, DispatchPhase,
7671 DragMoveEvent, Empty, ExternalDragPayload, ExternalPaths, FileDragPaths, FileDropEvent,
7672 FocusHandle, InputEvent as _, InteractiveElement as _, IntoElement, KeyDownEvent,
7673 Keystroke, LongPressEvent, MouseButton, MouseDownEvent, MouseMoveEvent, ParentElement,
7674 Pixels, PlatformInput, Point, Render, RequestFrameOptions, ScaledPixels,
7675 StatefulInteractiveElement as _, Styled, TestAppContext, TouchDragEvent, TouchEvent,
7676 TouchId, TouchPhase, Underline, UnderlineStyle, Window, WindowAppearance, WindowOptions,
7677 canvas, div, hsla, point, px, size,
7678 };
7679
7680 #[gpui::test]
7684 fn test_window_visibility(cx: &mut TestAppContext) {
7685 use crate::WindowVisibility;
7686
7687 let window = cx.add_window(|_, _| EmptyView);
7688 let observed = Rc::new(RefCell::new(Vec::new()));
7689 let _subscription = window
7690 .update(cx, {
7691 let observed = observed.clone();
7692 move |_, window, _| {
7693 assert_eq!(window.visibility(), WindowVisibility::Visible);
7694 assert!(window.is_visible());
7695 window.observe_window_visibility(move |visibility, window, _| {
7696 assert_eq!(window.visibility(), visibility);
7697 observed.borrow_mut().push(visibility);
7698 })
7699 }
7700 })
7701 .unwrap();
7702 let test_window = cx.test_window(window.into());
7703 let frame_wake_count = test_window.frame_wake_count();
7704
7705 test_window.simulate_visibility_change(WindowVisibility::Hidden);
7706 assert_eq!(*observed.borrow(), [WindowVisibility::Hidden]);
7707 window
7708 .update(cx, |_, window, _| assert!(!window.is_visible()))
7709 .unwrap();
7710
7711 test_window.simulate_visibility_change(WindowVisibility::Hidden);
7713 assert_eq!(observed.borrow().len(), 1);
7714
7715 test_window.simulate_visibility_change(WindowVisibility::Visible);
7716 assert_eq!(
7717 *observed.borrow(),
7718 [WindowVisibility::Hidden, WindowVisibility::Visible]
7719 );
7720 window
7721 .update(cx, |_, window, _| assert!(window.is_visible()))
7722 .unwrap();
7723 assert_eq!(test_window.frame_wake_count(), frame_wake_count);
7724 }
7725
7726 #[gpui::test]
7727 fn test_fully_visible_bounds_preserve_layout_viewport(cx: &mut TestAppContext) {
7728 let window = cx.add_window(|_, _| EmptyView);
7729 let mut platform_window = cx.test_window(window.into());
7730 platform_window.simulate_resize(size(px(400.), px(800.)));
7731 window
7732 .update(cx, |_, window, _| {
7733 assert_eq!(
7734 window.visual_viewport_bounds(),
7735 Bounds::new(Point::default(), size(px(400.), px(800.)))
7736 );
7737 assert_eq!(
7738 window.fully_visible_bounds(),
7739 window.visual_viewport_bounds()
7740 );
7741 })
7742 .unwrap();
7743
7744 platform_window.simulate_frame_request(RequestFrameOptions::default());
7745 let wakes = platform_window.frame_wake_count();
7746 let visual_bounds = Bounds::new(point(px(10.), px(40.)), size(px(380.), px(460.)));
7747 platform_window.simulate_visual_viewport_change(visual_bounds);
7748 assert!(platform_window.frame_wake_count() > wakes);
7749 platform_window.simulate_frame_request(RequestFrameOptions::default());
7750 let wakes = platform_window.frame_wake_count();
7751 platform_window.simulate_insets_change(crate::WindowInsets {
7752 safe_area: crate::Edges {
7753 top: px(60.),
7754 right: px(20.),
7755 bottom: px(30.),
7756 left: px(-10.),
7757 },
7758 ime: crate::Edges {
7759 bottom: px(350.),
7760 ..Default::default()
7761 },
7762 });
7763 assert!(platform_window.frame_wake_count() > wakes);
7764 window
7765 .update(cx, |_, window, _| {
7766 assert_eq!(window.viewport_size(), size(px(400.), px(800.)));
7767 assert_eq!(window.visual_viewport_bounds(), visual_bounds);
7768 assert_eq!(
7769 window.fully_visible_bounds(),
7770 Bounds::new(point(px(10.), px(60.)), size(px(370.), px(390.)))
7771 );
7772 window.request_virtual_keyboard();
7773 window.dismiss_virtual_keyboard();
7774 assert_eq!(window.viewport_size(), size(px(400.), px(800.)));
7775 })
7776 .unwrap();
7777 assert_eq!(platform_window.virtual_keyboard_requests(), 1);
7778 assert_eq!(platform_window.virtual_keyboard_dismissals(), 1);
7779
7780 platform_window.simulate_insets_change(crate::WindowInsets {
7781 safe_area: crate::Edges {
7782 top: px(900.),
7783 left: px(500.),
7784 ..Default::default()
7785 },
7786 ..Default::default()
7787 });
7788 window
7789 .update(cx, |_, window, _| {
7790 assert_eq!(
7791 window.fully_visible_bounds().size,
7792 size(Pixels::ZERO, Pixels::ZERO)
7793 );
7794 })
7795 .unwrap();
7796 }
7797
7798 struct EmptyView;
7799
7800 impl Render for EmptyView {
7801 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
7802 div()
7803 }
7804 }
7805
7806 struct OpensWindowOnPaint {
7807 opened: Rc<Cell<bool>>,
7808 }
7809
7810 impl Render for OpensWindowOnPaint {
7811 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
7812 let opened = self.opened.clone();
7813 div()
7814 .size_full()
7815 .child(canvas(
7816 |_, _, _| {},
7817 move |_, _, _window, cx| {
7818 if !opened.replace(true) {
7819 cx.open_window(WindowOptions::default(), |_, cx| cx.new(|_| EmptyView))
7820 .unwrap();
7821 }
7822 },
7823 ))
7824 .child(div().child("after"))
7828 }
7829 }
7830
7831 #[test]
7837 fn test_window_opened_during_draw_defers_arena_clear() {
7838 let mut cx = TestAppContext::single();
7839
7840 let opened = Rc::new(Cell::new(false));
7841 let window = cx.add_window({
7843 let opened = opened.clone();
7844 move |_, _| OpensWindowOnPaint { opened }
7845 });
7846
7847 assert!(opened.get());
7848 assert_eq!(cx.windows().len(), 2);
7849
7850 cx.update_window(window.into(), |_, window, cx| window.draw(cx).clear(cx))
7853 .unwrap();
7854 }
7855
7856 #[test]
7857 fn test_scale_factor_change_preserves_bounds_and_survives_resize() {
7858 let mut cx = TestAppContext::single();
7859 let window = cx.add_window(|_, _| EmptyView);
7860 let handle: AnyWindowHandle = window.into();
7861 let window_state = |cx: &mut TestAppContext| {
7862 cx.update_window(handle, |_, window, _| {
7863 (
7864 window.scale_factor(),
7865 window.bounds(),
7866 window.viewport_size(),
7867 )
7868 })
7869 .unwrap()
7870 };
7871
7872 let (scale_factor, mut expected_bounds, _) = window_state(&mut cx);
7873 assert_eq!(scale_factor, 2.0);
7874
7875 for (scale_factor, resized_size) in [
7876 (1.0, size(px(800.), px(600.))),
7877 (1.25, size(px(640.), px(480.))),
7878 (2.0, size(px(1024.), px(768.))),
7879 ] {
7880 cx.simulate_window_scale_factor_change(handle, scale_factor);
7881 assert_eq!(
7882 window_state(&mut cx),
7883 (scale_factor, expected_bounds, expected_bounds.size)
7884 );
7885
7886 cx.simulate_window_resize(handle, resized_size);
7887 expected_bounds.size = resized_size;
7888 assert_eq!(
7889 window_state(&mut cx),
7890 (scale_factor, expected_bounds, resized_size)
7891 );
7892 }
7893 }
7894
7895 #[gpui::test]
7900 fn test_frame_waker_fires_on_frame_demand(cx: &mut TestAppContext) {
7901 let window = cx.add_window(|_, _| EmptyView);
7902 let test_window = cx.test_window(window.into());
7903
7904 assert!(
7908 test_window.frame_wake_count() >= 1,
7909 "opening a window must wake the frame source for the initial frame"
7910 );
7911
7912 test_window.simulate_frame_request(RequestFrameOptions::default());
7914
7915 let baseline = test_window.frame_wake_count();
7918 test_window.simulate_frame_request(RequestFrameOptions::default());
7919 window.update(cx, |_, _, _| {}).unwrap();
7920 assert_eq!(
7921 test_window.frame_wake_count(),
7922 baseline,
7923 "clean frames and non-notifying updates must not wake the frame source"
7924 );
7925
7926 window.update(cx, |_, _, cx| cx.notify()).unwrap();
7928 assert!(
7929 test_window.frame_wake_count() > baseline,
7930 "notifying a view in an idle window must wake the frame source"
7931 );
7932
7933 test_window.simulate_frame_request(RequestFrameOptions::default());
7935 let baseline = test_window.frame_wake_count();
7936 test_window.simulate_frame_request(RequestFrameOptions::default());
7937 assert_eq!(
7938 test_window.frame_wake_count(),
7939 baseline,
7940 "serving demand must return the window to idle"
7941 );
7942
7943 window
7945 .update(cx, |_, window, _| window.on_next_frame(|_, _| {}))
7946 .unwrap();
7947 assert!(
7948 test_window.frame_wake_count() > baseline,
7949 "scheduling a next-frame callback in an idle window must wake the frame source"
7950 );
7951 }
7952
7953 #[gpui::test]
7958 fn test_pending_next_frame_callbacks_are_not_stranded(cx: &mut TestAppContext) {
7959 let window = cx.add_window(|_, _| EmptyView);
7960 let test_window = cx.test_window(window.into());
7961 test_window.simulate_frame_request(RequestFrameOptions::default());
7964
7965 let callback_ran = Rc::new(Cell::new(false));
7966 window
7967 .update(cx, {
7968 let callback_ran = callback_ran.clone();
7969 move |_, window, _| {
7970 window.on_next_frame(move |_, _| callback_ran.set(true));
7971 }
7972 })
7973 .unwrap();
7974
7975 let baseline = test_window.frame_wake_count();
7976 test_window.simulate_frame_request(RequestFrameOptions::default());
7977 assert!(
7984 test_window.frame_wake_count() > baseline || callback_ran.get(),
7985 "a frame request with pending next-frame callbacks must either run them or re-arm the frame source"
7986 );
7987 }
7988
7989 #[gpui::test]
7990 fn test_window_reports_no_raw_handle_instead_of_panicking(cx: &mut TestAppContext) {
7991 use raw_window_handle::{HandleError, HasDisplayHandle as _, HasWindowHandle as _};
7992
7993 let window = cx.add_window(|_, _| EmptyView);
7994 window
7995 .update(cx, |_, window, _| {
7996 assert!(matches!(
7997 window.window_handle(),
7998 Err(HandleError::NotSupported)
7999 ));
8000 assert!(matches!(
8001 window.display_handle(),
8002 Err(HandleError::NotSupported)
8003 ));
8004 })
8005 .unwrap();
8006 }
8007
8008 #[gpui::test]
8009 fn test_appearance_change_runs_after_app_update(cx: &mut TestAppContext) {
8010 let window = cx.add_window(|_, _| EmptyView);
8011 let observed_appearance = Rc::new(Cell::new(None));
8012 let _subscription = window
8013 .update(cx, {
8014 let observed_appearance = observed_appearance.clone();
8015 move |_, window, _| {
8016 window.observe_window_appearance(move |window, _| {
8017 observed_appearance.set(Some(window.appearance()));
8018 })
8019 }
8020 })
8021 .unwrap();
8022 let test_window = cx.test_window(window.into());
8023
8024 cx.update(|_| {
8025 test_window.simulate_appearance_change(WindowAppearance::Dark);
8026 assert_eq!(observed_appearance.get(), None);
8027 });
8028 cx.run_until_parked();
8029
8030 assert_eq!(observed_appearance.get(), Some(WindowAppearance::Dark));
8031 }
8032
8033 #[gpui::test]
8034 fn queued_frame_callback_wakes_a_parked_render_loop(cx: &mut TestAppContext) {
8035 let window = cx.add_window(|_, _| Empty);
8036 let test_window = cx.test_window(window.into());
8037
8038 assert!(test_window.simulate_scheduled_frame());
8039 assert!(test_window.simulate_scheduled_frame());
8040 assert!(!test_window.frame_scheduled());
8041
8042 cx.update_window(window.into(), |_, window, _| {
8043 window.active.set(true);
8044 window.on_next_frame(|_, _| {});
8045 })
8046 .unwrap();
8047 assert!(
8048 test_window.frame_scheduled(),
8049 "queuing work on a parked window must wake the render loop"
8050 );
8051
8052 assert!(test_window.simulate_scheduled_frame());
8053 assert!(
8054 test_window.frame_scheduled(),
8055 "presenting the frame must await one compositor callback"
8056 );
8057 assert!(test_window.simulate_scheduled_frame());
8058 assert!(!test_window.frame_scheduled());
8059 }
8060
8061 #[gpui::test]
8062 fn pending_presentation_wakes_a_parked_render_loop(cx: &mut TestAppContext) {
8063 let window = cx.add_window(|_, _| Empty);
8064 let test_window = cx.test_window(window.into());
8065
8066 assert!(test_window.simulate_scheduled_frame());
8067 assert!(test_window.simulate_scheduled_frame());
8068 assert!(!test_window.frame_scheduled());
8069
8070 cx.update_window(window.into(), |_, window, cx| window.draw(cx).clear(cx))
8071 .unwrap();
8072
8073 assert!(
8074 test_window.frame_scheduled(),
8075 "a rendered scene awaiting presentation must wake the render loop"
8076 );
8077 }
8078
8079 #[gpui::test]
8080 fn callback_queued_during_a_frame_requests_a_follow_up(cx: &mut TestAppContext) {
8081 let window = cx.add_window(|_, _| Empty);
8082 let test_window = cx.test_window(window.into());
8083
8084 let callback_ran = Rc::new(Cell::new(false));
8085 cx.update_window(window.into(), |_, window, _| {
8086 window.active.set(true);
8089 let callback_ran = callback_ran.clone();
8090 window.on_next_frame(move |window, _| {
8091 window.on_next_frame(move |_, _| callback_ran.set(true));
8092 });
8093 })
8094 .unwrap();
8095
8096 assert!(test_window.simulate_scheduled_frame());
8097 assert!(!callback_ran.get());
8098 assert!(
8099 test_window.frame_scheduled(),
8100 "a callback queued mid-frame must schedule a follow-up before the loop parks"
8101 );
8102
8103 assert!(test_window.simulate_scheduled_frame());
8104 assert!(callback_ran.get());
8105 }
8106
8107 struct RootView {
8108 explicit_size: bool,
8109 child_bounds: Rc<Cell<Bounds<Pixels>>>,
8110 }
8111
8112 impl Render for RootView {
8113 fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
8114 let child_bounds = self.child_bounds.clone();
8115 let root = div().flex().flex_col().child(
8116 canvas(
8117 move |bounds, _, _| child_bounds.set(bounds),
8118 |_, _, _, _| {},
8119 )
8120 .size_full(),
8121 );
8122 if self.explicit_size {
8123 root.w(px(300.)).h(px(200.))
8124 } else {
8125 root
8126 }
8127 }
8128 }
8129
8130 #[test]
8131 fn auto_sized_window_root_fills_the_window() {
8132 let mut cx = TestAppContext::single();
8133 let child_bounds = Rc::new(Cell::new(Bounds::default()));
8134 let window = cx.add_window({
8135 let child_bounds = child_bounds.clone();
8136 move |_, _| RootView {
8137 explicit_size: false,
8138 child_bounds,
8139 }
8140 });
8141
8142 let viewport_size = cx
8143 .update_window(window.into(), |_, window, cx| {
8144 window.draw(cx).clear(cx);
8145 window.viewport_size()
8146 })
8147 .unwrap();
8148
8149 assert_eq!(child_bounds.get().size, viewport_size);
8150 }
8151
8152 #[test]
8153 fn explicitly_sized_window_root_keeps_its_size() {
8154 let mut cx = TestAppContext::single();
8155 let child_bounds = Rc::new(Cell::new(Bounds::default()));
8156 let window = cx.add_window({
8157 let child_bounds = child_bounds.clone();
8158 move |_, _| RootView {
8159 explicit_size: true,
8160 child_bounds,
8161 }
8162 });
8163
8164 cx.update_window(window.into(), |_, window, cx| {
8165 window.draw(cx).clear(cx);
8166 })
8167 .unwrap();
8168
8169 assert_eq!(child_bounds.get().size, size(px(300.), px(200.)));
8170 }
8171
8172 struct FileDragView {
8173 path: PathBuf,
8174 observed_drag_moves: Rc<RefCell<Vec<Point<Pixels>>>>,
8175 observed_drops: Rc<RefCell<Vec<PathBuf>>>,
8176 }
8177
8178 struct FileDropExitView(Rc<Cell<usize>>);
8179
8180 impl Render for FileDropExitView {
8181 fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
8182 div().size_full().on_file_drop_exit({
8183 let observed_file_drop_exit = self.0.clone();
8184 move |_, _, _| observed_file_drop_exit.set(observed_file_drop_exit.get() + 1)
8185 })
8186 }
8187 }
8188
8189 impl Render for FileDragView {
8190 fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
8191 div()
8192 .id("file-drag")
8193 .size_full()
8194 .on_drag(self.path.clone(), |_, _, _, cx| cx.new(|_| Empty))
8195 .external_drag_payload(|path: &PathBuf, _, _| {
8196 Some(ExternalDragPayload::Files(FileDragPaths::new([(
8197 path.clone(),
8198 true,
8199 )])))
8200 })
8201 .on_drag_move({
8202 let observed_drag_moves = self.observed_drag_moves.clone();
8203 move |event: &DragMoveEvent<PathBuf>, _, _| {
8204 observed_drag_moves.borrow_mut().push(event.event.position);
8205 }
8206 })
8207 .on_drop({
8208 let observed_drops = self.observed_drops.clone();
8209 move |path: &PathBuf, _, _| observed_drops.borrow_mut().push(path.clone())
8210 })
8211 }
8212 }
8213
8214 #[gpui::test]
8215 fn file_drag_is_promoted_once_and_restored_in_source_window(cx: &mut TestAppContext) {
8216 struct Drag {
8217 window: AnyWindowHandle,
8218 observed_drag_moves: Rc<RefCell<Vec<Point<Pixels>>>>,
8219 observed_drops: Rc<RefCell<Vec<PathBuf>>>,
8220 }
8221
8222 fn start_drag(cx: &mut TestAppContext, path: PathBuf, platform_result: bool) -> Drag {
8223 let observed_drag_moves = Rc::new(RefCell::new(Vec::new()));
8224 let observed_drops = Rc::new(RefCell::new(Vec::new()));
8225 let window: AnyWindowHandle = cx
8226 .add_window({
8227 let observed_drag_moves = observed_drag_moves.clone();
8228 let observed_drops = observed_drops.clone();
8229 move |_, _| FileDragView {
8230 path,
8231 observed_drag_moves,
8232 observed_drops,
8233 }
8234 })
8235 .into();
8236 cx.test_window(window)
8237 .set_start_external_drag_result(platform_result);
8238
8239 let update_result = cx.update_window(window, |_, window, cx| {
8240 window.draw(cx).clear(cx);
8241 window.dispatch_event(
8242 MouseDownEvent {
8243 position: point(px(10.), px(10.)),
8244 button: MouseButton::Left,
8245 modifiers: Default::default(),
8246 click_count: 1,
8247 first_mouse: false,
8248 }
8249 .to_platform_input(),
8250 cx,
8251 );
8252 window.dispatch_event(
8253 MouseMoveEvent {
8254 position: point(px(20.), px(20.)),
8255 pressed_button: Some(MouseButton::Left),
8256 modifiers: Default::default(),
8257 }
8258 .to_platform_input(),
8259 cx,
8260 );
8261 assert!(cx.active_drag.is_some());
8262 });
8263 assert!(
8264 update_result.is_ok(),
8265 "failed to start drag: {update_result:?}"
8266 );
8267
8268 assert!(cx.test_window(window).external_drag_files().is_empty());
8269 Drag {
8270 window,
8271 observed_drag_moves,
8272 observed_drops,
8273 }
8274 }
8275
8276 let successful_path = PathBuf::from("/tmp/successful-drag");
8277 let successful = start_drag(cx, successful_path.clone(), true);
8278 let outside_position = point(px(-1.), px(20.));
8279 let update_result = cx.update_window(successful.window, |_, window, cx| {
8280 window.dispatch_event(
8281 MouseMoveEvent {
8282 position: outside_position,
8283 pressed_button: Some(MouseButton::Left),
8284 modifiers: Default::default(),
8285 }
8286 .to_platform_input(),
8287 cx,
8288 );
8289 assert!(cx.active_drag.is_none());
8290 });
8291 assert!(
8292 update_result.is_ok(),
8293 "failed to promote drag: {update_result:?}"
8294 );
8295 assert_eq!(
8296 cx.test_window(successful.window).external_drag_files(),
8297 [(successful_path.clone(), true)]
8298 );
8299 assert_eq!(
8302 successful.observed_drag_moves.borrow().last(),
8303 Some(&outside_position)
8304 );
8305
8306 let first_destination_exit_count = Rc::new(Cell::new(0));
8307 let first_destination: AnyWindowHandle = cx
8308 .add_window({
8309 let first_destination_exit_count = first_destination_exit_count.clone();
8310 move |_, _| FileDropExitView(first_destination_exit_count)
8311 })
8312 .into();
8313 let second_destination_exit_count = Rc::new(Cell::new(0));
8314 let second_destination: AnyWindowHandle = cx
8315 .add_window({
8316 let second_destination_exit_count = second_destination_exit_count.clone();
8317 move |_, _| FileDropExitView(second_destination_exit_count)
8318 })
8319 .into();
8320 let reentry_position = point(px(30.), px(30.));
8321 let external_paths = || ExternalPaths([successful_path.clone()].into_iter().collect());
8322 let update_result = cx.update_window(first_destination, |_, window, cx| {
8323 window.draw(cx).clear(cx);
8324 window.dispatch_event(
8325 FileDropEvent::Entered {
8326 position: reentry_position,
8327 paths: external_paths(),
8328 }
8329 .to_platform_input(),
8330 cx,
8331 );
8332 assert!(
8333 cx.active_drag
8334 .as_ref()
8335 .is_some_and(|drag| drag.value.downcast_ref::<ExternalPaths>().is_some())
8336 );
8337 window.dispatch_event(FileDropEvent::Exited.to_platform_input(), cx);
8338 assert!(cx.active_drag.is_none());
8339 assert_eq!(first_destination_exit_count.get(), 1);
8340 assert_eq!(second_destination_exit_count.get(), 0);
8341 });
8342 assert!(
8343 update_result.is_ok(),
8344 "failed to handle drag in first destination window: {update_result:?}"
8345 );
8346
8347 let update_result = cx.update_window(second_destination, |_, window, cx| {
8348 window.draw(cx).clear(cx);
8349 window.dispatch_event(
8350 PlatformInput::KeyDown(KeyDownEvent {
8351 keystroke: Keystroke::parse("down").expect("valid keystroke"),
8352 is_held: false,
8353 prefer_character_input: false,
8354 }),
8355 cx,
8356 );
8357 window.dispatch_event(
8358 FileDropEvent::Entered {
8359 position: reentry_position,
8360 paths: external_paths(),
8361 }
8362 .to_platform_input(),
8363 cx,
8364 );
8365 assert!(
8366 cx.active_drag
8367 .as_ref()
8368 .is_some_and(|drag| drag.value.downcast_ref::<ExternalPaths>().is_some())
8369 );
8370 assert_eq!(first_destination_exit_count.get(), 1);
8371 assert_eq!(second_destination_exit_count.get(), 0);
8372
8373 window.dispatch_event(FileDropEvent::Exited.to_platform_input(), cx);
8374 assert!(cx.active_drag.is_none());
8375 assert_eq!(first_destination_exit_count.get(), 1);
8376 assert_eq!(second_destination_exit_count.get(), 1);
8377 });
8378 assert!(
8379 update_result.is_ok(),
8380 "failed to handle drag in second destination window: {update_result:?}"
8381 );
8382
8383 let update_result = cx.update_window(successful.window, |_, window, cx| {
8384 window.dispatch_event(
8385 FileDropEvent::Entered {
8386 position: reentry_position,
8387 paths: external_paths(),
8388 }
8389 .to_platform_input(),
8390 cx,
8391 );
8392 assert!(
8393 cx.active_drag
8394 .as_ref()
8395 .is_some_and(|drag| drag.value.downcast_ref::<PathBuf>().is_some())
8396 );
8397 assert_eq!(
8398 successful.observed_drag_moves.borrow().last(),
8399 Some(&reentry_position)
8400 );
8401
8402 window.dispatch_event(FileDropEvent::Exited.to_platform_input(), cx);
8403 assert!(cx.active_drag.is_none());
8404
8405 window.dispatch_event(
8406 FileDropEvent::Entered {
8407 position: reentry_position,
8408 paths: external_paths(),
8409 }
8410 .to_platform_input(),
8411 cx,
8412 );
8413 assert!(
8414 cx.active_drag
8415 .as_ref()
8416 .is_some_and(|drag| drag.value.downcast_ref::<PathBuf>().is_some())
8417 );
8418
8419 window.dispatch_event(
8420 FileDropEvent::Submit {
8421 position: reentry_position,
8422 }
8423 .to_platform_input(),
8424 cx,
8425 );
8426 assert_eq!(
8427 successful.observed_drops.borrow().as_slice(),
8428 std::slice::from_ref(&successful_path)
8429 );
8430 assert!(cx.active_drag.is_none());
8431
8432 window.dispatch_event(FileDropEvent::Exited.to_platform_input(), cx);
8433 assert!(cx.active_drag.is_none());
8434 window.dispatch_event(FileDropEvent::Ended.to_platform_input(), cx);
8435 assert!(cx.active_drag.is_none());
8436
8437 window.dispatch_event(
8438 FileDropEvent::Entered {
8439 position: reentry_position,
8440 paths: external_paths(),
8441 }
8442 .to_platform_input(),
8443 cx,
8444 );
8445 assert!(
8446 cx.active_drag
8447 .as_ref()
8448 .is_some_and(|drag| drag.value.downcast_ref::<ExternalPaths>().is_some())
8449 );
8450 window.dispatch_event(FileDropEvent::Exited.to_platform_input(), cx);
8451 });
8452 assert!(
8453 update_result.is_ok(),
8454 "failed to restore drag in source window: {update_result:?}"
8455 );
8456
8457 let cancelled_path = PathBuf::from("/tmp/cancelled-drag");
8458 let cancelled = start_drag(cx, cancelled_path.clone(), true);
8459 let update_result = cx.update_window(cancelled.window, |_, window, cx| {
8460 window.dispatch_event(
8461 MouseMoveEvent {
8462 position: outside_position,
8463 pressed_button: Some(MouseButton::Left),
8464 modifiers: Default::default(),
8465 }
8466 .to_platform_input(),
8467 cx,
8468 );
8469 assert!(cx.active_drag.is_none());
8470
8471 window.dispatch_event(
8472 FileDropEvent::Entered {
8473 position: reentry_position,
8474 paths: ExternalPaths([cancelled_path].into_iter().collect()),
8475 }
8476 .to_platform_input(),
8477 cx,
8478 );
8479 assert!(
8480 cx.active_drag
8481 .as_ref()
8482 .is_some_and(|drag| drag.value.downcast_ref::<PathBuf>().is_some())
8483 );
8484 assert!(cx.stop_active_drag(window));
8485 assert!(cx.active_drag.is_none());
8486 });
8487 assert!(
8488 update_result.is_ok(),
8489 "failed to cancel restored drag: {update_result:?}"
8490 );
8491 assert!(!cx.update(|cx| cx.end_platform_drag(cancelled.window.window_id())));
8492
8493 let removed_path = PathBuf::from("/tmp/removed-window-drag");
8494 let removed = start_drag(cx, removed_path, true);
8495 let removed_window_id = removed.window.window_id();
8496 let update_result = cx.update_window(removed.window, |_, window, cx| {
8497 window.dispatch_event(
8498 MouseMoveEvent {
8499 position: outside_position,
8500 pressed_button: Some(MouseButton::Left),
8501 modifiers: Default::default(),
8502 }
8503 .to_platform_input(),
8504 cx,
8505 );
8506 assert!(cx.active_drag.is_none());
8507 window.remove_window();
8508 });
8509 assert!(
8510 update_result.is_ok(),
8511 "failed to remove drag source window: {update_result:?}"
8512 );
8513 assert!(!cx.update(|cx| cx.end_platform_drag(removed_window_id)));
8514
8515 let failed_path = PathBuf::from("/tmp/failed-drag");
8516 let failed = start_drag(cx, failed_path.clone(), false);
8517 let update_result = cx.update_window(failed.window, |_, window, cx| {
8518 for x_position in [-1., -2.] {
8519 window.dispatch_event(
8520 MouseMoveEvent {
8521 position: point(px(x_position), px(20.)),
8522 pressed_button: Some(MouseButton::Left),
8523 modifiers: Default::default(),
8524 }
8525 .to_platform_input(),
8526 cx,
8527 );
8528 }
8529 assert!(cx.active_drag.is_some());
8530 });
8531 assert!(
8532 update_result.is_ok(),
8533 "failed to retain drag after platform failure: {update_result:?}"
8534 );
8535 assert_eq!(
8536 cx.test_window(failed.window).external_drag_files(),
8537 [(failed_path, true)]
8538 );
8539 }
8540
8541 struct FocusForwarder {
8542 a: FocusHandle,
8543 b: FocusHandle,
8544 }
8545
8546 impl Render for FocusForwarder {
8547 fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
8548 div()
8549 .size_full()
8550 .child(div().w(px(50.)).h(px(50.)).track_focus(&self.a))
8551 .child(div().w(px(50.)).h(px(50.)).track_focus(&self.b))
8552 }
8553 }
8554
8555 #[gpui::test]
8559 fn test_focus_moved_by_focus_listener_is_dispatched(cx: &mut TestAppContext) {
8560 let b_focus_count = Rc::new(Cell::new(0));
8561 let window = cx.add_window({
8562 let b_focus_count = b_focus_count.clone();
8563 move |window, cx| {
8564 let a = cx.focus_handle();
8565 let b = cx.focus_handle();
8566 cx.on_focus(&a, window, |this: &mut FocusForwarder, window, cx| {
8567 let b = this.b.clone();
8568 window.focus(&b, cx);
8569 })
8570 .detach();
8571 cx.on_focus(&b, window, move |_, _, _| {
8572 b_focus_count.set(b_focus_count.get() + 1);
8573 })
8574 .detach();
8575 FocusForwarder { a, b }
8576 }
8577 });
8578
8579 window
8580 .update(cx, |_, window, _| window.activate_window())
8581 .unwrap();
8582 cx.executor().run_until_parked();
8583
8584 window
8585 .update(cx, |this, window, cx| {
8586 let a = this.a.clone();
8587 window.focus(&a, cx);
8588 })
8589 .unwrap();
8590 cx.executor().run_until_parked();
8591
8592 window
8593 .update(cx, |this, window, _| {
8594 assert!(this.b.is_focused(window));
8595 })
8596 .unwrap();
8597 assert_eq!(b_focus_count.get(), 1);
8598 }
8599
8600 #[gpui::test]
8601 fn claimed_touch_drag_receives_movement_and_release(cx: &mut TestAppContext) {
8602 let events = Rc::new(RefCell::new(Vec::new()));
8603 let window = cx.add_window({
8604 let events = events.clone();
8605 move |_, _| TouchDragListener { events }
8606 });
8607 let touch = TouchId(1);
8608
8609 dispatch_touch(window, cx, touch, TouchPhase::Started, 10.);
8610 dispatch_touch(window, cx, touch, TouchPhase::Moved, 30.);
8611 dispatch_touch(window, cx, touch, TouchPhase::Ended, 40.);
8612
8613 assert_eq!(
8614 events.borrow().as_slice(),
8615 [
8616 (TouchPhase::Started, px(10.)),
8617 (TouchPhase::Moved, px(30.)),
8618 (TouchPhase::Ended, px(40.)),
8619 ]
8620 );
8621 }
8622
8623 struct TouchDragListener {
8624 events: Rc<RefCell<Vec<(TouchPhase, Pixels)>>>,
8625 }
8626
8627 impl Render for TouchDragListener {
8628 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
8629 let events = self.events.clone();
8630 canvas(
8631 |_, _, _| {},
8632 move |_, _, window, _| {
8633 window.on_mouse_event(move |event: &TouchDragEvent, phase, window, _cx| {
8634 if phase != DispatchPhase::Bubble {
8635 return;
8636 }
8637 events.borrow_mut().push((event.phase, event.position.x));
8638 if event.phase == TouchPhase::Started {
8639 window.prevent_default();
8640 }
8641 });
8642 },
8643 )
8644 }
8645 }
8646
8647 #[gpui::test]
8648 fn long_press_is_claimed_only_when_started_prevents_default(cx: &mut TestAppContext) {
8649 for response in [
8650 LongPressResponse::PreventDefault,
8651 LongPressResponse::StopPropagation,
8652 LongPressResponse::None,
8653 ] {
8654 let phases = Rc::new(RefCell::new(Vec::new()));
8655 let window = cx.add_window({
8656 let phases = phases.clone();
8657 move |_, _| LongPressListener { phases, response }
8658 });
8659 dispatch_touch(window, cx, TouchId(1), TouchPhase::Started, 0.);
8660 cx.executor().advance_clock(Duration::from_millis(501));
8661 cx.executor().run_until_parked();
8662 window
8663 .update(cx, |_, window, _| {
8664 assert_eq!(
8665 window.long_press_capture.is_some(),
8666 response == LongPressResponse::PreventDefault
8667 );
8668 })
8669 .unwrap();
8670 dispatch_touch(window, cx, TouchId(1), TouchPhase::Moved, 2.);
8671 dispatch_touch(window, cx, TouchId(1), TouchPhase::Ended, 2.);
8672 window
8673 .update(cx, |_, window, _| {
8674 assert!(window.long_press_capture.is_none());
8675 })
8676 .unwrap();
8677
8678 let phases = phases.borrow();
8679 if response == LongPressResponse::PreventDefault {
8680 assert_eq!(
8681 phases.as_slice(),
8682 [TouchPhase::Started, TouchPhase::Moved, TouchPhase::Ended]
8683 );
8684 } else {
8685 assert_eq!(phases.as_slice(), [TouchPhase::Started]);
8686 }
8687 }
8688 }
8689
8690 #[gpui::test]
8691 fn stale_default_prevention_does_not_claim_long_press(cx: &mut TestAppContext) {
8692 let phases = Rc::new(RefCell::new(Vec::new()));
8693 let window = cx.add_window({
8694 let phases = phases.clone();
8695 move |_, _| LongPressListener {
8696 phases,
8697 response: LongPressResponse::None,
8698 }
8699 });
8700 window
8701 .update(cx, |_, window, _| {
8702 window.prevent_default();
8703 })
8704 .unwrap();
8705
8706 dispatch_touch(window, cx, TouchId(1), TouchPhase::Started, 0.);
8707 cx.executor().advance_clock(Duration::from_millis(501));
8708 cx.executor().run_until_parked();
8709 dispatch_touch(window, cx, TouchId(1), TouchPhase::Moved, 2.);
8710
8711 assert_eq!(phases.borrow().as_slice(), [TouchPhase::Started]);
8712 }
8713
8714 #[gpui::test]
8715 fn resolved_touch_cancels_scheduled_long_press(cx: &mut TestAppContext) {
8716 for (phase, position) in [
8717 (TouchPhase::Ended, 0.),
8718 (TouchPhase::Cancelled, 0.),
8719 (TouchPhase::Moved, 20.),
8720 ] {
8721 let phases = Rc::new(RefCell::new(Vec::new()));
8722 let window = cx.add_window({
8723 let phases = phases.clone();
8724 move |_, _| LongPressListener {
8725 phases,
8726 response: LongPressResponse::PreventDefault,
8727 }
8728 });
8729 dispatch_touch(window, cx, TouchId(1), TouchPhase::Started, 0.);
8730 dispatch_touch(window, cx, TouchId(1), phase, position);
8731 cx.executor().advance_clock(Duration::from_millis(501));
8732 cx.executor().run_until_parked();
8733
8734 assert!(phases.borrow().is_empty(), "{phase:?} allowed long press");
8735 }
8736 }
8737
8738 #[gpui::test]
8739 fn stale_long_press_timer_cannot_affect_replacement_touch(cx: &mut TestAppContext) {
8740 let phases = Rc::new(RefCell::new(Vec::new()));
8741 let window = cx.add_window({
8742 let phases = phases.clone();
8743 move |_, _| LongPressListener {
8744 phases,
8745 response: LongPressResponse::PreventDefault,
8746 }
8747 });
8748 let first_touch = TouchId(1);
8749 dispatch_touch(window, cx, first_touch, TouchPhase::Started, 0.);
8750 cx.executor().advance_clock(Duration::from_millis(250));
8751 dispatch_touch(window, cx, first_touch, TouchPhase::Cancelled, 0.);
8752 dispatch_touch(window, cx, TouchId(2), TouchPhase::Started, 10.);
8753
8754 cx.executor().advance_clock(Duration::from_millis(251));
8755 cx.executor().run_until_parked();
8756 assert!(phases.borrow().is_empty());
8757
8758 cx.executor().advance_clock(Duration::from_millis(250));
8759 cx.executor().run_until_parked();
8760 assert_eq!(phases.borrow().as_slice(), [TouchPhase::Started]);
8761 }
8762
8763 #[gpui::test]
8764 fn test_underline_exclusions_preserve_device_geometry(cx: &mut TestAppContext) {
8765 test_underline_paint_at_scales(cx, |window| {
8766 let (numerator, denominator) = match window.scale_factor() {
8767 1.0 => (1, 1),
8768 1.25 => (5, 4),
8769 1.5 => (3, 2),
8770 2.0 => (2, 1),
8771 3.0 => (3, 1),
8772 scale => panic!("unexpected scale {scale}"),
8773 };
8774 let snap = |quarters: i32| {
8775 let scaled = quarters * numerator;
8776 let divisor = 4 * denominator;
8777 let rounded =
8778 scaled.abs() / divisor + i32::from(2 * (scaled.abs() % divisor) > divisor);
8779 ScaledPixels((scaled.signum() * rounded) as f32)
8780 };
8781 let stroke = |quarters| {
8782 if quarters == 0 {
8783 ScaledPixels(0.)
8784 } else {
8785 snap(quarters).max(ScaledPixels(1.))
8786 }
8787 };
8788
8789 for origin in [-101, -3, -2, -1, 0, 1, 2, 3, 101] {
8790 for width in [0, 1, 3, 84] {
8791 for thickness in [0, 1, 4, 7] {
8792 for wavy in [false, true] {
8793 let style = UnderlineStyle {
8794 thickness: px(thickness as f32 / 4.),
8795 color: Some(hsla(0.25, 0.5, 0.75, 0.5)),
8796 wavy,
8797 };
8798 let bounds = Bounds::new(
8799 point(snap(origin), snap(-origin)),
8800 size(
8801 stroke(width),
8802 stroke(thickness) * if wavy { 3. } else { 1. },
8803 ),
8804 );
8805 let origin = point(px(origin as f32 / 4.), px(-origin as f32 / 4.));
8806 let width = px(width as f32 / 4.);
8807 assert_eq!(window.underline_bounds(origin, width, &style), bounds);
8808 let original = paint_test_underlines(window, |window| {
8809 window.paint_underline(origin, width, &style);
8810 })
8811 .to_vec();
8812 assert_eq!(original.len(), usize::from(!bounds.is_empty()));
8813 if let Some(underline) = original.first() {
8814 assert_eq!(underline.bounds, bounds);
8815 assert_eq!(underline.thickness, stroke(thickness));
8816 assert_eq!(underline.wavy, wavy.into());
8817 assert_eq!(underline.color, hsla(0.25, 0.5, 0.75, 0.5));
8818 }
8819
8820 let underlines = paint_test_underlines(window, |window| {
8821 window.paint_underline_with_exclusions(origin, width, &style, &[]);
8822 });
8823 assert_eq!(underlines.len(), original.len());
8824 for (actual, original) in underlines.iter().zip(&original) {
8825 assert_same_underline_geometry(actual, original);
8826 assert_eq!(actual.content_mask, original.content_mask);
8827 }
8828
8829 let left = bounds.left().0 as i32;
8830 let right = bounds.right().0 as i32;
8831 let exclusions = [
8832 (15, 25),
8833 (3, 7),
8834 (5, 10),
8835 (10, 12),
8836 (0, 0),
8837 (4, 2),
8838 (-50, -1),
8839 (70, 100),
8840 ]
8841 .map(|(start, end)| {
8842 ScaledPixels((left + start) as f32)
8843 ..ScaledPixels((left + end) as f32)
8844 });
8845 let underlines = paint_test_underlines(window, |window| {
8846 window.paint_underline_with_exclusions(
8847 origin,
8848 width,
8849 &style,
8850 &exclusions,
8851 );
8852 });
8853 let expected = (left..right)
8854 .filter(|column| {
8855 !bounds.is_empty()
8856 && !exclusions.iter().any(|span| {
8857 span.contains(&ScaledPixels(*column as f32))
8858 })
8859 })
8860 .collect::<Vec<_>>();
8861 assert_eq!(underline_device_columns(underlines), expected);
8862 for underline in underlines {
8863 assert_same_underline_geometry(underline, &original[0]);
8864 }
8865 }
8866 }
8867 }
8868 }
8869 });
8870 }
8871
8872 #[gpui::test]
8873 fn test_underline_exclusions_preserve_helvetica_warning_edge(cx: &mut TestAppContext) {
8874 test_underline_paint_at_scales(cx, |window| {
8875 if window.scale_factor() != 2.0 {
8876 return;
8877 }
8878 let style = UnderlineStyle {
8879 thickness: px(1.),
8880 color: None,
8881 wavy: true,
8882 };
8883 let origin = point(px(2.888_183_8), px(15.357_917));
8884 let width = px(23.848_145) - origin.x;
8885 let original = paint_test_underlines(window, |window| {
8886 window.paint_underline(origin, width, &style);
8887 })[0];
8888 assert_eq!(original.bounds.left(), ScaledPixels(6.));
8889 assert_eq!(original.bounds.right(), ScaledPixels(48.));
8890 let point_bounds = window.underline_bounds(origin, px(10.829_102), &style);
8891 assert_eq!(point_bounds.left(), ScaledPixels(6.));
8892 assert_eq!(point_bounds.right(), ScaledPixels(28.));
8893
8894 let underlines = paint_test_underlines(window, |window| {
8895 window.paint_underline_with_exclusions(
8896 origin,
8897 width,
8898 &style,
8899 &[point_bounds.left()..point_bounds.right()],
8900 );
8901 });
8902 assert_eq!(underlines.len(), 1);
8903 assert_same_underline_geometry(&underlines[0], &original);
8904 assert_eq!(
8905 underline_device_columns(underlines),
8906 (28..48).collect::<Vec<_>>()
8907 );
8908 });
8909 }
8910
8911 #[gpui::test]
8912 fn test_underline_exclusions_preserve_content_mask_and_opacity(cx: &mut TestAppContext) {
8913 test_underline_paint_at_scales(cx, |window| {
8914 let scale = window.scale_factor();
8915 let original_mask = window.content_mask();
8916 let original_opacity = window.element_opacity();
8917 let mask = ContentMask {
8918 bounds: Bounds::from_corners(point(px(4.), px(10.)), point(px(16.), px(12.))),
8919 };
8920 let style = UnderlineStyle {
8921 thickness: px(2.),
8922 color: Some(hsla(0.25, 0.5, 0.75, 0.5)),
8923 wavy: true,
8924 };
8925 let origin = point(px(-1.25), px(9.25));
8926 let width = px(24.);
8927 window.with_content_mask(Some(mask), |window| {
8928 window.with_element_opacity(Some(0.5), |window| {
8929 window.with_element_opacity(Some(0.5), |window| {
8930 let original = paint_test_underlines(window, |window| {
8931 window.paint_underline(origin, width, &style);
8932 })[0];
8933 assert_eq!(original.color, hsla(0.25, 0.5, 0.75, 0.125));
8934 let underlines = paint_test_underlines(window, |window| {
8935 window.paint_underline_with_exclusions(
8936 origin,
8937 width,
8938 &style,
8939 &[ScaledPixels(6. * scale)..ScaledPixels(8. * scale)],
8940 );
8941 });
8942 assert_eq!(underlines.len(), 2);
8943 let expected = [(4. * scale, 6. * scale), (8. * scale, 16. * scale)].map(
8944 |(left, right)| {
8945 Bounds::from_corners(
8946 point(ScaledPixels(left), ScaledPixels((10. * scale).floor())),
8947 point(ScaledPixels(right), ScaledPixels((12. * scale).ceil())),
8948 )
8949 },
8950 );
8951 assert_eq!(
8952 underlines
8953 .iter()
8954 .map(|underline| underline.content_mask.bounds)
8955 .collect::<Vec<_>>(),
8956 expected
8957 );
8958 for underline in underlines {
8959 assert_same_underline_geometry(underline, &original);
8960 }
8961 });
8962 });
8963 });
8964 assert_eq!(window.content_mask(), original_mask);
8965 assert_eq!(window.element_opacity(), original_opacity);
8966 });
8967 }
8968
8969 #[gpui::test]
8970 fn test_underline_exclusions_adversarial_permutations(cx: &mut TestAppContext) {
8971 test_underline_paint_at_scales(cx, |window| {
8972 let style = UnderlineStyle {
8973 thickness: px(1.),
8974 color: None,
8975 wavy: true,
8976 };
8977 let origin = point(px(-4.), px(-1.));
8978 let width = px(8.);
8979 let left = (-4. * window.scale_factor()) as i32;
8980 let right = (4. * window.scale_factor()) as i32;
8981 let endpoints = [-16, -8, -1, 0, 1, 8, 16];
8982 for first_start in endpoints {
8983 for first_end in endpoints {
8984 for second_start in endpoints {
8985 for second_end in endpoints {
8986 let exclusions = [first_start..first_end, second_start..second_end];
8987 let expected = (left..right)
8988 .filter(|column| {
8989 !exclusions.iter().any(|span| span.contains(column))
8990 })
8991 .collect::<Vec<_>>();
8992 let exclusions = exclusions.map(|span| {
8993 ScaledPixels(span.start as f32)..ScaledPixels(span.end as f32)
8994 });
8995 let underlines = paint_test_underlines(window, |window| {
8996 window.paint_underline_with_exclusions(
8997 origin,
8998 width,
8999 &style,
9000 &exclusions,
9001 );
9002 });
9003 assert_eq!(
9004 underline_device_columns(underlines),
9005 expected,
9006 "{exclusions:?}"
9007 );
9008 }
9009 }
9010 }
9011 }
9012 });
9013 }
9014
9015 #[derive(Clone, Copy, PartialEq)]
9016 enum LongPressResponse {
9017 PreventDefault,
9018 StopPropagation,
9019 None,
9020 }
9021
9022 struct LongPressListener {
9023 phases: Rc<RefCell<Vec<TouchPhase>>>,
9024 response: LongPressResponse,
9025 }
9026
9027 impl Render for LongPressListener {
9028 fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
9029 let entity = cx.entity();
9030 let phases = self.phases.clone();
9031 let response = self.response;
9032 canvas(
9033 |_, _, _| {},
9034 move |_, _, window, _| {
9035 window.on_mouse_event(move |event: &LongPressEvent, phase, window, cx| {
9036 if phase != DispatchPhase::Bubble {
9037 return;
9038 }
9039 phases.borrow_mut().push(event.phase);
9040 match response {
9041 LongPressResponse::PreventDefault => {
9042 window.capture_long_press(&entity);
9043 window.prevent_default();
9044 }
9045 LongPressResponse::StopPropagation => cx.stop_propagation(),
9046 LongPressResponse::None => {}
9047 }
9048 });
9049 },
9050 )
9051 }
9052 }
9053
9054 struct UnderlineTestView(Rc<dyn Fn(&mut Window)>);
9055
9056 impl Render for UnderlineTestView {
9057 fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
9058 let paint = self.0.clone();
9059 canvas(
9060 |_, _, _| {},
9061 move |_, _, window, _| {
9062 window.content_mask_stack.push(ContentMask {
9063 bounds: Bounds::from_corners(
9064 point(px(-1000.), px(-1000.)),
9065 point(px(1000.), px(1000.)),
9066 ),
9067 });
9068 paint(window);
9069 window.content_mask_stack.pop();
9070 },
9071 )
9072 .size_full()
9073 }
9074 }
9075
9076 fn test_underline_paint_at_scales(
9077 cx: &mut TestAppContext,
9078 paint: impl Fn(&mut Window) + 'static,
9079 ) {
9080 let window = cx.add_window(move |_, _| UnderlineTestView(Rc::new(paint)));
9081 for scale in [1., 1.25, 1.5, 2., 3.] {
9082 cx.simulate_window_scale_factor_change(window.into(), scale);
9083 cx.update_window(window.into(), |_, window, cx| window.draw(cx).clear(cx))
9084 .unwrap();
9085 }
9086 }
9087
9088 fn paint_test_underlines(window: &mut Window, paint: impl FnOnce(&mut Window)) -> &[Underline] {
9089 window.next_frame.scene.clear();
9090 paint(window);
9091 &window.next_frame.scene.underlines
9092 }
9093
9094 fn assert_same_underline_geometry(actual: &Underline, expected: &Underline) {
9095 assert_eq!(actual.bounds, expected.bounds);
9096 assert_eq!(actual.thickness, expected.thickness);
9097 assert_eq!(actual.wavy, expected.wavy);
9098 assert_eq!(actual.color, expected.color);
9099 assert_eq!(actual.pad, expected.pad);
9100 }
9101
9102 fn underline_device_columns(underlines: &[Underline]) -> Vec<i32> {
9103 underlines
9104 .iter()
9105 .flat_map(|underline| {
9106 let bounds = underline.bounds.intersect(&underline.content_mask.bounds);
9107 bounds.left().0 as i32..bounds.right().0 as i32
9108 })
9109 .collect()
9110 }
9111
9112 fn dispatch_touch<T: 'static>(
9113 window: crate::WindowHandle<T>,
9114 cx: &mut TestAppContext,
9115 id: TouchId,
9116 phase: TouchPhase,
9117 x: f32,
9118 ) {
9119 window
9120 .update(cx, |_, window, cx| {
9121 window.dispatch_event(
9122 TouchEvent {
9123 id,
9124 phase,
9125 position: point(px(x), px(0.)),
9126 predicted_position: None,
9127 force: None,
9128 }
9129 .to_platform_input(),
9130 cx,
9131 );
9132 })
9133 .unwrap();
9134 }
9135}
9136
9137#[cfg(all(test, any(feature = "inspector", debug_assertions)))]
9138mod inspector_tests {
9139 use super::*;
9140 use crate::{
9141 DivInspectorState, InspectorElementId, MouseDownEvent, StyleRefinement, TestAppContext, div,
9142 };
9143
9144 #[gpui::test]
9145 fn inspector_only_tracks_its_open_window(cx: &mut TestAppContext) {
9146 let windows = [
9147 cx.add_window(|_, cx| InspectorTestRoot {
9148 child: cx.new(|_| InspectorTestView::default()),
9149 }),
9150 cx.add_window(|_, cx| InspectorTestRoot {
9151 child: cx.new(|_| InspectorTestView::default()),
9152 }),
9153 ];
9154 for window in windows {
9155 assert_closed_inspector(window.into(), cx);
9156 }
9157 for _ in 0..2 {
9158 cx.update_window(windows[0].into(), |root, window, cx| {
9159 let root = root.downcast::<InspectorTestRoot>().expect("test root");
9160 let child_widths = root.read(cx).child.read(cx).child_widths.clone();
9161 window.toggle_inspector(cx);
9162 window.draw(cx).clear(cx);
9163 assert_eq!(child_widths.borrow().as_slice(), &[px(10.); 3]);
9164 let path = window
9165 .rendered_frame
9166 .next_inspector_instance_ids
9167 .iter()
9168 .find_map(|(path, count)| (*count == 3).then(|| path.clone()))
9169 .expect("anonymous siblings share an inspector path");
9170 let selected_id = InspectorElementId {
9171 path,
9172 instance_id: 1,
9173 };
9174 let position = window
9175 .rendered_frame
9176 .hitboxes
9177 .iter()
9178 .find(|hitbox| {
9179 window.rendered_frame.inspector_hitboxes.get(&hitbox.id)
9180 == Some(&selected_id)
9181 })
9182 .expect("middle sibling is pickable")
9183 .bounds
9184 .center();
9185 window.simulate_mouse_move(position, cx);
9186 window.dispatch_event(
9187 PlatformInput::MouseDown(MouseDownEvent {
9188 position,
9189 button: MouseButton::Left,
9190 modifiers: Modifiers::default(),
9191 click_count: 1,
9192 first_mouse: false,
9193 }),
9194 cx,
9195 );
9196 window.dispatch_event(
9197 PlatformInput::MouseUp(MouseUpEvent {
9198 position,
9199 button: MouseButton::Left,
9200 modifiers: Modifiers::default(),
9201 click_count: 1,
9202 }),
9203 cx,
9204 );
9205 assert!(!window.is_inspector_picking(cx));
9206 assert_eq!(
9207 window
9208 .inspector
9209 .as_ref()
9210 .expect("open inspector")
9211 .read(cx)
9212 .active_element_id(),
9213 Some(&selected_id)
9214 );
9215 window.draw(cx).clear(cx);
9216 window.with_inspector_state::<DivInspectorState, _>(
9217 Some(&selected_id),
9218 cx,
9219 |state, _| {
9220 let state = state.as_mut().expect("selected div has style state");
9221 assert_eq!(
9222 state.base_style.size.width,
9223 Some(crate::Length::from(px(10.)))
9224 );
9225 state.base_style.size.width = Some(crate::Length::from(px(25.)));
9226 },
9227 );
9228 window.refresh();
9229 window.draw(cx).clear(cx);
9230 assert_eq!(
9231 child_widths.borrow().as_slice(),
9232 &[px(10.), px(25.), px(10.)]
9233 );
9234 })
9235 .expect("pick and edit a cached child");
9236 assert_closed_inspector(windows[1].into(), cx);
9237 windows[0]
9238 .update(cx, |_, window, cx| window.toggle_inspector(cx))
9239 .expect("close inspector");
9240 assert_closed_inspector(windows[0].into(), cx);
9241 }
9242 }
9243
9244 struct InspectorTestRoot {
9245 child: Entity<InspectorTestView>,
9246 }
9247
9248 impl Render for InspectorTestRoot {
9249 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
9250 self.child
9251 .clone()
9252 .cached(StyleRefinement::default().size(px(100.)))
9253 }
9254 }
9255
9256 #[derive(Default)]
9257 struct InspectorTestView {
9258 child_widths: Rc<RefCell<Vec<Pixels>>>,
9259 }
9260
9261 impl Render for InspectorTestView {
9262 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
9263 let child_widths = self.child_widths.clone();
9264 div()
9265 .on_children_prepainted(move |bounds, _, _| {
9266 *child_widths.borrow_mut() =
9267 bounds.iter().map(|bounds| bounds.size.width).collect();
9268 })
9269 .with_dynamic_prepaint_order(|_, _| SmallVec::from_iter([2, 0, 1]))
9270 .id("inspector-root")
9271 .flex()
9272 .children((0..3).map(|_| div().size(px(10.)).flex_shrink_0()))
9273 }
9274 }
9275
9276 fn assert_closed_inspector(window: AnyWindowHandle, cx: &mut TestAppContext) {
9277 cx.update_window(window, |root, window, cx| {
9278 window.draw(cx).clear(cx);
9279 window.draw(cx).clear(cx);
9280 let root = root.downcast::<InspectorTestRoot>().expect("test root");
9281 assert_eq!(
9282 root.read(cx)
9283 .child
9284 .read(cx)
9285 .child_widths
9286 .borrow()
9287 .as_slice(),
9288 &[px(10.); 3]
9289 );
9290 for frame in [&window.rendered_frame, &window.next_frame] {
9291 assert_eq!(frame.next_inspector_instance_ids.capacity(), 0);
9292 assert_eq!(frame.inspector_hitboxes.capacity(), 0);
9293 }
9294 })
9295 .expect("closed inspector has no bookkeeping and no style overrides");
9296 }
9297}