1#[cfg(any(feature = "inspector", debug_assertions))]
2use crate::Inspector;
3use crate::{
4 Action, AnyDrag, AnyElement, AnyImageCache, AnyTooltip, AnyView, App, AppContext, Arena, Asset,
5 AsyncWindowContext, AtlasTile, AvailableSpace, BackdropFilter, Background, BorderStyle, Bounds,
6 BoxShadow, Capslock, ColorExt, Context, Corners, CursorHideMode, CursorStyle, Decorations,
7 DevicePixels, DispatchActionListener, DispatchNodeId, DispatchTree, DisplayId, Edges, Effect,
8 Entity, EntityId, EventEmitter, FileDropEvent, Filter, FilterBoundary, FontId, Global,
9 GlobalElementId, GlyphId, GpuSpecs, InputHandler, IsZero, KeyBinding, KeyContext, KeyDownEvent,
10 KeyEvent, Keystroke, KeystrokeEvent, LayoutId, Lerp, LineLayoutIndex, Modifiers,
11 ModifiersChangedEvent, MonochromeSprite, MouseButton, MouseEvent, MouseMoveEvent, MouseUpEvent,
12 Path, Pixels, PlatformAtlas, PlatformDisplay, PlatformInput, PlatformInputHandler,
13 PlatformWindow, Point, PolychromeSprite, Priority, PromptButton, PromptLevel, Quad, Render,
14 RenderGlyphParams, RenderImage, RenderImageParams, RenderSvgParams, Replay, ResizeEdge,
15 SMOOTH_SVG_SCALE_FACTOR, SUBPIXEL_VARIANTS_X, SUBPIXEL_VARIANTS_Y, ScaledFilter, ScaledPixels,
16 Scene, Shadow, SharedString, Size, StrikethroughStyle, Style, SubpixelSprite, SubscriberSet,
17 Subscription, SystemWindowTab, SystemWindowTabController, TabStopMap, TaffyLayoutEngine, Task,
18 TextRenderingMode, TextStyle, TextStyleRefinement, ThermalState, TransformationMatrix,
19 Transition, TransitionState, Underline, UnderlineStyle, WindowAppearance,
20 WindowBackgroundAppearance, WindowBounds, WindowControls, WindowDecorations, WindowOptions,
21 WindowParams, WindowTextSystem, point, prelude::*, profiler, px, rems, size, transparent_black,
22};
23
24use anyhow::{Context as _, Result, anyhow};
25use collections::{FxHashMap, FxHashSet};
26#[cfg(target_os = "macos")]
27use core_video::pixel_buffer::CVPixelBuffer;
28use derive_more::{Deref, DerefMut};
29use futures::FutureExt;
30use futures::channel::oneshot;
31use gpui_util::post_inc;
32use gpui_util::{ResultExt, measure};
33#[cfg(feature = "input-latency-histogram")]
34use hdrhistogram::Histogram;
35use itertools::FoldWhile::{Continue, Done};
36use itertools::Itertools;
37use palette::{Hsla, IntoColor};
38use parking_lot::RwLock;
39use raw_window_handle::{HandleError, HasDisplayHandle, HasWindowHandle};
40use refineable::Refineable;
41use scheduler::Instant;
42use slotmap::SlotMap;
43use smallvec::SmallVec;
44use std::{
45 any::{Any, TypeId},
46 borrow::Cow,
47 cell::{Cell, RefCell},
48 cmp,
49 fmt::{Debug, Display},
50 hash::{Hash, Hasher},
51 marker::PhantomData,
52 mem,
53 ops::{DerefMut, Range},
54 rc::Rc,
55 sync::{
56 Arc, Weak,
57 atomic::{AtomicBool, AtomicUsize, Ordering::SeqCst},
58 },
59 time::Duration,
60};
61use uuid::Uuid;
62
63pub(crate) mod a11y;
64mod prompts;
65
66pub use a11y::A11ySubtreeBuilder;
67
68use self::a11y::A11y;
69#[cfg(not(target_family = "wasm"))]
70use self::a11y::ROOT_NODE_ID;
71use crate::util::{
72 atomic_incr_if_not_zero, ceil_to_device_pixel, floor_to_device_pixel, round_half_toward_zero,
73 round_half_toward_zero_f64, round_stroke_to_device_pixel, round_to_device_pixel,
74};
75pub use prompts::*;
76
77pub const DEFAULT_WINDOW_SIZE: Size<Pixels> = size(px(1536.), px(1095.));
79
80pub const DEFAULT_ADDITIONAL_WINDOW_SIZE: Size<Pixels> = Size {
83 width: Pixels(900.),
84 height: Pixels(750.),
85};
86
87#[derive(Default, Copy, Clone, Debug, Eq, PartialEq)]
89pub enum DispatchPhase {
90 #[default]
95 Bubble,
96 Capture,
102}
103
104impl DispatchPhase {
105 #[inline]
107 pub fn bubble(self) -> bool {
108 self == DispatchPhase::Bubble
109 }
110
111 #[inline]
113 pub fn capture(self) -> bool {
114 self == DispatchPhase::Capture
115 }
116}
117
118struct WindowInvalidatorInner {
119 pub dirty: bool,
120 pub draw_phase: DrawPhase,
121 pub dirty_views: FxHashSet<EntityId>,
122 pub update_count: usize,
123 pub frame_dirty: FrameDirtyAccumulator,
124}
125
126#[derive(Default)]
131struct FrameDirtyAccumulator {
132 dirty_at: Option<Instant>,
133 invalidations: u64,
134}
135
136#[derive(Clone)]
137pub(crate) struct WindowInvalidator {
138 inner: Rc<RefCell<WindowInvalidatorInner>>,
139}
140
141impl WindowInvalidator {
142 pub fn new() -> Self {
143 WindowInvalidator {
144 inner: Rc::new(RefCell::new(WindowInvalidatorInner {
145 dirty: true,
146 draw_phase: DrawPhase::None,
147 dirty_views: FxHashSet::default(),
148 update_count: 0,
149 frame_dirty: FrameDirtyAccumulator::default(),
150 })),
151 }
152 }
153
154 pub fn invalidate_view(&self, entity: EntityId, cx: &mut App) -> bool {
155 let mut inner = self.inner.borrow_mut();
156 inner.update_count += 1;
157 inner.dirty_views.insert(entity);
158 if inner.draw_phase == DrawPhase::None {
159 Self::record_frame_dirty(&mut inner);
160 inner.dirty = true;
161 cx.push_effect(Effect::Notify { emitter: entity });
162 true
163 } else {
164 false
165 }
166 }
167
168 pub fn is_dirty(&self) -> bool {
169 self.inner.borrow().dirty
170 }
171
172 pub fn set_dirty(&self, dirty: bool) {
173 let mut inner = self.inner.borrow_mut();
174 inner.dirty = dirty;
175 if dirty {
176 inner.update_count += 1;
177 Self::record_frame_dirty(&mut inner);
178 }
179 }
180
181 pub fn set_phase(&self, phase: DrawPhase) {
182 self.inner.borrow_mut().draw_phase = phase
183 }
184
185 pub fn update_count(&self) -> usize {
186 self.inner.borrow().update_count
187 }
188
189 fn record_frame_dirty(inner: &mut WindowInvalidatorInner) {
190 if profiler::frame_trace_enabled() {
191 inner.frame_dirty.dirty_at.get_or_insert_with(Instant::now);
192 inner.frame_dirty.invalidations += 1;
193 }
194 }
195
196 fn take_frame_dirty(&self) -> FrameDirtyAccumulator {
197 mem::take(&mut self.inner.borrow_mut().frame_dirty)
198 }
199
200 pub fn take_views(&self) -> FxHashSet<EntityId> {
201 mem::take(&mut self.inner.borrow_mut().dirty_views)
202 }
203
204 pub fn replace_views(&self, views: FxHashSet<EntityId>) {
205 self.inner.borrow_mut().dirty_views = views;
206 }
207
208 pub fn not_drawing(&self) -> bool {
209 self.inner.borrow().draw_phase == DrawPhase::None
210 }
211
212 #[track_caller]
213 pub fn debug_assert_paint(&self) {
214 debug_assert!(
215 matches!(self.inner.borrow().draw_phase, DrawPhase::Paint),
216 "this method can only be called during paint"
217 );
218 }
219
220 #[track_caller]
221 pub fn debug_assert_prepaint(&self) {
222 debug_assert!(
223 matches!(self.inner.borrow().draw_phase, DrawPhase::Prepaint),
224 "this method can only be called during request_layout, or prepaint"
225 );
226 }
227
228 #[track_caller]
229 pub fn debug_assert_paint_or_prepaint(&self) {
230 debug_assert!(
231 matches!(
232 self.inner.borrow().draw_phase,
233 DrawPhase::Paint | DrawPhase::Prepaint
234 ),
235 "this method can only be called during request_layout, prepaint, or paint"
236 );
237 }
238}
239
240type AnyObserver = Box<dyn FnMut(&mut Window, &mut App) -> bool + 'static>;
241
242pub(crate) type AnyWindowFocusListener =
243 Box<dyn FnMut(&WindowFocusEvent, &mut Window, &mut App) -> bool + 'static>;
244
245pub(crate) struct WindowFocusEvent {
246 pub(crate) previous_focus_path: SmallVec<[FocusId; 8]>,
247 pub(crate) current_focus_path: SmallVec<[FocusId; 8]>,
248}
249
250impl WindowFocusEvent {
251 pub fn is_focus_in(&self, focus_id: FocusId) -> bool {
252 !self.previous_focus_path.contains(&focus_id) && self.current_focus_path.contains(&focus_id)
253 }
254
255 pub fn is_focus_out(&self, focus_id: FocusId) -> bool {
256 self.previous_focus_path.contains(&focus_id) && !self.current_focus_path.contains(&focus_id)
257 }
258}
259
260pub struct FocusOutEvent {
262 pub blurred: WeakFocusHandle,
264}
265
266slotmap::new_key_type! {
267 pub struct FocusId;
269}
270
271thread_local! {
272 pub(crate) static ELEMENT_ARENA: RefCell<Arena> = RefCell::new(Arena::new(1024 * 1024));
275
276 static CURRENT_ELEMENT_ARENA: Cell<Option<*const RefCell<Arena>>> = const { Cell::new(None) };
280}
281
282fn draw_in_progress() -> bool {
293 CURRENT_ELEMENT_ARENA.with(|current| current.get().is_some())
294}
295
296pub(crate) fn with_element_arena<R>(f: impl FnOnce(&mut Arena) -> R) -> R {
299 CURRENT_ELEMENT_ARENA.with(|current| {
300 if let Some(arena_ptr) = current.get() {
301 let arena_cell = unsafe { &*arena_ptr };
304 f(&mut arena_cell.borrow_mut())
305 } else {
306 ELEMENT_ARENA.with_borrow_mut(f)
307 }
308 })
309}
310
311pub(crate) struct ElementArenaScope {
326 entered: *const RefCell<Arena>,
329 previous: Option<*const RefCell<Arena>>,
330 exited: bool,
331}
332
333impl ElementArenaScope {
334 pub(crate) fn enter(arena: &RefCell<Arena>) -> Self {
336 arena.borrow_mut().begin_scope();
337 let previous = CURRENT_ELEMENT_ARENA.with(|current| {
338 let prev = current.get();
339 current.set(Some(arena as *const RefCell<Arena>));
340 prev
341 });
342 Self {
343 entered: arena as *const RefCell<Arena>,
344 previous,
345 exited: false,
346 }
347 }
348
349 pub(crate) fn exit(mut self, arena: &RefCell<Arena>) -> ArenaClearNeeded {
358 assert!(
359 std::ptr::eq(self.entered, arena),
360 "ElementArenaScope::exit called with a different arena than was entered"
361 );
362 self.exited = true;
363 ArenaClearNeeded::new(arena)
368 }
369}
370
371impl Drop for ElementArenaScope {
372 fn drop(&mut self) {
373 CURRENT_ELEMENT_ARENA.with(|current| {
380 current.set(self.previous);
381 });
382 unsafe { &*self.entered }.borrow_mut().end_scope();
386 if !self.exited && !std::thread::panicking() {
387 debug_assert!(false, "ElementArenaScope dropped without calling exit()");
388 log::error!(
389 "ElementArenaScope dropped without calling exit(); \
390 the arena clear for this draw was never requested"
391 );
392 }
393 }
394}
395
396#[must_use]
398pub struct ArenaClearNeeded {
399 arena: *const RefCell<Arena>,
402}
403
404impl ArenaClearNeeded {
405 fn new(arena: &RefCell<Arena>) -> Self {
408 Self {
409 arena: arena as *const RefCell<Arena>,
410 }
411 }
412
413 pub fn clear(self, cx: &mut App) {
422 assert!(
423 std::ptr::eq(self.arena, &cx.element_arena),
424 "ArenaClearNeeded::clear called with a different App than the draw ran against"
425 );
426 cx.element_arena.borrow_mut().clear();
427 }
428}
429
430pub(crate) type FocusMap = RwLock<SlotMap<FocusId, FocusRef>>;
431pub(crate) struct FocusRef {
432 pub(crate) ref_count: AtomicUsize,
433 pub(crate) tab_index: isize,
434 pub(crate) tab_stop: bool,
435}
436
437impl FocusId {
438 pub fn is_focused(&self, window: &Window) -> bool {
440 window.focus == Some(*self)
441 }
442
443 pub fn contains_focused(&self, window: &Window, cx: &App) -> bool {
446 window
447 .focused(cx)
448 .is_some_and(|focused| self.contains(focused.id, window))
449 }
450
451 pub fn within_focused(&self, window: &Window, cx: &App) -> bool {
454 let focused = window.focused(cx);
455 focused.is_some_and(|focused| focused.id.contains(*self, window))
456 }
457
458 pub(crate) fn contains(&self, other: Self, window: &Window) -> bool {
460 window
461 .rendered_frame
462 .dispatch_tree
463 .focus_contains(*self, other)
464 }
465}
466
467pub struct FocusHandle {
469 pub(crate) id: FocusId,
470 handles: Arc<FocusMap>,
471 pub tab_index: isize,
473 pub tab_stop: bool,
475}
476
477impl std::fmt::Debug for FocusHandle {
478 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
479 f.write_fmt(format_args!("FocusHandle({:?})", self.id))
480 }
481}
482
483impl FocusHandle {
484 pub(crate) fn new(handles: &Arc<FocusMap>) -> Self {
485 let id = handles.write().insert(FocusRef {
486 ref_count: AtomicUsize::new(1),
487 tab_index: 0,
488 tab_stop: false,
489 });
490
491 Self {
492 id,
493 tab_index: 0,
494 tab_stop: false,
495 handles: handles.clone(),
496 }
497 }
498
499 pub(crate) fn for_id(id: FocusId, handles: &Arc<FocusMap>) -> Option<Self> {
500 let lock = handles.read();
501 let focus = lock.get(id)?;
502 if atomic_incr_if_not_zero(&focus.ref_count) == 0 {
503 return None;
504 }
505 Some(Self {
506 id,
507 tab_index: focus.tab_index,
508 tab_stop: focus.tab_stop,
509 handles: handles.clone(),
510 })
511 }
512
513 pub fn tab_index(mut self, index: isize) -> Self {
515 self.tab_index = index;
516 if let Some(focus) = self.handles.write().get_mut(self.id) {
517 focus.tab_index = index;
518 }
519 self
520 }
521
522 pub fn tab_stop(mut self, tab_stop: bool) -> Self {
526 self.tab_stop = tab_stop;
527 if let Some(focus) = self.handles.write().get_mut(self.id) {
528 focus.tab_stop = tab_stop;
529 }
530 self
531 }
532
533 pub fn downgrade(&self) -> WeakFocusHandle {
535 WeakFocusHandle {
536 id: self.id,
537 handles: Arc::downgrade(&self.handles),
538 }
539 }
540
541 pub fn focus(&self, window: &mut Window, cx: &mut App) {
543 window.focus(self, cx)
544 }
545
546 pub fn is_focused(&self, window: &Window) -> bool {
548 self.id.is_focused(window)
549 }
550
551 pub fn contains_focused(&self, window: &Window, cx: &App) -> bool {
554 self.id.contains_focused(window, cx)
555 }
556
557 pub fn within_focused(&self, window: &Window, cx: &mut App) -> bool {
560 self.id.within_focused(window, cx)
561 }
562
563 pub fn contains(&self, other: &Self, window: &Window) -> bool {
565 self.id.contains(other.id, window)
566 }
567
568 pub fn dispatch_action(&self, action: &dyn Action, window: &mut Window, cx: &mut App) {
570 if let Some(node_id) = window
571 .rendered_frame
572 .dispatch_tree
573 .focusable_node_id(self.id)
574 {
575 window.dispatch_action_on_node(node_id, action, cx)
576 }
577 }
578}
579
580impl Clone for FocusHandle {
581 fn clone(&self) -> Self {
582 Self::for_id(self.id, &self.handles).unwrap()
583 }
584}
585
586impl PartialEq for FocusHandle {
587 fn eq(&self, other: &Self) -> bool {
588 self.id == other.id
589 }
590}
591
592impl Eq for FocusHandle {}
593
594impl Drop for FocusHandle {
595 fn drop(&mut self) {
596 self.handles
597 .read()
598 .get(self.id)
599 .unwrap()
600 .ref_count
601 .fetch_sub(1, SeqCst);
602 }
603}
604
605#[derive(Clone, Debug)]
607pub struct WeakFocusHandle {
608 pub(crate) id: FocusId,
609 pub(crate) handles: Weak<FocusMap>,
610}
611
612impl WeakFocusHandle {
613 pub fn upgrade(&self) -> Option<FocusHandle> {
615 let handles = self.handles.upgrade()?;
616 FocusHandle::for_id(self.id, &handles)
617 }
618}
619
620impl PartialEq for WeakFocusHandle {
621 fn eq(&self, other: &WeakFocusHandle) -> bool {
622 self.id == other.id
623 }
624}
625
626impl Eq for WeakFocusHandle {}
627
628impl PartialEq<FocusHandle> for WeakFocusHandle {
629 fn eq(&self, other: &FocusHandle) -> bool {
630 self.id == other.id
631 }
632}
633
634impl PartialEq<WeakFocusHandle> for FocusHandle {
635 fn eq(&self, other: &WeakFocusHandle) -> bool {
636 self.id == other.id
637 }
638}
639
640pub trait Focusable: 'static {
643 fn focus_handle(&self, cx: &App) -> FocusHandle;
645}
646
647impl<V: Focusable> Focusable for Entity<V> {
648 fn focus_handle(&self, cx: &App) -> FocusHandle {
649 self.read(cx).focus_handle(cx)
650 }
651}
652
653pub trait ManagedView: Focusable + EventEmitter<DismissEvent> + Render {}
656
657impl<M: Focusable + EventEmitter<DismissEvent> + Render> ManagedView for M {}
658
659pub struct DismissEvent;
661
662type FrameCallback = Box<dyn FnOnce(&mut Window, &mut App)>;
663
664pub(crate) type AnyMouseListener =
665 Box<dyn FnMut(&dyn Any, DispatchPhase, &mut Window, &mut App) + 'static>;
666
667#[derive(Clone)]
668pub(crate) struct CursorStyleRequest {
669 pub(crate) hitbox_id: Option<HitboxId>,
670 pub(crate) style: CursorStyle,
671}
672
673#[derive(Default, Eq, PartialEq)]
674pub(crate) struct HitTest {
675 pub(crate) ids: SmallVec<[HitboxId; 8]>,
676 pub(crate) hover_hitbox_count: usize,
677}
678
679#[derive(Clone, Copy, Debug, Eq, PartialEq)]
681pub enum WindowControlArea {
682 Drag,
684 Close,
686 Max,
688 Min,
690}
691
692#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
694pub struct HitboxId(u64);
695
696#[cfg(feature = "test-support")]
697impl HitboxId {
698 pub const fn placeholder() -> Self {
703 Self(0)
704 }
705}
706
707impl HitboxId {
708 pub fn is_hovered(self, window: &Window) -> bool {
715 if window.captured_hitbox == Some(self) {
717 return true;
718 }
719 if window.last_input_was_keyboard() {
720 return false;
721 }
722 self.hit_test(window)
723 }
724
725 pub(crate) fn is_hovered_ignoring_last_input(self, window: &Window) -> bool {
730 if window.captured_hitbox == Some(self) {
732 return true;
733 }
734 self.hit_test(window)
735 }
736
737 fn hit_test(self, window: &Window) -> bool {
738 let hit_test = &window.mouse_hit_test;
739 for id in hit_test.ids.iter().take(hit_test.hover_hitbox_count) {
740 if self == *id {
741 return true;
742 }
743 }
744 false
745 }
746
747 pub fn should_handle_scroll(self, window: &Window) -> bool {
752 window.mouse_hit_test.ids.contains(&self)
753 }
754
755 fn next(mut self) -> HitboxId {
756 HitboxId(self.0.wrapping_add(1))
757 }
758}
759
760#[derive(Clone, Debug, Deref)]
763pub struct Hitbox {
764 pub id: HitboxId,
766 #[deref]
768 pub bounds: Bounds<Pixels>,
769 pub content_mask: ContentMask<Pixels>,
771 pub behavior: HitboxBehavior,
773}
774
775impl Hitbox {
776 pub fn is_hovered(&self, window: &Window) -> bool {
793 self.id.is_hovered(window)
794 }
795
796 pub fn should_handle_scroll(&self, window: &Window) -> bool {
803 self.id.should_handle_scroll(window)
804 }
805}
806
807#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
809pub enum HitboxBehavior {
810 #[default]
812 Normal,
813
814 BlockMouse,
836
837 BlockMouseExceptScroll,
864}
865
866#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
868pub struct TooltipId(usize);
869
870impl TooltipId {
871 pub fn is_hovered(&self, window: &Window) -> bool {
873 window
874 .tooltip_bounds
875 .as_ref()
876 .is_some_and(|tooltip_bounds| {
877 tooltip_bounds.id == *self
878 && tooltip_bounds.bounds.contains(&window.mouse_position())
879 })
880 }
881}
882
883pub(crate) struct TooltipBounds {
884 id: TooltipId,
885 bounds: Bounds<Pixels>,
886}
887
888#[derive(Clone)]
889pub(crate) struct TooltipRequest {
890 id: TooltipId,
891 tooltip: AnyTooltip,
892}
893
894pub(crate) struct DeferredDraw {
895 current_view: EntityId,
896 priority: usize,
897 parent_node: DispatchNodeId,
898 element_id_stack: SmallVec<[ElementId; 32]>,
899 text_style_stack: Vec<TextStyleRefinement>,
900 content_mask: Option<ContentMask<Pixels>>,
901 rem_size: Pixels,
902 element: Option<AnyElement>,
903 absolute_offset: Point<Pixels>,
904 prepaint_range: Range<PrepaintStateIndex>,
905 paint_range: Range<PaintIndex>,
906}
907
908pub(crate) struct Frame {
909 pub(crate) focus: Option<FocusId>,
910 pub(crate) window_active: bool,
911 pub(crate) element_states: FxHashMap<(GlobalElementId, TypeId), ElementStateBox>,
912 accessed_element_states: Vec<(GlobalElementId, TypeId)>,
913 pub(crate) mouse_listeners: Vec<Option<AnyMouseListener>>,
914 pub(crate) dispatch_tree: DispatchTree,
915 pub(crate) scene: Scene,
916 pub(crate) hitboxes: Vec<Hitbox>,
917 pub(crate) window_control_hitboxes: Vec<(WindowControlArea, Hitbox)>,
918 pub(crate) deferred_draws: Vec<DeferredDraw>,
919 pub(crate) input_handlers: Vec<Option<PlatformInputHandler>>,
920 pub(crate) tooltip_requests: Vec<Option<TooltipRequest>>,
921 pub(crate) cursor_styles: Vec<CursorStyleRequest>,
922 #[cfg(any(test, feature = "test-support"))]
923 pub(crate) debug_bounds: FxHashMap<String, Bounds<Pixels>>,
924 #[cfg(any(feature = "inspector", debug_assertions))]
925 pub(crate) next_inspector_instance_ids: FxHashMap<Rc<crate::InspectorElementPath>, usize>,
926 #[cfg(any(feature = "inspector", debug_assertions))]
927 pub(crate) inspector_hitboxes: FxHashMap<HitboxId, crate::InspectorElementId>,
928 pub(crate) tab_stops: TabStopMap,
929}
930
931#[derive(Clone, Default)]
932pub(crate) struct PrepaintStateIndex {
933 hitboxes_index: usize,
934 tooltips_index: usize,
935 deferred_draws_index: usize,
936 dispatch_tree_index: usize,
937 accessed_element_states_index: usize,
938 line_layout_index: LineLayoutIndex,
939}
940
941#[derive(Clone, Default)]
942pub(crate) struct PaintIndex {
943 scene_index: usize,
944 mouse_listeners_index: usize,
945 input_handlers_index: usize,
946 cursor_styles_index: usize,
947 accessed_element_states_index: usize,
948 tab_handle_index: usize,
949 line_layout_index: LineLayoutIndex,
950}
951
952impl Frame {
953 pub(crate) fn new(dispatch_tree: DispatchTree) -> Self {
954 Frame {
955 focus: None,
956 window_active: false,
957 element_states: FxHashMap::default(),
958 accessed_element_states: Vec::new(),
959 mouse_listeners: Vec::new(),
960 dispatch_tree,
961 scene: Scene::default(),
962 hitboxes: Vec::new(),
963 window_control_hitboxes: Vec::new(),
964 deferred_draws: Vec::new(),
965 input_handlers: Vec::new(),
966 tooltip_requests: Vec::new(),
967 cursor_styles: Vec::new(),
968
969 #[cfg(any(test, feature = "test-support"))]
970 debug_bounds: FxHashMap::default(),
971
972 #[cfg(any(feature = "inspector", debug_assertions))]
973 next_inspector_instance_ids: FxHashMap::default(),
974
975 #[cfg(any(feature = "inspector", debug_assertions))]
976 inspector_hitboxes: FxHashMap::default(),
977 tab_stops: TabStopMap::default(),
978 }
979 }
980
981 pub(crate) fn clear(&mut self) {
982 self.element_states.clear();
983 self.accessed_element_states.clear();
984 self.mouse_listeners.clear();
985 self.dispatch_tree.clear();
986 self.scene.clear();
987 self.input_handlers.clear();
988 self.tooltip_requests.clear();
989 self.cursor_styles.clear();
990 self.hitboxes.clear();
991 self.window_control_hitboxes.clear();
992 self.deferred_draws.clear();
993 self.tab_stops.clear();
994 self.focus = None;
995
996 #[cfg(any(test, feature = "test-support"))]
997 {
998 self.debug_bounds.clear();
999 }
1000
1001 #[cfg(any(feature = "inspector", debug_assertions))]
1002 {
1003 self.next_inspector_instance_ids.clear();
1004 self.inspector_hitboxes.clear();
1005 }
1006 }
1007
1008 pub(crate) fn cursor_style(&self, window: &Window) -> Option<CursorStyle> {
1009 self.cursor_styles
1010 .iter()
1011 .rev()
1012 .fold_while(None, |style, request| match request.hitbox_id {
1013 None => Done(Some(request.style)),
1014 Some(hitbox_id) => Continue(style.or_else(|| {
1015 hitbox_id
1016 .is_hovered_ignoring_last_input(window)
1017 .then_some(request.style)
1018 })),
1019 })
1020 .into_inner()
1021 }
1022
1023 pub(crate) fn hit_test(&self, position: Point<Pixels>) -> HitTest {
1024 let mut set_hover_hitbox_count = false;
1025 let mut hit_test = HitTest::default();
1026 for hitbox in self.hitboxes.iter().rev() {
1027 let bounds = hitbox.bounds.intersect(&hitbox.content_mask.bounds);
1028 if bounds.contains(&position) {
1029 hit_test.ids.push(hitbox.id);
1030 if !set_hover_hitbox_count
1031 && hitbox.behavior == HitboxBehavior::BlockMouseExceptScroll
1032 {
1033 hit_test.hover_hitbox_count = hit_test.ids.len();
1034 set_hover_hitbox_count = true;
1035 }
1036 if hitbox.behavior == HitboxBehavior::BlockMouse {
1037 break;
1038 }
1039 }
1040 }
1041 if !set_hover_hitbox_count {
1042 hit_test.hover_hitbox_count = hit_test.ids.len();
1043 }
1044 hit_test
1045 }
1046
1047 pub(crate) fn focus_path(&self) -> SmallVec<[FocusId; 8]> {
1048 self.focus
1049 .map(|focus_id| self.dispatch_tree.focus_path(focus_id))
1050 .unwrap_or_default()
1051 }
1052
1053 pub(crate) fn finish(&mut self, prev_frame: &mut Self) {
1054 for element_state_key in &self.accessed_element_states {
1055 if let Some((element_state_key, element_state)) =
1056 prev_frame.element_states.remove_entry(element_state_key)
1057 {
1058 self.element_states.insert(element_state_key, element_state);
1059 }
1060 }
1061
1062 self.scene.finish();
1063 }
1064}
1065
1066#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
1067enum InputModality {
1068 Mouse,
1069 Keyboard,
1070 Touch,
1071}
1072
1073pub struct Window {
1075 pub(crate) handle: AnyWindowHandle,
1076 pub(crate) invalidator: WindowInvalidator,
1077 pub(crate) removed: bool,
1078 pub(crate) platform_window: Box<dyn PlatformWindow>,
1079 display_id: Option<DisplayId>,
1080 sprite_atlas: Arc<dyn PlatformAtlas>,
1081 text_system: Arc<WindowTextSystem>,
1082 text_rendering_mode: Rc<Cell<TextRenderingMode>>,
1083 rem_size: Pixels,
1084 rem_size_override_stack: SmallVec<[Pixels; 8]>,
1089 pub(crate) viewport_size: Size<Pixels>,
1090 layout_engine: Option<TaffyLayoutEngine>,
1091 pub(crate) root: Option<AnyView>,
1092 pub(crate) element_id_stack: SmallVec<[ElementId; 32]>,
1093 pub(crate) text_style_stack: Vec<TextStyleRefinement>,
1094 pub(crate) rendered_entity_stack: Vec<EntityId>,
1095 pub(crate) element_offset_stack: Vec<Point<Pixels>>,
1096 pub(crate) element_opacity: f32,
1097 pub(crate) content_mask_stack: Vec<ContentMask<Pixels>>,
1098 pub(crate) requested_autoscroll: Option<Bounds<Pixels>>,
1099 pub(crate) image_cache_stack: Vec<AnyImageCache>,
1100 pub(crate) rendered_frame: Frame,
1101 pub(crate) next_frame: Frame,
1102 next_hitbox_id: HitboxId,
1103 pub(crate) next_tooltip_id: TooltipId,
1104 pub(crate) tooltip_bounds: Option<TooltipBounds>,
1105 next_frame_callbacks: Rc<RefCell<Vec<FrameCallback>>>,
1106 pub(crate) dirty_views: FxHashSet<EntityId>,
1107 focus_listeners: SubscriberSet<(), AnyWindowFocusListener>,
1108 pub(crate) focus_lost_listeners: SubscriberSet<(), AnyObserver>,
1109 default_prevented: bool,
1110 mouse_position: Point<Pixels>,
1111 mouse_hit_test: HitTest,
1112 modifiers: Modifiers,
1113 capslock: Capslock,
1114 scale_factor: f32,
1115 pub(crate) bounds_observers: SubscriberSet<(), AnyObserver>,
1116 appearance: WindowAppearance,
1117 pub(crate) appearance_observers: SubscriberSet<(), AnyObserver>,
1118 pub(crate) button_layout_observers: SubscriberSet<(), AnyObserver>,
1119 active: Rc<Cell<bool>>,
1120 hovered: Rc<Cell<bool>>,
1121 pub(crate) needs_present: Rc<Cell<bool>>,
1122 pub(crate) input_rate_tracker: Rc<RefCell<InputRateTracker>>,
1125 #[cfg(feature = "input-latency-histogram")]
1126 input_latency_tracker: InputLatencyTracker,
1127 last_input_modality: InputModality,
1128 pub(crate) refreshing: bool,
1129 pub(crate) activation_observers: SubscriberSet<(), AnyObserver>,
1130 pub(crate) focus: Option<FocusId>,
1131 focus_enabled: bool,
1132 pub(crate) focus_generation: u64,
1135 pending_input: Option<PendingInput>,
1136 pending_modifier: ModifierState,
1137 pub(crate) pending_input_observers: SubscriberSet<(), AnyObserver>,
1138 prompt: Option<RenderablePromptHandle>,
1139 pub(crate) client_inset: Option<Pixels>,
1140 captured_hitbox: Option<HitboxId>,
1143 #[cfg(any(feature = "inspector", debug_assertions))]
1144 inspector: Option<Entity<Inspector>>,
1145 pub(crate) a11y: A11y,
1146}
1147
1148#[derive(Clone, Debug, Default)]
1149struct ModifierState {
1150 modifiers: Modifiers,
1151 saw_keystroke: bool,
1152}
1153
1154#[derive(Clone, Debug)]
1157pub(crate) struct InputRateTracker {
1158 timestamps: Vec<Instant>,
1159 window: Duration,
1160 inputs_per_second: u32,
1161 sustain_until: Instant,
1162 sustain_duration: Duration,
1163}
1164
1165impl Default for InputRateTracker {
1166 fn default() -> Self {
1167 Self {
1168 timestamps: Vec::new(),
1169 window: Duration::from_millis(100),
1170 inputs_per_second: 60,
1171 sustain_until: Instant::now(),
1172 sustain_duration: Duration::from_secs(1),
1173 }
1174 }
1175}
1176
1177impl InputRateTracker {
1178 pub fn record_input(&mut self) {
1179 let now = Instant::now();
1180 self.timestamps.push(now);
1181 self.prune_old_timestamps(now);
1182
1183 let min_events = self.inputs_per_second as u128 * self.window.as_millis() / 1000;
1184 if self.timestamps.len() as u128 >= min_events {
1185 self.sustain_until = now + self.sustain_duration;
1186 }
1187 }
1188
1189 pub fn is_high_rate(&self) -> bool {
1190 Instant::now() < self.sustain_until
1191 }
1192
1193 fn prune_old_timestamps(&mut self, now: Instant) {
1194 self.timestamps
1195 .retain(|&t| now.duration_since(t) <= self.window);
1196 }
1197}
1198
1199#[cfg(feature = "input-latency-histogram")]
1202#[derive(Clone)]
1203pub struct InputLatencySnapshot {
1204 pub latency_histogram: Histogram<u64>,
1206 pub events_per_frame_histogram: Histogram<u64>,
1208 pub mid_draw_events_dropped: u64,
1211}
1212
1213#[cfg(feature = "input-latency-histogram")]
1217struct InputLatencyTracker {
1218 first_input_at: Option<Instant>,
1221 pending_input_count: u64,
1223 latency_histogram: Histogram<u64>,
1225 events_per_frame_histogram: Histogram<u64>,
1227 mid_draw_events_dropped: u64,
1230}
1231
1232#[cfg(feature = "input-latency-histogram")]
1233impl InputLatencyTracker {
1234 fn new() -> Result<Self> {
1235 Ok(Self {
1236 first_input_at: None,
1237 pending_input_count: 0,
1238 latency_histogram: Histogram::new(3)
1239 .map_err(|e| anyhow!("Failed to create input latency histogram: {e}"))?,
1240 events_per_frame_histogram: Histogram::new(3)
1241 .map_err(|e| anyhow!("Failed to create events per frame histogram: {e}"))?,
1242 mid_draw_events_dropped: 0,
1243 })
1244 }
1245
1246 fn record_input(&mut self, dispatch_time: Instant) {
1249 self.first_input_at.get_or_insert(dispatch_time);
1250 self.pending_input_count += 1;
1251 }
1252
1253 fn record_mid_draw_input(&mut self) {
1256 self.mid_draw_events_dropped += 1;
1257 }
1258
1259 fn record_frame_presented(&mut self) {
1261 if let Some(first_input_at) = self.first_input_at.take() {
1262 let latency_nanos = first_input_at.elapsed().as_nanos() as u64;
1263 self.latency_histogram.record(latency_nanos).ok();
1264 }
1265 if self.pending_input_count > 0 {
1266 self.events_per_frame_histogram
1267 .record(self.pending_input_count)
1268 .ok();
1269 self.pending_input_count = 0;
1270 }
1271 }
1272
1273 fn snapshot(&self) -> InputLatencySnapshot {
1274 InputLatencySnapshot {
1275 latency_histogram: self.latency_histogram.clone(),
1276 events_per_frame_histogram: self.events_per_frame_histogram.clone(),
1277 mid_draw_events_dropped: self.mid_draw_events_dropped,
1278 }
1279 }
1280}
1281
1282#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1283pub(crate) enum DrawPhase {
1284 None,
1285 Prepaint,
1286 Paint,
1287 Focus,
1288}
1289
1290#[derive(Default, Debug)]
1291struct PendingInput {
1292 keystrokes: SmallVec<[Keystroke; 1]>,
1293 focus: Option<FocusId>,
1294 timer: Option<Task<()>>,
1295 needs_timeout: bool,
1296}
1297
1298pub(crate) struct ElementStateBox {
1299 pub(crate) inner: Box<dyn Any>,
1300 #[cfg(debug_assertions)]
1301 pub(crate) type_name: &'static str,
1302}
1303
1304fn default_bounds(display_id: Option<DisplayId>, cx: &mut App) -> WindowBounds {
1305 let active_window_bounds = cx
1310 .active_window()
1311 .and_then(|w| w.update(cx, |_, window, _| window.window_bounds()).ok());
1312
1313 const CASCADE_OFFSET: f32 = 25.0;
1314
1315 let display = display_id
1316 .map(|id| cx.find_display(id))
1317 .unwrap_or_else(|| cx.primary_display());
1318
1319 let default_placement = || Bounds::new(point(px(0.), px(0.)), DEFAULT_WINDOW_SIZE);
1320
1321 let display_bounds = display
1323 .as_ref()
1324 .map(|d| d.visible_bounds())
1325 .unwrap_or_else(default_placement);
1326
1327 let (
1328 Bounds {
1329 origin: base_origin,
1330 size: base_size,
1331 },
1332 window_bounds_ctor,
1333 ): (_, fn(Bounds<Pixels>) -> WindowBounds) = match active_window_bounds {
1334 Some(bounds) => match bounds {
1335 WindowBounds::Windowed(bounds) => (bounds, WindowBounds::Windowed),
1336 WindowBounds::Maximized(bounds) => (bounds, WindowBounds::Maximized),
1337 WindowBounds::Fullscreen(bounds) => (bounds, WindowBounds::Fullscreen),
1338 },
1339 None => (
1340 display
1341 .as_ref()
1342 .map(|d| d.default_bounds())
1343 .unwrap_or_else(default_placement),
1344 WindowBounds::Windowed,
1345 ),
1346 };
1347
1348 let cascade_offset = point(px(CASCADE_OFFSET), px(CASCADE_OFFSET));
1349 let proposed_origin = base_origin + cascade_offset;
1350 let proposed_bounds = Bounds::new(proposed_origin, base_size);
1351
1352 let display_right = display_bounds.origin.x + display_bounds.size.width;
1353 let display_bottom = display_bounds.origin.y + display_bounds.size.height;
1354 let window_right = proposed_bounds.origin.x + proposed_bounds.size.width;
1355 let window_bottom = proposed_bounds.origin.y + proposed_bounds.size.height;
1356
1357 let fits_horizontally = window_right <= display_right;
1358 let fits_vertically = window_bottom <= display_bottom;
1359
1360 let final_origin = match (fits_horizontally, fits_vertically) {
1361 (true, true) => proposed_origin,
1362 (false, true) => point(display_bounds.origin.x, base_origin.y),
1363 (true, false) => point(base_origin.x, display_bounds.origin.y),
1364 (false, false) => display_bounds.origin,
1365 };
1366 window_bounds_ctor(Bounds::new(final_origin, base_size))
1367}
1368
1369impl Window {
1370 pub(crate) fn new(
1371 handle: AnyWindowHandle,
1372 options: WindowOptions,
1373 cx: &mut App,
1374 ) -> Result<Self> {
1375 let WindowOptions {
1376 window_bounds,
1377 titlebar,
1378 focus,
1379 show,
1380 kind,
1381 is_movable,
1382 app_owns_titlebar_drag,
1383 is_resizable,
1384 is_minimizable,
1385 display_id,
1386 window_background,
1387 app_id,
1388 window_min_size,
1389 window_decorations,
1390 #[cfg_attr(
1391 not(any(target_os = "linux", target_os = "freebsd")),
1392 allow(unused_variables)
1393 )]
1394 icon,
1395 #[cfg_attr(not(target_os = "macos"), allow(unused_variables))]
1396 tabbing_identifier,
1397 } = options;
1398
1399 let initial_window_title = titlebar
1400 .as_ref()
1401 .and_then(|titlebar| titlebar.title.clone());
1402
1403 let window_bounds = window_bounds.unwrap_or_else(|| default_bounds(display_id, cx));
1404 let mut platform_window = cx.platform.open_window(
1405 handle,
1406 WindowParams {
1407 bounds: window_bounds.get_bounds(),
1408 titlebar,
1409 kind,
1410 is_movable,
1411 app_owns_titlebar_drag,
1412 is_resizable,
1413 is_minimizable,
1414 focus,
1415 show,
1416 display_id,
1417 window_min_size,
1418 app_id: app_id.clone(),
1419 icon,
1420 #[cfg(target_os = "macos")]
1421 tabbing_identifier,
1422 },
1423 )?;
1424
1425 let tab_bar_visible = platform_window.tab_bar_visible();
1426 SystemWindowTabController::init_visible(cx, tab_bar_visible);
1427 if let Some(tabs) = platform_window.tabbed_windows() {
1428 SystemWindowTabController::add_tab(cx, handle.window_id(), tabs);
1429 }
1430
1431 let display_id = platform_window.display().map(|display| display.id());
1432 let sprite_atlas = platform_window.sprite_atlas();
1433 let mouse_position = platform_window.mouse_position();
1434 let modifiers = platform_window.modifiers();
1435 let capslock = platform_window.capslock();
1436 let content_size = platform_window.content_size();
1437 let scale_factor = platform_window.scale_factor();
1438 let appearance = platform_window.appearance();
1439 let text_system = Arc::new(WindowTextSystem::new(cx.text_system().clone()));
1440 let invalidator = WindowInvalidator::new();
1441 let active = Rc::new(Cell::new(platform_window.is_active()));
1442 let hovered = Rc::new(Cell::new(platform_window.is_hovered()));
1443 let needs_present = Rc::new(Cell::new(false));
1444 let next_frame_callbacks: Rc<RefCell<Vec<FrameCallback>>> = Default::default();
1445 let input_rate_tracker = Rc::new(RefCell::new(InputRateTracker::default()));
1446 let last_frame_time = Rc::new(Cell::new(None));
1447
1448 platform_window
1449 .request_decorations(window_decorations.unwrap_or(WindowDecorations::Server));
1450 platform_window.set_background_appearance(window_background);
1451
1452 match window_bounds {
1453 WindowBounds::Fullscreen(_) => platform_window.toggle_fullscreen(),
1454 WindowBounds::Maximized(_) => platform_window.zoom(),
1455 WindowBounds::Windowed(_) => {}
1456 }
1457
1458 let accessibility_force_disabled = cx.accessibility_force_disabled;
1459 let a11y_active_flag = Arc::new(AtomicBool::new(false));
1460
1461 #[cfg(not(target_family = "wasm"))]
1462 if !accessibility_force_disabled {
1463 let mut initial_root_node = accesskit::Node::new(accesskit::Role::Window);
1464 if let Some(title) = &initial_window_title {
1465 initial_root_node.set_label(title.to_string());
1466 }
1467 let initial_tree = accesskit::TreeUpdate {
1468 nodes: vec![(ROOT_NODE_ID, initial_root_node)],
1469 tree: Some(accesskit::Tree::new(ROOT_NODE_ID)),
1470 tree_id: accesskit::TreeId::ROOT,
1471 focus: ROOT_NODE_ID,
1472 };
1473 let (activation_sender, activation_receiver) = async_channel::unbounded::<()>();
1474 let (deactivation_sender, deactivation_receiver) = async_channel::unbounded::<()>();
1475 let (action_sender, action_receiver) =
1476 async_channel::unbounded::<accesskit::ActionRequest>();
1477
1478 platform_window.a11y_init(crate::A11yCallbacks {
1479 activation: {
1480 let active_flag = a11y_active_flag.clone();
1481 Box::new(move || {
1482 log::info!("Accessibility activated");
1483 active_flag.store(true, SeqCst);
1484 activation_sender.send_blocking(()).log_err();
1485 Some(initial_tree.clone())
1486 })
1487 },
1488 action: Box::new(move |request| {
1489 action_sender.send_blocking(request).log_err();
1490 }),
1491 deactivation: {
1492 let active_flag = a11y_active_flag.clone();
1493 Box::new(move || {
1494 log::info!("Accessibility deactivated");
1495 active_flag.store(false, SeqCst);
1496 deactivation_sender.send_blocking(()).log_err();
1497 })
1498 },
1499 });
1500
1501 let mut async_cx = cx.to_async();
1507 cx.foreground_executor()
1508 .spawn(async move {
1509 while activation_receiver.recv().await.is_ok() {
1510 handle
1511 .update(&mut async_cx, |_, window, _| window.refresh())
1512 .log_err();
1513 }
1514 })
1515 .detach();
1516
1517 let mut async_cx = cx.to_async();
1518 cx.foreground_executor()
1519 .spawn(async move {
1520 while deactivation_receiver.recv().await.is_ok() {
1521 handle
1522 .update(&mut async_cx, |_, window, _| window.refresh())
1523 .log_err();
1524 }
1525 })
1526 .detach();
1527
1528 let mut async_cx = cx.to_async();
1529 cx.foreground_executor()
1530 .spawn(async move {
1531 while let Ok(request) = action_receiver.recv().await {
1532 handle
1533 .update(&mut async_cx, |_, window, cx| {
1534 window.handle_a11y_action(request, cx);
1535 })
1536 .log_err();
1537 }
1538 })
1539 .detach();
1540 }
1541
1542 platform_window.on_close(Box::new({
1543 let window_id = handle.window_id();
1544 let mut cx = cx.to_async();
1545 move || {
1546 let _ = handle.update(&mut cx, |_, window, _| window.remove_window());
1547 let _ = cx.update(|cx| {
1548 SystemWindowTabController::remove_tab(cx, window_id);
1549 });
1550 }
1551 }));
1552 platform_window.on_request_frame(Box::new({
1553 let mut cx = cx.to_async();
1554 let invalidator = invalidator.clone();
1555 let active = active.clone();
1556 let needs_present = needs_present.clone();
1557 let next_frame_callbacks = next_frame_callbacks.clone();
1558 let input_rate_tracker = input_rate_tracker.clone();
1559 let mut deferred_force_render = false;
1560 move |request_frame_options| {
1561 if draw_in_progress() {
1577 log::debug!("deferring re-entrant window draw request");
1578 deferred_force_render |= request_frame_options.force_render;
1579 return;
1580 }
1581 let force_render =
1585 mem::take(&mut deferred_force_render) || request_frame_options.force_render;
1586
1587 let thermal_state = handle
1588 .update(&mut cx, |_, _, cx| cx.thermal_state())
1589 .log_err();
1590
1591 let min_frame_interval = if request_frame_options.require_presentation
1595 || (!request_frame_options.force_render
1596 && next_frame_callbacks.borrow().is_empty())
1597 {
1598 None
1599 } else if !active.get() && !input_rate_tracker.borrow_mut().is_high_rate() {
1600 Some(Duration::from_micros(33333))
1601 } else if let Some(ThermalState::Critical | ThermalState::Serious) = thermal_state {
1602 Some(Duration::from_micros(16667))
1603 } else {
1604 None
1605 };
1606
1607 let now = Instant::now();
1608 if let Some(min_interval) = min_frame_interval {
1609 if let Some(last_frame) = last_frame_time.get()
1610 && now.duration_since(last_frame) < min_interval
1611 {
1612 deferred_force_render |= force_render;
1614 handle
1619 .update(&mut cx, |_, window, _| window.complete_frame())
1620 .log_err();
1621 return;
1622 }
1623 }
1624 last_frame_time.set(Some(now));
1625
1626 let next_frame_callbacks = next_frame_callbacks.take();
1627 if !next_frame_callbacks.is_empty() {
1628 handle
1629 .update(&mut cx, |_, window, cx| {
1630 for callback in next_frame_callbacks {
1631 callback(window, cx);
1632 }
1633 })
1634 .log_err();
1635 }
1636
1637 let needs_present = request_frame_options.require_presentation
1641 || needs_present.get()
1642 || input_rate_tracker.borrow_mut().is_high_rate();
1643
1644 if invalidator.is_dirty() || force_render {
1645 measure("frame duration", || {
1646 handle
1647 .update(&mut cx, |_, window, cx| {
1648 if force_render {
1649 window.refresh();
1652 }
1653 let arena_clear_needed = window.draw(cx);
1654 window.present();
1655 arena_clear_needed.clear(cx);
1656 })
1657 .log_err();
1658 })
1659 } else if needs_present {
1660 handle
1661 .update(&mut cx, |_, window, _| window.present())
1662 .log_err();
1663 }
1664
1665 handle
1666 .update(&mut cx, |_, window, _| {
1667 window.complete_frame();
1668 })
1669 .log_err();
1670 }
1671 }));
1672 platform_window.on_resize(Box::new({
1673 let mut cx = cx.to_async();
1674 move |_, _| {
1675 handle
1676 .update(&mut cx, |_, window, cx| window.bounds_changed(cx))
1677 .log_err();
1678 }
1679 }));
1680 platform_window.on_moved(Box::new({
1681 let mut cx = cx.to_async();
1682 move || {
1683 handle
1684 .update(&mut cx, |_, window, cx| window.bounds_changed(cx))
1685 .log_err();
1686 }
1687 }));
1688 platform_window.on_appearance_changed(Box::new({
1689 let cx = cx.to_async();
1690 let foreground_executor = cx.foreground_executor().clone();
1691 move || {
1692 let mut cx = cx.clone();
1693 foreground_executor
1696 .spawn(async move {
1697 handle
1698 .update(&mut cx, |_, window, cx| window.appearance_changed(cx))
1699 .log_err();
1700 })
1701 .detach();
1702 }
1703 }));
1704 platform_window.on_button_layout_changed(Box::new({
1705 let mut cx = cx.to_async();
1706 move || {
1707 handle
1708 .update(&mut cx, |_, window, cx| window.button_layout_changed(cx))
1709 .log_err();
1710 }
1711 }));
1712 platform_window.on_active_status_change(Box::new({
1713 let mut cx = cx.to_async();
1714 move |active| {
1715 handle
1716 .update(&mut cx, |_, window, cx| {
1717 window.active.set(active);
1718 window.modifiers = window.platform_window.modifiers();
1719 window.capslock = window.platform_window.capslock();
1720 window
1721 .activation_observers
1722 .clone()
1723 .retain(&(), |callback| callback(window, cx));
1724
1725 window.bounds_changed(cx);
1726 window.refresh();
1727
1728 SystemWindowTabController::update_last_active(cx, window.handle.id);
1729 })
1730 .log_err();
1731 }
1732 }));
1733 platform_window.on_hover_status_change(Box::new({
1734 let mut cx = cx.to_async();
1735 move |active| {
1736 handle
1737 .update(&mut cx, |_, window, _| {
1738 window.hovered.set(active);
1739 window.refresh();
1740 })
1741 .log_err();
1742 }
1743 }));
1744 platform_window.on_input({
1745 let mut cx = cx.to_async();
1746 Box::new(move |event| {
1747 handle
1748 .update(&mut cx, |_, window, cx| window.dispatch_event(event, cx))
1749 .log_err()
1750 .unwrap_or(DispatchEventResult::default())
1751 })
1752 });
1753 platform_window.on_hit_test_window_control({
1754 let mut cx = cx.to_async();
1755 Box::new(move || {
1756 handle
1757 .update(&mut cx, |_, window, _cx| {
1758 for (area, hitbox) in &window.rendered_frame.window_control_hitboxes {
1759 if window.mouse_hit_test.ids.contains(&hitbox.id) {
1760 return Some(*area);
1761 }
1762 }
1763 None
1764 })
1765 .log_err()
1766 .unwrap_or(None)
1767 })
1768 });
1769 platform_window.on_move_tab_to_new_window({
1770 let mut cx = cx.to_async();
1771 Box::new(move || {
1772 handle
1773 .update(&mut cx, |_, _window, cx| {
1774 SystemWindowTabController::move_tab_to_new_window(cx, handle.window_id());
1775 })
1776 .log_err();
1777 })
1778 });
1779 platform_window.on_merge_all_windows({
1780 let mut cx = cx.to_async();
1781 Box::new(move || {
1782 handle
1783 .update(&mut cx, |_, _window, cx| {
1784 SystemWindowTabController::merge_all_windows(cx, handle.window_id());
1785 })
1786 .log_err();
1787 })
1788 });
1789 platform_window.on_select_next_tab({
1790 let mut cx = cx.to_async();
1791 Box::new(move || {
1792 handle
1793 .update(&mut cx, |_, _window, cx| {
1794 SystemWindowTabController::select_next_tab(cx, handle.window_id());
1795 })
1796 .log_err();
1797 })
1798 });
1799 platform_window.on_select_previous_tab({
1800 let mut cx = cx.to_async();
1801 Box::new(move || {
1802 handle
1803 .update(&mut cx, |_, _window, cx| {
1804 SystemWindowTabController::select_previous_tab(cx, handle.window_id())
1805 })
1806 .log_err();
1807 })
1808 });
1809 platform_window.on_toggle_tab_bar({
1810 let mut cx = cx.to_async();
1811 Box::new(move || {
1812 handle
1813 .update(&mut cx, |_, window, cx| {
1814 let tab_bar_visible = window.platform_window.tab_bar_visible();
1815 SystemWindowTabController::set_visible(cx, tab_bar_visible);
1816 })
1817 .log_err();
1818 })
1819 });
1820
1821 if let Some(app_id) = app_id {
1822 platform_window.set_app_id(&app_id);
1823 }
1824
1825 platform_window.map_window().unwrap();
1826
1827 Ok(Window {
1828 handle,
1829 invalidator,
1830 removed: false,
1831 platform_window,
1832 display_id,
1833 sprite_atlas,
1834 text_system,
1835 text_rendering_mode: cx.text_rendering_mode.clone(),
1836 rem_size: px(16.),
1837 rem_size_override_stack: SmallVec::new(),
1838 viewport_size: content_size,
1839 layout_engine: Some(TaffyLayoutEngine::new()),
1840 root: None,
1841 element_id_stack: SmallVec::default(),
1842 text_style_stack: Vec::new(),
1843 rendered_entity_stack: Vec::new(),
1844 element_offset_stack: Vec::new(),
1845 content_mask_stack: Vec::new(),
1846 element_opacity: 1.0,
1847 requested_autoscroll: None,
1848 rendered_frame: Frame::new(DispatchTree::new(cx.keymap.clone(), cx.actions.clone())),
1849 next_frame: Frame::new(DispatchTree::new(cx.keymap.clone(), cx.actions.clone())),
1850 next_frame_callbacks,
1851 next_hitbox_id: HitboxId(0),
1852 next_tooltip_id: TooltipId::default(),
1853 tooltip_bounds: None,
1854 dirty_views: FxHashSet::default(),
1855 focus_listeners: SubscriberSet::new(),
1856 focus_lost_listeners: SubscriberSet::new(),
1857 default_prevented: true,
1858 mouse_position,
1859 mouse_hit_test: HitTest::default(),
1860 modifiers,
1861 capslock,
1862 scale_factor,
1863 bounds_observers: SubscriberSet::new(),
1864 appearance,
1865 appearance_observers: SubscriberSet::new(),
1866 button_layout_observers: SubscriberSet::new(),
1867 active,
1868 hovered,
1869 needs_present,
1870 input_rate_tracker,
1871 #[cfg(feature = "input-latency-histogram")]
1872 input_latency_tracker: InputLatencyTracker::new()?,
1873 last_input_modality: InputModality::Mouse,
1874 refreshing: false,
1875 activation_observers: SubscriberSet::new(),
1876 focus: None,
1877 focus_enabled: true,
1878 focus_generation: 0,
1879 pending_input: None,
1880 pending_modifier: ModifierState::default(),
1881 pending_input_observers: SubscriberSet::new(),
1882 prompt: None,
1883 client_inset: None,
1884 image_cache_stack: Vec::new(),
1885 captured_hitbox: None,
1886 #[cfg(any(feature = "inspector", debug_assertions))]
1887 inspector: None,
1888 a11y: A11y::new(
1889 a11y_active_flag,
1890 accessibility_force_disabled,
1891 initial_window_title,
1892 ),
1893 })
1894 }
1895
1896 pub(crate) fn new_focus_listener(
1897 &self,
1898 value: AnyWindowFocusListener,
1899 ) -> (Subscription, impl FnOnce() + use<>) {
1900 self.focus_listeners.insert((), value)
1901 }
1902}
1903
1904#[derive(Clone, Debug, Default, PartialEq, Eq)]
1905#[expect(missing_docs)]
1906pub struct DispatchEventResult {
1907 pub propagate: bool,
1908 pub default_prevented: bool,
1909}
1910
1911#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
1915#[repr(C)]
1916pub struct ContentMask<P: Clone + Debug + Default + PartialEq> {
1917 pub bounds: Bounds<P>,
1919}
1920
1921impl ContentMask<Pixels> {
1922 pub fn scale(&self, factor: f32) -> ContentMask<ScaledPixels> {
1924 ContentMask {
1925 bounds: self.bounds.scale(factor),
1926 }
1927 }
1928
1929 pub fn intersect(&self, other: &Self) -> Self {
1931 let bounds = self.bounds.intersect(&other.bounds);
1932 ContentMask { bounds }
1933 }
1934}
1935
1936impl Window {
1937 fn mark_view_dirty(&mut self, view_id: EntityId) {
1938 for view_id in self
1941 .rendered_frame
1942 .dispatch_tree
1943 .view_path_reversed(view_id)
1944 {
1945 if !self.dirty_views.insert(view_id) {
1946 break;
1947 }
1948 }
1949 }
1950
1951 pub fn observe_window_appearance(
1953 &self,
1954 mut callback: impl FnMut(&mut Window, &mut App) + 'static,
1955 ) -> Subscription {
1956 let (subscription, activate) = self.appearance_observers.insert(
1957 (),
1958 Box::new(move |window, cx| {
1959 callback(window, cx);
1960 true
1961 }),
1962 );
1963 activate();
1964 subscription
1965 }
1966
1967 pub fn observe_button_layout_changed(
1969 &self,
1970 mut callback: impl FnMut(&mut Window, &mut App) + 'static,
1971 ) -> Subscription {
1972 let (subscription, activate) = self.button_layout_observers.insert(
1973 (),
1974 Box::new(move |window, cx| {
1975 callback(window, cx);
1976 true
1977 }),
1978 );
1979 activate();
1980 subscription
1981 }
1982
1983 pub fn replace_root<E>(
1985 &mut self,
1986 cx: &mut App,
1987 build_view: impl FnOnce(&mut Window, &mut Context<E>) -> E,
1988 ) -> Entity<E>
1989 where
1990 E: 'static + Render,
1991 {
1992 let view = cx.new(|cx| build_view(self, cx));
1993 self.root = Some(view.clone().into());
1994 self.refresh();
1995 view
1996 }
1997
1998 pub fn root<E>(&self) -> Option<Option<Entity<E>>>
2000 where
2001 E: 'static + Render,
2002 {
2003 self.root
2004 .as_ref()
2005 .map(|view| view.clone().downcast::<E>().ok())
2006 }
2007
2008 pub fn window_handle(&self) -> AnyWindowHandle {
2010 self.handle
2011 }
2012
2013 pub fn refresh(&mut self) {
2015 if self.invalidator.not_drawing() {
2016 self.refreshing = true;
2017 self.invalidator.set_dirty(true);
2018 }
2019 }
2020
2021 pub fn remove_window(&mut self) {
2023 self.removed = true;
2024 }
2025
2026 pub fn focused(&self, cx: &App) -> Option<FocusHandle> {
2028 self.focus
2029 .and_then(|id| FocusHandle::for_id(id, &cx.focus_handles))
2030 }
2031
2032 pub fn focus(&mut self, handle: &FocusHandle, cx: &mut App) {
2034 if !self.focus_enabled || self.focus == Some(handle.id) {
2035 return;
2036 }
2037
2038 self.focus = Some(handle.id);
2039 self.focus_generation = self.focus_generation.wrapping_add(1);
2040 self.clear_pending_keystrokes();
2041
2042 let window_handle = self.handle;
2045 cx.defer(move |cx| {
2046 window_handle
2047 .update(cx, |_, window, cx| {
2048 window.pending_input_changed(cx);
2049 })
2050 .ok();
2051 });
2052
2053 self.refresh();
2054 }
2055
2056 pub fn blur(&mut self) {
2058 if !self.focus_enabled {
2059 return;
2060 }
2061
2062 if self.focus.is_some() {
2063 self.focus_generation = self.focus_generation.wrapping_add(1);
2064 }
2065 self.focus = None;
2066 self.refresh();
2067 }
2068
2069 pub fn disable_focus(&mut self) {
2071 self.blur();
2072 self.focus_enabled = false;
2073 }
2074
2075 pub fn focus_next(&mut self, cx: &mut App) {
2077 if !self.focus_enabled {
2078 return;
2079 }
2080
2081 if let Some(handle) = self.rendered_frame.tab_stops.next(self.focus.as_ref()) {
2082 self.focus(&handle, cx)
2083 }
2084 }
2085
2086 pub fn focus_prev(&mut self, cx: &mut App) {
2088 if !self.focus_enabled {
2089 return;
2090 }
2091
2092 if let Some(handle) = self.rendered_frame.tab_stops.prev(self.focus.as_ref()) {
2093 self.focus(&handle, cx)
2094 }
2095 }
2096
2097 pub fn text_system(&self) -> &Arc<WindowTextSystem> {
2099 &self.text_system
2100 }
2101
2102 pub fn text_style(&self) -> TextStyle {
2104 let mut style = TextStyle::default();
2105 for refinement in &self.text_style_stack {
2106 style.refine(refinement);
2107 }
2108 style
2109 }
2110
2111 pub fn is_maximized(&self) -> bool {
2115 self.platform_window.is_maximized()
2116 }
2117
2118 pub fn request_decorations(&self, decorations: WindowDecorations) {
2120 self.platform_window.request_decorations(decorations);
2121 }
2122
2123 pub fn set_exclusive_zone(&self, zone: Pixels) {
2129 self.platform_window.set_exclusive_zone(zone);
2130 }
2131
2132 #[cfg(all(target_os = "linux", feature = "wayland"))]
2137 pub fn set_exclusive_edge(&self, edge: crate::layer_shell::Anchor) {
2138 self.platform_window.set_exclusive_edge(edge);
2139 }
2140
2141 pub fn start_window_resize(&self, edge: ResizeEdge) {
2143 self.platform_window.start_window_resize(edge);
2144 }
2145
2146 pub fn set_input_region(&self, region: Option<&[Bounds<Pixels>]>) {
2153 self.platform_window.set_input_region(region);
2154 }
2155
2156 pub fn window_bounds(&self) -> WindowBounds {
2159 self.platform_window.window_bounds()
2160 }
2161
2162 pub fn inner_window_bounds(&self) -> WindowBounds {
2164 self.platform_window.inner_window_bounds()
2165 }
2166
2167 pub fn dispatch_action(&mut self, action: Box<dyn Action>, cx: &mut App) {
2169 let focus_id = self.focused(cx).map(|handle| handle.id);
2170
2171 let window = self.handle;
2172 cx.defer(move |cx| {
2173 window
2174 .update(cx, |_, window, cx| {
2175 let node_id = window.focus_node_id_in_rendered_frame(focus_id);
2176 window.dispatch_action_on_node(node_id, action.as_ref(), cx);
2177 })
2178 .log_err();
2179 })
2180 }
2181
2182 pub(crate) fn dispatch_keystroke_observers(
2183 &mut self,
2184 event: &dyn Any,
2185 action: Option<Box<dyn Action>>,
2186 context_stack: Vec<KeyContext>,
2187 cx: &mut App,
2188 ) {
2189 let Some(key_down_event) = event.downcast_ref::<KeyDownEvent>() else {
2190 return;
2191 };
2192
2193 cx.keystroke_observers.clone().retain(&(), move |callback| {
2194 (callback)(
2195 &KeystrokeEvent {
2196 keystroke: key_down_event.keystroke.clone(),
2197 action: action.as_ref().map(|action| action.boxed_clone()),
2198 context_stack: context_stack.clone(),
2199 },
2200 self,
2201 cx,
2202 )
2203 });
2204 }
2205
2206 pub(crate) fn dispatch_keystroke_interceptors(
2207 &mut self,
2208 event: &dyn Any,
2209 context_stack: Vec<KeyContext>,
2210 cx: &mut App,
2211 ) {
2212 let Some(key_down_event) = event.downcast_ref::<KeyDownEvent>() else {
2213 return;
2214 };
2215
2216 cx.keystroke_interceptors
2217 .clone()
2218 .retain(&(), move |callback| {
2219 (callback)(
2220 &KeystrokeEvent {
2221 keystroke: key_down_event.keystroke.clone(),
2222 action: None,
2223 context_stack: context_stack.clone(),
2224 },
2225 self,
2226 cx,
2227 )
2228 });
2229 }
2230
2231 pub fn defer(&self, cx: &mut App, f: impl FnOnce(&mut Window, &mut App) + 'static) {
2234 let handle = self.handle;
2235 cx.defer(move |cx| {
2236 handle.update(cx, |_, window, cx| f(window, cx)).ok();
2237 });
2238 }
2239
2240 pub fn observe<T: 'static>(
2244 &mut self,
2245 observed: &Entity<T>,
2246 cx: &mut App,
2247 mut on_notify: impl FnMut(Entity<T>, &mut Window, &mut App) + 'static,
2248 ) -> Subscription {
2249 let entity_id = observed.entity_id();
2250 let observed = observed.downgrade();
2251 let window_handle = self.handle;
2252 cx.new_observer(
2253 entity_id,
2254 Box::new(move |cx| {
2255 window_handle
2256 .update(cx, |_, window, cx| {
2257 if let Some(handle) = observed.upgrade() {
2258 on_notify(handle, window, cx);
2259 true
2260 } else {
2261 false
2262 }
2263 })
2264 .unwrap_or(false)
2265 }),
2266 )
2267 }
2268
2269 pub fn subscribe<Emitter, Evt>(
2273 &mut self,
2274 entity: &Entity<Emitter>,
2275 cx: &mut App,
2276 mut on_event: impl FnMut(Entity<Emitter>, &Evt, &mut Window, &mut App) + 'static,
2277 ) -> Subscription
2278 where
2279 Emitter: EventEmitter<Evt>,
2280 Evt: 'static,
2281 {
2282 let entity_id = entity.entity_id();
2283 let handle = entity.downgrade();
2284 let window_handle = self.handle;
2285 cx.new_subscription(
2286 entity_id,
2287 (
2288 TypeId::of::<Evt>(),
2289 Box::new(move |event, cx| {
2290 window_handle
2291 .update(cx, |_, window, cx| {
2292 if let Some(entity) = handle.upgrade() {
2293 let event = event.downcast_ref().expect("invalid event type");
2294 on_event(entity, event, window, cx);
2295 true
2296 } else {
2297 false
2298 }
2299 })
2300 .unwrap_or(false)
2301 }),
2302 ),
2303 )
2304 }
2305
2306 pub fn observe_release<T>(
2308 &self,
2309 entity: &Entity<T>,
2310 cx: &mut App,
2311 mut on_release: impl FnOnce(&mut T, &mut Window, &mut App) + 'static,
2312 ) -> Subscription
2313 where
2314 T: 'static,
2315 {
2316 let entity_id = entity.entity_id();
2317 let window_handle = self.handle;
2318 let (subscription, activate) = cx.release_listeners.insert(
2319 entity_id,
2320 Box::new(move |entity, cx| {
2321 let entity = entity.downcast_mut().expect("invalid entity type");
2322 let _ = window_handle.update(cx, |_, window, cx| on_release(entity, window, cx));
2323 }),
2324 );
2325 activate();
2326 subscription
2327 }
2328
2329 pub fn to_async(&self, cx: &App) -> AsyncWindowContext {
2332 AsyncWindowContext::new_context(cx.to_async(), self.handle)
2333 }
2334
2335 pub fn on_next_frame(&self, callback: impl FnOnce(&mut Window, &mut App) + 'static) {
2337 RefCell::borrow_mut(&self.next_frame_callbacks).push(Box::new(callback));
2338 }
2339
2340 pub fn request_animation_frame(&self) {
2353 let entity = self.current_view();
2354 self.on_next_frame(move |_, cx| cx.notify(entity));
2355 }
2356
2357 #[cfg(any(test, feature = "test-support"))]
2362 pub fn simulate_next_frame(&mut self, cx: &mut App) -> usize {
2363 let callbacks = self.next_frame_callbacks.take();
2364 let count = callbacks.len();
2365 for callback in callbacks {
2366 callback(self, cx);
2367 }
2368 count
2369 }
2370
2371 #[track_caller]
2375 pub fn spawn<AsyncFn, R>(&self, cx: &App, f: AsyncFn) -> Task<R>
2376 where
2377 R: 'static,
2378 AsyncFn: AsyncFnOnce(&mut AsyncWindowContext) -> R + 'static,
2379 {
2380 let handle = self.handle;
2381 cx.spawn(async move |app| {
2382 let mut async_window_cx = AsyncWindowContext::new_context(app.clone(), handle);
2383 f(&mut async_window_cx).await
2384 })
2385 }
2386
2387 #[track_caller]
2391 pub fn spawn_with_priority<AsyncFn, R>(
2392 &self,
2393 priority: Priority,
2394 cx: &App,
2395 f: AsyncFn,
2396 ) -> Task<R>
2397 where
2398 R: 'static,
2399 AsyncFn: AsyncFnOnce(&mut AsyncWindowContext) -> R + 'static,
2400 {
2401 let handle = self.handle;
2402 cx.spawn_with_priority(priority, async move |app| {
2403 let mut async_window_cx = AsyncWindowContext::new_context(app.clone(), handle);
2404 f(&mut async_window_cx).await
2405 })
2406 }
2407
2408 pub fn bounds_changed(&mut self, cx: &mut App) {
2414 self.scale_factor = self.platform_window.scale_factor();
2415 self.viewport_size = self.platform_window.content_size();
2416 self.display_id = self.platform_window.display().map(|display| display.id());
2417 self.mouse_position = self.platform_window.mouse_position();
2418
2419 self.refresh();
2420
2421 self.bounds_observers
2422 .clone()
2423 .retain(&(), |callback| callback(self, cx));
2424 }
2425
2426 pub fn bounds(&self) -> Bounds<Pixels> {
2428 self.platform_window.bounds()
2429 }
2430
2431 #[cfg(any(test, feature = "test-support"))]
2435 pub fn render_to_image(&self) -> anyhow::Result<image::RgbaImage> {
2436 self.platform_window
2437 .render_to_image(&self.rendered_frame.scene)
2438 }
2439
2440 pub fn resize(&mut self, size: Size<Pixels>) {
2442 self.platform_window.resize(size);
2443 }
2444
2445 pub fn is_fullscreen(&self) -> bool {
2447 self.platform_window.is_fullscreen()
2448 }
2449
2450 pub(crate) fn appearance_changed(&mut self, cx: &mut App) {
2451 self.appearance = self.platform_window.appearance();
2452
2453 self.appearance_observers
2454 .clone()
2455 .retain(&(), |callback| callback(self, cx));
2456 }
2457
2458 pub(crate) fn button_layout_changed(&mut self, cx: &mut App) {
2459 self.button_layout_observers
2460 .clone()
2461 .retain(&(), |callback| callback(self, cx));
2462 }
2463
2464 pub fn appearance(&self) -> WindowAppearance {
2466 self.appearance
2467 }
2468
2469 pub fn viewport_size(&self) -> Size<Pixels> {
2471 self.viewport_size
2472 }
2473
2474 pub fn is_window_active(&self) -> bool {
2476 self.active.get()
2477 }
2478
2479 pub fn is_window_hovered(&self) -> bool {
2483 if cfg!(any(
2484 target_os = "windows",
2485 target_os = "linux",
2486 target_os = "freebsd"
2487 )) {
2488 self.hovered.get()
2489 } else {
2490 self.is_window_active()
2491 }
2492 }
2493
2494 pub fn zoom_window(&self) {
2496 self.platform_window.zoom();
2497 }
2498
2499 pub fn show_window_menu(&self, position: Point<Pixels>) {
2501 self.platform_window.show_window_menu(position)
2502 }
2503
2504 pub fn start_window_move(&self) {
2509 self.platform_window.start_window_move()
2510 }
2511
2512 pub fn set_client_inset(&mut self, inset: Pixels) {
2514 self.client_inset = Some(inset);
2515 self.platform_window.set_client_inset(inset);
2516 }
2517
2518 pub fn client_inset(&self) -> Option<Pixels> {
2520 self.client_inset
2521 }
2522
2523 pub fn window_decorations(&self) -> Decorations {
2525 self.platform_window.window_decorations()
2526 }
2527
2528 pub fn window_controls(&self) -> WindowControls {
2530 self.platform_window.window_controls()
2531 }
2532
2533 pub fn set_window_title(&mut self, title: &str) {
2535 self.platform_window.set_title(title);
2536 self.a11y.set_window_title(title.to_string());
2537 }
2538
2539 #[cfg(target_os = "macos")]
2541 pub fn set_traffic_light_position(&self, position: Point<Pixels>) {
2542 self.platform_window.set_traffic_light_position(position);
2543 }
2544
2545 pub fn set_app_id(&mut self, app_id: &str) {
2547 self.platform_window.set_app_id(app_id);
2548 }
2549
2550 pub fn set_background_appearance(&self, background_appearance: WindowBackgroundAppearance) {
2552 self.platform_window
2553 .set_background_appearance(background_appearance);
2554 }
2555
2556 pub fn set_window_edited(&mut self, edited: bool) {
2558 self.platform_window.set_edited(edited);
2559 }
2560
2561 pub fn set_document_path(&self, path: Option<&std::path::Path>) {
2564 self.platform_window.set_document_path(path);
2565 }
2566
2567 pub fn display(&self, cx: &App) -> Option<Rc<dyn PlatformDisplay>> {
2569 cx.platform
2570 .displays()
2571 .into_iter()
2572 .find(|display| Some(display.id()) == self.display_id)
2573 }
2574
2575 pub fn show_character_palette(&self) {
2577 self.platform_window.show_character_palette();
2578 }
2579
2580 pub fn scale_factor(&self) -> f32 {
2584 self.scale_factor
2585 }
2586
2587 #[cfg(any(test, feature = "test-support"))]
2589 pub fn set_scale_factor(&mut self, scale_factor: f32) {
2590 self.scale_factor = scale_factor;
2591 self.refresh();
2592 }
2593
2594 pub fn rem_size(&self) -> Pixels {
2597 self.rem_size_override_stack
2598 .last()
2599 .copied()
2600 .unwrap_or(self.rem_size)
2601 }
2602
2603 pub fn set_rem_size(&mut self, rem_size: impl Into<Pixels>) {
2606 self.rem_size = rem_size.into();
2607 }
2608
2609 pub fn with_global_id<R>(
2612 &mut self,
2613 element_id: ElementId,
2614 f: impl FnOnce(&GlobalElementId, &mut Self) -> R,
2615 ) -> R {
2616 self.with_id(element_id, |this| {
2617 let global_id = GlobalElementId(Arc::from(&*this.element_id_stack));
2618
2619 f(&global_id, this)
2620 })
2621 }
2622
2623 #[inline]
2625 pub fn with_id<R>(
2626 &mut self,
2627 element_id: impl Into<ElementId>,
2628 f: impl FnOnce(&mut Self) -> R,
2629 ) -> R {
2630 self.element_id_stack.push(element_id.into());
2631 let result = f(self);
2632 self.element_id_stack.pop();
2633 result
2634 }
2635
2636 #[inline]
2642 pub fn with_rem_size<F, R>(&mut self, rem_size: Option<impl Into<Pixels>>, f: F) -> R
2643 where
2644 F: FnOnce(&mut Self) -> R,
2645 {
2646 self.invalidator.debug_assert_paint_or_prepaint();
2647
2648 if let Some(rem_size) = rem_size {
2649 self.rem_size_override_stack.push(rem_size.into());
2650 let result = f(self);
2651 self.rem_size_override_stack.pop();
2652 result
2653 } else {
2654 f(self)
2655 }
2656 }
2657
2658 pub fn line_height(&self) -> Pixels {
2660 self.text_style().line_height_in_pixels(self.rem_size())
2661 }
2662
2663 #[inline]
2665 pub fn pixel_snap(&self, value: Pixels) -> Pixels {
2666 px(round_to_device_pixel(value.0, self.scale_factor()) / self.scale_factor())
2667 }
2668
2669 #[inline]
2671 pub fn pixel_snap_f64(&self, value: f64) -> f64 {
2672 let scale_factor = f64::from(self.scale_factor());
2673 round_half_toward_zero_f64(value * scale_factor) / scale_factor
2674 }
2675
2676 #[inline]
2678 pub fn pixel_snap_bounds(&self, bounds: Bounds<Pixels>) -> Bounds<Pixels> {
2679 bounds.map(|c| self.pixel_snap(c))
2680 }
2681
2682 #[inline]
2684 pub fn pixel_snap_point(&self, position: Point<Pixels>) -> Point<Pixels> {
2685 position.map(|c| self.pixel_snap(c))
2686 }
2687
2688 #[inline]
2689 fn snap_bounds(&self, bounds: Bounds<Pixels>) -> Bounds<ScaledPixels> {
2690 let scale_factor = self.scale_factor();
2691 let left = round_to_device_pixel(bounds.left().0, scale_factor);
2692 let top = round_to_device_pixel(bounds.top().0, scale_factor);
2693 let right = round_to_device_pixel(bounds.right().0, scale_factor).max(left);
2694 let bottom = round_to_device_pixel(bounds.bottom().0, scale_factor).max(top);
2695 Bounds::from_corners(
2696 point(ScaledPixels(left), ScaledPixels(top)),
2697 point(ScaledPixels(right), ScaledPixels(bottom)),
2698 )
2699 }
2700
2701 #[inline]
2703 fn snap_stroke(&self, value: Pixels) -> ScaledPixels {
2704 ScaledPixels(round_stroke_to_device_pixel(value.0, self.scale_factor()))
2705 }
2706
2707 #[inline]
2708 fn snap_border_widths(&self, edges: Edges<Pixels>) -> Edges<ScaledPixels> {
2709 edges.map(|e| self.snap_stroke(*e))
2710 }
2711
2712 #[inline]
2714 fn cover_bounds(&self, bounds: Bounds<Pixels>) -> Bounds<ScaledPixels> {
2715 let scale_factor = self.scale_factor();
2716 let left = floor_to_device_pixel(bounds.left().0, scale_factor);
2717 let top = floor_to_device_pixel(bounds.top().0, scale_factor);
2718 let right = ceil_to_device_pixel(bounds.right().0, scale_factor).max(left);
2719 let bottom = ceil_to_device_pixel(bounds.bottom().0, scale_factor).max(top);
2720 Bounds::from_corners(
2721 point(ScaledPixels(left), ScaledPixels(top)),
2722 point(ScaledPixels(right), ScaledPixels(bottom)),
2723 )
2724 }
2725
2726 #[inline]
2727 fn snapped_content_mask(&self) -> ContentMask<ScaledPixels> {
2728 ContentMask {
2729 bounds: self.cover_bounds(self.content_mask().bounds),
2730 }
2731 }
2732
2733 pub fn prevent_default(&mut self) {
2736 self.default_prevented = true;
2737 }
2738
2739 pub fn default_prevented(&self) -> bool {
2741 self.default_prevented
2742 }
2743
2744 pub fn is_action_available(&self, action: &dyn Action, cx: &App) -> bool {
2746 let node_id =
2747 self.focus_node_id_in_rendered_frame(self.focused(cx).map(|handle| handle.id));
2748 self.rendered_frame
2749 .dispatch_tree
2750 .is_action_available(action, node_id)
2751 }
2752
2753 pub fn is_action_available_in(&self, action: &dyn Action, focus_handle: &FocusHandle) -> bool {
2755 let node_id = self.focus_node_id_in_rendered_frame(Some(focus_handle.id));
2756 self.rendered_frame
2757 .dispatch_tree
2758 .is_action_available(action, node_id)
2759 }
2760
2761 pub fn mouse_position(&self) -> Point<Pixels> {
2763 self.mouse_position
2764 }
2765
2766 pub fn capture_pointer(&mut self, hitbox_id: HitboxId) {
2773 self.captured_hitbox = Some(hitbox_id);
2774 }
2775
2776 pub fn release_pointer(&mut self) {
2778 self.captured_hitbox = None;
2779 }
2780
2781 pub fn captured_hitbox(&self) -> Option<HitboxId> {
2783 self.captured_hitbox
2784 }
2785
2786 pub fn modifiers(&self) -> Modifiers {
2788 self.modifiers
2789 }
2790
2791 pub fn last_input_was_keyboard(&self) -> bool {
2794 self.last_input_modality == InputModality::Keyboard
2795 }
2796
2797 pub fn capslock(&self) -> Capslock {
2799 self.capslock
2800 }
2801
2802 fn complete_frame(&self) {
2803 self.platform_window.completed_frame();
2804 }
2805
2806 #[profiling::function]
2809 pub fn draw(&mut self, cx: &mut App) -> ArenaClearNeeded {
2810 let frame_dirty = self.invalidator.take_frame_dirty();
2813 let draw_started_at = profiler::frame_trace_enabled().then(Instant::now);
2814
2815 let arena_scope = ElementArenaScope::enter(&cx.element_arena);
2818
2819 self.invalidate_entities();
2820 cx.entities.clear_accessed();
2821 debug_assert!(self.rendered_entity_stack.is_empty());
2822 self.invalidator.set_dirty(false);
2823 self.requested_autoscroll = None;
2824
2825 if let Some(input_handler) = self.platform_window.take_input_handler() {
2830 if let Some(slot) = self
2831 .rendered_frame
2832 .input_handlers
2833 .iter_mut()
2834 .rev()
2835 .find(|h| h.is_none())
2836 {
2837 *slot = Some(input_handler);
2838 } else {
2839 self.rendered_frame.input_handlers.push(Some(input_handler));
2840 }
2841 }
2842 if !cx.mode.skip_drawing() {
2843 self.draw_roots(cx);
2844 }
2845 self.dirty_views.clear();
2846 self.next_frame.window_active = self.active.get();
2847
2848 if let Some(input_handler) = self
2854 .next_frame
2855 .input_handlers
2856 .iter_mut()
2857 .rev()
2858 .find_map(|h| h.take())
2859 {
2860 self.platform_window.set_input_handler(input_handler);
2861 }
2862
2863 self.layout_engine.as_mut().unwrap().clear();
2864 self.text_system().finish_frame();
2865 self.next_frame.finish(&mut self.rendered_frame);
2866
2867 self.invalidator.set_phase(DrawPhase::Focus);
2868 let previous_focus_path = self.rendered_frame.focus_path();
2869 let previous_window_active = self.rendered_frame.window_active;
2870 mem::swap(&mut self.rendered_frame, &mut self.next_frame);
2871 self.next_frame.clear();
2872 let current_focus_path = self.rendered_frame.focus_path();
2873 let current_window_active = self.rendered_frame.window_active;
2874 let mut focus_before_listeners = self.focus;
2875
2876 if previous_focus_path != current_focus_path
2877 || previous_window_active != current_window_active
2878 {
2879 if !previous_focus_path.is_empty() && current_focus_path.is_empty() {
2880 self.focus_lost_listeners
2881 .clone()
2882 .retain(&(), |listener| listener(self, cx));
2883 focus_before_listeners = self.focus;
2888 }
2889
2890 let event = WindowFocusEvent {
2891 previous_focus_path: if previous_window_active {
2892 previous_focus_path
2893 } else {
2894 Default::default()
2895 },
2896 current_focus_path: if current_window_active {
2897 current_focus_path
2898 } else {
2899 Default::default()
2900 },
2901 };
2902 self.focus_listeners
2903 .clone()
2904 .retain(&(), |listener| listener(&event, self, cx));
2905 }
2906
2907 debug_assert!(self.rendered_entity_stack.is_empty());
2908 self.record_entities_accessed(cx);
2909 self.reset_cursor_style(cx);
2910 self.refreshing = false;
2911 self.invalidator.set_phase(DrawPhase::None);
2912 if self.focus != focus_before_listeners {
2917 self.refresh();
2918 }
2919 self.needs_present.set(true);
2920
2921 if let Some(draw_start) = draw_started_at {
2922 profiler::record_frame_timing(profiler::FrameTiming {
2923 window_id: self.handle.window_id(),
2924 dirty_at: frame_dirty.dirty_at,
2925 invalidations: frame_dirty.invalidations,
2926 draw_start,
2927 draw_end: Instant::now(),
2928 });
2929 }
2930
2931 arena_scope.exit(&cx.element_arena)
2934 }
2935
2936 fn record_entities_accessed(&mut self, cx: &mut App) {
2937 let mut entities_ref = cx.entities.accessed_entities.get_mut();
2938 let mut entities = mem::take(entities_ref.deref_mut());
2939 let handle = self.handle;
2940 cx.record_entities_accessed(
2941 handle,
2942 self.invalidator.clone(),
2944 &entities,
2945 );
2946 let mut entities_ref = cx.entities.accessed_entities.get_mut();
2947 mem::swap(&mut entities, entities_ref.deref_mut());
2948 }
2949
2950 fn invalidate_entities(&mut self) {
2951 let mut views = self.invalidator.take_views();
2952 for entity in views.drain() {
2953 self.mark_view_dirty(entity);
2954 }
2955 self.invalidator.replace_views(views);
2956 }
2957
2958 #[profiling::function]
2959 fn present(&mut self) {
2960 self.platform_window.draw(&self.rendered_frame.scene);
2961 #[cfg(feature = "input-latency-histogram")]
2962 self.input_latency_tracker.record_frame_presented();
2963 self.needs_present.set(false);
2964 profiling::finish_frame!();
2965 }
2966
2967 #[cfg(feature = "bench")]
2973 pub fn present_if_needed(&mut self) {
2974 if self.needs_present.get() {
2975 self.present();
2976 }
2977 }
2978
2979 #[cfg(feature = "input-latency-histogram")]
2981 pub fn input_latency_snapshot(&self) -> InputLatencySnapshot {
2982 self.input_latency_tracker.snapshot()
2983 }
2984
2985 fn draw_roots(&mut self, cx: &mut App) {
2986 self.invalidator.set_phase(DrawPhase::Prepaint);
2987 self.tooltip_bounds.take();
2988
2989 self.a11y.sync_active_flag();
2990 if self.a11y.is_active() {
2991 self.a11y.begin_frame();
2992 }
2993
2994 let _inspector_width: Pixels = rems(30.0).to_pixels(self.rem_size());
2995 let root_size = {
2996 #[cfg(any(feature = "inspector", debug_assertions))]
2997 {
2998 if self.inspector.is_some() {
2999 let mut size = self.viewport_size;
3000 size.width = (size.width - _inspector_width).max(px(0.0));
3001 size
3002 } else {
3003 self.viewport_size
3004 }
3005 }
3006 #[cfg(not(any(feature = "inspector", debug_assertions)))]
3007 {
3008 self.viewport_size
3009 }
3010 };
3011
3012 let scale_factor = self.scale_factor();
3016 let mut root_element = self.root.as_ref().unwrap().clone().into_any_element();
3017 let root_layout_id = root_element.request_layout(self, cx);
3018 self.layout_engine
3019 .as_mut()
3020 .unwrap()
3021 .stretch_auto_size_to_fill(root_layout_id, root_size, scale_factor);
3022 root_element.prepaint_as_root(Point::default(), root_size.into(), self, cx);
3023
3024 #[cfg(any(feature = "inspector", debug_assertions))]
3025 let inspector_element = self.prepaint_inspector(_inspector_width, cx);
3026
3027 self.prepaint_deferred_draws(cx);
3028
3029 let mut prompt_element = None;
3030 let mut active_drag_element = None;
3031 let mut tooltip_element = None;
3032 if let Some(prompt) = self.prompt.take() {
3033 let mut element = prompt.view.any_view().into_any_element();
3034 let prompt_layout_id = element.request_layout(self, cx);
3035 self.layout_engine
3036 .as_mut()
3037 .unwrap()
3038 .stretch_auto_size_to_fill(prompt_layout_id, root_size, scale_factor);
3039 element.prepaint_as_root(Point::default(), root_size.into(), self, cx);
3040 prompt_element = Some(element);
3041 self.prompt = Some(prompt);
3042 } else if let Some(active_drag) = cx.active_drag.take() {
3043 let mut element = active_drag.view.clone().into_any_element();
3044 let offset = self.mouse_position() - active_drag.cursor_offset;
3045 element.prepaint_as_root(offset, AvailableSpace::min_size(), self, cx);
3046 active_drag_element = Some(element);
3047 cx.active_drag = Some(active_drag);
3048 } else {
3049 tooltip_element = self.prepaint_tooltip(cx);
3050 }
3051
3052 self.mouse_hit_test = self.next_frame.hit_test(self.mouse_position);
3053
3054 self.invalidator.set_phase(DrawPhase::Paint);
3056 root_element.paint(self, cx);
3057
3058 #[cfg(any(feature = "inspector", debug_assertions))]
3059 self.paint_inspector(inspector_element, cx);
3060
3061 self.paint_deferred_draws(cx);
3062
3063 if let Some(mut prompt_element) = prompt_element {
3064 prompt_element.paint(self, cx);
3065 } else if let Some(mut drag_element) = active_drag_element {
3066 drag_element.paint(self, cx);
3067 } else if let Some(mut tooltip_element) = tooltip_element {
3068 tooltip_element.paint(self, cx);
3069 }
3070
3071 #[cfg(any(feature = "inspector", debug_assertions))]
3072 self.paint_inspector_hitbox(cx);
3073
3074 let a11y_active_start_of_frame = self.a11y.is_active();
3076 self.a11y.sync_active_flag();
3077 let a11y_active_end_of_frame = self.a11y.is_active();
3078
3079 let should_send_a11y_update = a11y_active_start_of_frame && a11y_active_end_of_frame;
3080
3081 if a11y_active_start_of_frame {
3082 let frame_info = crate::window::a11y::debug::FrameDebugInfo {
3085 viewport_size: self.viewport_size,
3086 scale_factor: self.scale_factor,
3087 tab_stop_count: self.next_frame.tab_stops.tab_stop_count(),
3088 };
3089 let tree_update = self.a11y.end_frame(frame_info);
3091
3092 if should_send_a11y_update {
3093 log::debug!(
3094 "Sending a11y tree update: {} nodes",
3095 tree_update.nodes.len()
3096 );
3097 self.platform_window.a11y_tree_update(tree_update);
3098 }
3099 }
3100 }
3101
3102 fn prepaint_tooltip(&mut self, cx: &mut App) -> Option<AnyElement> {
3103 for tooltip_request_index in (0..self.next_frame.tooltip_requests.len()).rev() {
3105 let Some(Some(tooltip_request)) = self
3106 .next_frame
3107 .tooltip_requests
3108 .get(tooltip_request_index)
3109 .cloned()
3110 else {
3111 log::error!("Unexpectedly absent TooltipRequest");
3112 continue;
3113 };
3114 let mut element = tooltip_request.tooltip.view.clone().into_any_element();
3115 let mouse_position = tooltip_request.tooltip.mouse_position;
3116 let tooltip_size = element.layout_as_root(AvailableSpace::min_size(), self, cx);
3117
3118 let mut tooltip_bounds =
3119 Bounds::new(mouse_position + point(px(1.), px(1.)), tooltip_size);
3120 let window_bounds = Bounds {
3121 origin: Point::default(),
3122 size: self.viewport_size(),
3123 };
3124
3125 if tooltip_bounds.right() > window_bounds.right() {
3126 let new_x = mouse_position.x - tooltip_bounds.size.width - px(1.);
3127 if new_x >= Pixels::ZERO {
3128 tooltip_bounds.origin.x = new_x;
3129 } else {
3130 tooltip_bounds.origin.x = cmp::max(
3131 Pixels::ZERO,
3132 tooltip_bounds.origin.x - tooltip_bounds.right() - window_bounds.right(),
3133 );
3134 }
3135 }
3136
3137 if tooltip_bounds.bottom() > window_bounds.bottom() {
3138 let new_y = mouse_position.y - tooltip_bounds.size.height - px(1.);
3139 if new_y >= Pixels::ZERO {
3140 tooltip_bounds.origin.y = new_y;
3141 } else {
3142 tooltip_bounds.origin.y = cmp::max(
3143 Pixels::ZERO,
3144 tooltip_bounds.origin.y - tooltip_bounds.bottom() - window_bounds.bottom(),
3145 );
3146 }
3147 }
3148
3149 let is_visible =
3153 (tooltip_request.tooltip.check_visible_and_update)(tooltip_bounds, self, cx);
3154 if !is_visible {
3155 continue;
3156 }
3157
3158 self.with_absolute_element_offset(tooltip_bounds.origin, |window| {
3159 element.prepaint(window, cx)
3160 });
3161
3162 self.tooltip_bounds = Some(TooltipBounds {
3163 id: tooltip_request.id,
3164 bounds: tooltip_bounds,
3165 });
3166 return Some(element);
3167 }
3168 None
3169 }
3170
3171 fn prepaint_deferred_draws(&mut self, cx: &mut App) {
3172 assert_eq!(self.element_id_stack.len(), 0);
3173
3174 let mut round_start = 0;
3185 let mut depth = 0;
3186 loop {
3187 let round_end = self.next_frame.deferred_draws.len();
3188 if round_start == round_end {
3189 break;
3190 }
3191 assert!(depth < 10, "Exceeded maximum (10) deferred depth");
3193 depth += 1;
3194
3195 let mut traversal_order = (round_start..round_end).collect::<SmallVec<[usize; 8]>>();
3197 traversal_order.sort_by_key(|ix| self.next_frame.deferred_draws[*ix].priority);
3198
3199 for deferred_draw_ix in traversal_order {
3200 let (element, parent_node, current_view, rem_size, absolute_offset, prepaint_range) = {
3201 let deferred_draw = &mut self.next_frame.deferred_draws[deferred_draw_ix];
3202 self.element_id_stack
3203 .clone_from(&deferred_draw.element_id_stack);
3204 self.text_style_stack
3205 .clone_from(&deferred_draw.text_style_stack);
3206 (
3207 deferred_draw.element.take(),
3208 deferred_draw.parent_node,
3209 deferred_draw.current_view,
3210 deferred_draw.rem_size,
3211 deferred_draw.absolute_offset,
3212 deferred_draw.prepaint_range.clone(),
3213 )
3214 };
3215 self.next_frame.dispatch_tree.set_active_node(parent_node);
3216
3217 let prepaint_start = self.prepaint_index();
3218 if let Some(mut element) = element {
3219 self.with_rendered_view(current_view, |window| {
3220 window.with_rem_size(Some(rem_size), |window| {
3221 window.with_absolute_element_offset(absolute_offset, |window| {
3222 element.prepaint(window, cx);
3223 });
3224 });
3225 });
3226 self.next_frame.deferred_draws[deferred_draw_ix].element = Some(element);
3227 } else {
3228 self.reuse_prepaint(prepaint_range);
3229 }
3230 let prepaint_end = self.prepaint_index();
3231 self.next_frame.deferred_draws[deferred_draw_ix].prepaint_range =
3232 prepaint_start..prepaint_end;
3233 }
3234
3235 self.element_id_stack.clear();
3236 self.text_style_stack.clear();
3237 round_start = round_end;
3238 }
3239 }
3240
3241 fn paint_deferred_draws(&mut self, cx: &mut App) {
3242 assert_eq!(self.element_id_stack.len(), 0);
3243
3244 if self.next_frame.deferred_draws.len() == 0 {
3247 return;
3248 }
3249
3250 self.next_frame.scene.raise_order_floor();
3254
3255 let traversal_order = self.deferred_draw_traversal_order();
3256 let mut deferred_draws = mem::take(&mut self.next_frame.deferred_draws);
3257 for deferred_draw_ix in traversal_order {
3258 let mut deferred_draw = &mut deferred_draws[deferred_draw_ix];
3259 self.element_id_stack
3260 .clone_from(&deferred_draw.element_id_stack);
3261 self.next_frame
3262 .dispatch_tree
3263 .set_active_node(deferred_draw.parent_node);
3264
3265 let paint_start = self.paint_index();
3266 let content_mask = deferred_draw.content_mask;
3267 if let Some(element) = deferred_draw.element.as_mut() {
3268 self.with_rendered_view(deferred_draw.current_view, |window| {
3269 window.with_content_mask(content_mask, |window| {
3270 window.with_rem_size(Some(deferred_draw.rem_size), |window| {
3271 element.paint(window, cx);
3272 });
3273 })
3274 })
3275 } else {
3276 self.reuse_paint(deferred_draw.paint_range.clone());
3277 }
3278 let paint_end = self.paint_index();
3279 deferred_draw.paint_range = paint_start..paint_end;
3280 }
3281 self.next_frame.deferred_draws = deferred_draws;
3282 self.element_id_stack.clear();
3283 }
3284
3285 fn deferred_draw_traversal_order(&mut self) -> SmallVec<[usize; 8]> {
3286 let deferred_count = self.next_frame.deferred_draws.len();
3287 let mut sorted_indices = (0..deferred_count).collect::<SmallVec<[_; 8]>>();
3288 sorted_indices.sort_by_key(|ix| self.next_frame.deferred_draws[*ix].priority);
3289 sorted_indices
3290 }
3291
3292 pub(crate) fn prepaint_index(&self) -> PrepaintStateIndex {
3293 PrepaintStateIndex {
3294 hitboxes_index: self.next_frame.hitboxes.len(),
3295 tooltips_index: self.next_frame.tooltip_requests.len(),
3296 deferred_draws_index: self.next_frame.deferred_draws.len(),
3297 dispatch_tree_index: self.next_frame.dispatch_tree.len(),
3298 accessed_element_states_index: self.next_frame.accessed_element_states.len(),
3299 line_layout_index: self.text_system.layout_index(),
3300 }
3301 }
3302
3303 pub(crate) fn reuse_prepaint(&mut self, range: Range<PrepaintStateIndex>) {
3304 self.next_frame.hitboxes.extend(
3305 self.rendered_frame.hitboxes[range.start.hitboxes_index..range.end.hitboxes_index]
3306 .iter()
3307 .cloned(),
3308 );
3309 self.next_frame.tooltip_requests.extend(
3310 self.rendered_frame.tooltip_requests
3311 [range.start.tooltips_index..range.end.tooltips_index]
3312 .iter_mut()
3313 .map(|request| request.take()),
3314 );
3315 self.next_frame.accessed_element_states.extend(
3316 self.rendered_frame.accessed_element_states[range.start.accessed_element_states_index
3317 ..range.end.accessed_element_states_index]
3318 .iter()
3319 .map(|(id, type_id)| (id.clone(), *type_id)),
3320 );
3321 self.text_system
3322 .reuse_layouts(range.start.line_layout_index..range.end.line_layout_index);
3323
3324 let reused_subtree = self.next_frame.dispatch_tree.reuse_subtree(
3325 range.start.dispatch_tree_index..range.end.dispatch_tree_index,
3326 &mut self.rendered_frame.dispatch_tree,
3327 self.focus,
3328 );
3329
3330 if reused_subtree.contains_focus() {
3331 self.next_frame.focus = self.focus;
3332 }
3333
3334 self.next_frame.deferred_draws.extend(
3335 self.rendered_frame.deferred_draws
3336 [range.start.deferred_draws_index..range.end.deferred_draws_index]
3337 .iter()
3338 .map(|deferred_draw| DeferredDraw {
3339 current_view: deferred_draw.current_view,
3340 parent_node: reused_subtree.refresh_node_id(deferred_draw.parent_node),
3341 element_id_stack: deferred_draw.element_id_stack.clone(),
3342 text_style_stack: deferred_draw.text_style_stack.clone(),
3343 content_mask: deferred_draw.content_mask,
3344 rem_size: deferred_draw.rem_size,
3345 priority: deferred_draw.priority,
3346 element: None,
3347 absolute_offset: deferred_draw.absolute_offset,
3348 prepaint_range: deferred_draw.prepaint_range.clone(),
3349 paint_range: deferred_draw.paint_range.clone(),
3350 }),
3351 );
3352 }
3353
3354 pub(crate) fn paint_index(&self) -> PaintIndex {
3355 PaintIndex {
3356 scene_index: self.next_frame.scene.len(),
3357 mouse_listeners_index: self.next_frame.mouse_listeners.len(),
3358 input_handlers_index: self.next_frame.input_handlers.len(),
3359 cursor_styles_index: self.next_frame.cursor_styles.len(),
3360 accessed_element_states_index: self.next_frame.accessed_element_states.len(),
3361 tab_handle_index: self.next_frame.tab_stops.paint_index(),
3362 line_layout_index: self.text_system.layout_index(),
3363 }
3364 }
3365
3366 pub(crate) fn reuse_paint(&mut self, range: Range<PaintIndex>) {
3367 self.next_frame.cursor_styles.extend(
3368 self.rendered_frame.cursor_styles
3369 [range.start.cursor_styles_index..range.end.cursor_styles_index]
3370 .iter()
3371 .cloned(),
3372 );
3373 self.next_frame.input_handlers.extend(
3374 self.rendered_frame.input_handlers
3375 [range.start.input_handlers_index..range.end.input_handlers_index]
3376 .iter_mut()
3377 .map(|handler| handler.take()),
3378 );
3379 self.next_frame.mouse_listeners.extend(
3380 self.rendered_frame.mouse_listeners
3381 [range.start.mouse_listeners_index..range.end.mouse_listeners_index]
3382 .iter_mut()
3383 .map(|listener| listener.take()),
3384 );
3385 self.next_frame.accessed_element_states.extend(
3386 self.rendered_frame.accessed_element_states[range.start.accessed_element_states_index
3387 ..range.end.accessed_element_states_index]
3388 .iter()
3389 .map(|(id, type_id)| (id.clone(), *type_id)),
3390 );
3391 self.next_frame.tab_stops.replay(
3392 &self.rendered_frame.tab_stops.insertion_history
3393 [range.start.tab_handle_index..range.end.tab_handle_index],
3394 );
3395
3396 self.text_system
3397 .reuse_layouts(range.start.line_layout_index..range.end.line_layout_index);
3398 self.next_frame.scene.replay(
3399 range.start.scene_index..range.end.scene_index,
3400 &self.rendered_frame.scene,
3401 );
3402 }
3403
3404 pub fn with_text_style<F, R>(&mut self, style: Option<TextStyleRefinement>, f: F) -> R
3408 where
3409 F: FnOnce(&mut Self) -> R,
3410 {
3411 self.invalidator.debug_assert_paint_or_prepaint();
3412 if let Some(style) = style {
3413 self.text_style_stack.push(style);
3414 let result = f(self);
3415 self.text_style_stack.pop();
3416 result
3417 } else {
3418 f(self)
3419 }
3420 }
3421
3422 pub fn set_cursor_style(&mut self, style: CursorStyle, hitbox: &Hitbox) {
3425 self.invalidator.debug_assert_paint();
3426 self.next_frame.cursor_styles.push(CursorStyleRequest {
3427 hitbox_id: Some(hitbox.id),
3428 style,
3429 });
3430 }
3431
3432 pub fn set_window_cursor_style(&mut self, style: CursorStyle) {
3437 self.invalidator.debug_assert_paint();
3438 self.next_frame.cursor_styles.push(CursorStyleRequest {
3439 hitbox_id: None,
3440 style,
3441 })
3442 }
3443
3444 pub fn set_tooltip(&mut self, tooltip: AnyTooltip) -> TooltipId {
3447 self.invalidator.debug_assert_prepaint();
3448 let id = TooltipId(post_inc(&mut self.next_tooltip_id.0));
3449 self.next_frame
3450 .tooltip_requests
3451 .push(Some(TooltipRequest { id, tooltip }));
3452 id
3453 }
3454
3455 #[inline]
3460 pub fn with_content_mask<R>(
3461 &mut self,
3462 mask: Option<ContentMask<Pixels>>,
3463 f: impl FnOnce(&mut Self) -> R,
3464 ) -> R {
3465 self.invalidator.debug_assert_paint_or_prepaint();
3466 if let Some(mask) = mask {
3467 let mask = mask.intersect(&self.content_mask());
3468 self.content_mask_stack.push(mask);
3469 let result = f(self);
3470 self.content_mask_stack.pop();
3471 result
3472 } else {
3473 f(self)
3474 }
3475 }
3476
3477 pub fn with_element_offset<R>(
3480 &mut self,
3481 offset: Point<Pixels>,
3482 f: impl FnOnce(&mut Self) -> R,
3483 ) -> R {
3484 self.invalidator.debug_assert_prepaint();
3485
3486 if offset.is_zero() {
3487 return f(self);
3488 };
3489
3490 let abs_offset = self.element_offset() + offset;
3491 self.with_absolute_element_offset(abs_offset, f)
3492 }
3493
3494 pub fn with_absolute_element_offset<R>(
3498 &mut self,
3499 offset: Point<Pixels>,
3500 f: impl FnOnce(&mut Self) -> R,
3501 ) -> R {
3502 self.invalidator.debug_assert_prepaint();
3503 self.element_offset_stack.push(offset);
3504 let result = f(self);
3505 self.element_offset_stack.pop();
3506 result
3507 }
3508
3509 pub(crate) fn with_element_opacity<R>(
3510 &mut self,
3511 opacity: Option<f32>,
3512 f: impl FnOnce(&mut Self) -> R,
3513 ) -> R {
3514 self.invalidator.debug_assert_paint_or_prepaint();
3515
3516 let Some(opacity) = opacity else {
3517 return f(self);
3518 };
3519
3520 let previous_opacity = self.element_opacity;
3521 self.element_opacity = previous_opacity * opacity;
3522 let result = f(self);
3523 self.element_opacity = previous_opacity;
3524 result
3525 }
3526
3527 pub fn transact<T, U>(&mut self, f: impl FnOnce(&mut Self) -> Result<T, U>) -> Result<T, U> {
3533 self.invalidator.debug_assert_prepaint();
3534 let index = self.prepaint_index();
3535 let result = f(self);
3536 if result.is_err() {
3537 self.next_frame.hitboxes.truncate(index.hitboxes_index);
3538 self.next_frame
3539 .tooltip_requests
3540 .truncate(index.tooltips_index);
3541 self.next_frame
3542 .deferred_draws
3543 .truncate(index.deferred_draws_index);
3544 self.next_frame
3545 .dispatch_tree
3546 .truncate(index.dispatch_tree_index);
3547 self.next_frame
3548 .accessed_element_states
3549 .truncate(index.accessed_element_states_index);
3550 self.text_system.truncate_layouts(index.line_layout_index);
3551 }
3552 result
3553 }
3554
3555 pub fn request_autoscroll(&mut self, bounds: Bounds<Pixels>) {
3561 self.invalidator.debug_assert_prepaint();
3562 self.requested_autoscroll = Some(bounds);
3563 }
3564
3565 pub fn take_autoscroll(&mut self) -> Option<Bounds<Pixels>> {
3568 self.invalidator.debug_assert_prepaint();
3569 self.requested_autoscroll.take()
3570 }
3571
3572 pub fn use_asset<A: Asset>(&mut self, source: &A::Source, cx: &mut App) -> Option<A::Output> {
3578 let (task, is_first) = cx.fetch_asset::<A>(source);
3579 task.clone().now_or_never().or_else(|| {
3580 if is_first {
3581 let entity_id = self.current_view();
3582 self.spawn(cx, {
3583 let task = task.clone();
3584 async move |cx| {
3585 task.await;
3586
3587 cx.on_next_frame(move |_, cx| {
3588 cx.notify(entity_id);
3589 });
3590 }
3591 })
3592 .detach();
3593 }
3594
3595 None
3596 })
3597 }
3598
3599 pub fn get_asset<A: Asset>(&mut self, source: &A::Source, cx: &mut App) -> Option<A::Output> {
3605 let (task, _) = cx.fetch_asset::<A>(source);
3606 task.now_or_never()
3607 }
3608 pub fn element_offset(&self) -> Point<Pixels> {
3611 self.invalidator.debug_assert_prepaint();
3612 self.element_offset_stack
3613 .last()
3614 .copied()
3615 .unwrap_or_default()
3616 }
3617
3618 #[inline]
3621 pub(crate) fn element_opacity(&self) -> f32 {
3622 self.invalidator.debug_assert_paint_or_prepaint();
3623 self.element_opacity
3624 }
3625
3626 pub fn content_mask(&self) -> ContentMask<Pixels> {
3628 self.invalidator.debug_assert_paint_or_prepaint();
3629 self.content_mask_stack
3630 .last()
3631 .cloned()
3632 .unwrap_or_else(|| ContentMask {
3633 bounds: Bounds {
3634 origin: Point::default(),
3635 size: self.viewport_size,
3636 },
3637 })
3638 }
3639
3640 pub fn with_element_namespace<R>(
3643 &mut self,
3644 element_id: impl Into<ElementId>,
3645 f: impl FnOnce(&mut Self) -> R,
3646 ) -> R {
3647 self.element_id_stack.push(element_id.into());
3648 let result = f(self);
3649 self.element_id_stack.pop();
3650 result
3651 }
3652
3653 pub fn use_keyed_state<S: 'static>(
3657 &mut self,
3658 key: impl Into<ElementId>,
3659 cx: &mut App,
3660 init: impl FnOnce(&mut Self, &mut Context<S>) -> S,
3661 ) -> Entity<S> {
3662 let current_view = self.current_view();
3663 self.with_global_id(key.into(), |global_id, window| {
3664 window.with_element_state(global_id, |state: Option<Entity<S>>, window| {
3665 if let Some(state) = state {
3666 (state.clone(), state)
3667 } else {
3668 let new_state = cx.new(|cx| init(window, cx));
3669 cx.observe(&new_state, move |_, cx| {
3670 cx.notify(current_view);
3671 })
3672 .detach();
3673 (new_state.clone(), new_state)
3674 }
3675 })
3676 })
3677 }
3678
3679 #[track_caller]
3685 pub fn use_state<S: 'static>(
3686 &mut self,
3687 cx: &mut App,
3688 init: impl FnOnce(&mut Self, &mut Context<S>) -> S,
3689 ) -> Entity<S> {
3690 self.use_keyed_state(
3691 ElementId::CodeLocation(*core::panic::Location::caller()),
3692 cx,
3693 init,
3694 )
3695 }
3696
3697 pub fn with_element_state<S, R>(
3704 &mut self,
3705 global_id: &GlobalElementId,
3706 f: impl FnOnce(Option<S>, &mut Self) -> (R, S),
3707 ) -> R
3708 where
3709 S: 'static,
3710 {
3711 self.invalidator.debug_assert_paint_or_prepaint();
3712
3713 let key = (global_id.clone(), TypeId::of::<S>());
3714 self.next_frame.accessed_element_states.push(key.clone());
3715
3716 if let Some(any) = self
3717 .next_frame
3718 .element_states
3719 .remove(&key)
3720 .or_else(|| self.rendered_frame.element_states.remove(&key))
3721 {
3722 let ElementStateBox {
3723 inner,
3724 #[cfg(debug_assertions)]
3725 type_name,
3726 } = any;
3727 let mut state_box = inner
3729 .downcast::<Option<S>>()
3730 .map_err(|_| {
3731 #[cfg(debug_assertions)]
3732 {
3733 anyhow::anyhow!(
3734 "invalid element state type for id, requested {:?}, actual: {:?}",
3735 std::any::type_name::<S>(),
3736 type_name
3737 )
3738 }
3739
3740 #[cfg(not(debug_assertions))]
3741 {
3742 anyhow::anyhow!(
3743 "invalid element state type for id, requested {:?}",
3744 std::any::type_name::<S>(),
3745 )
3746 }
3747 })
3748 .unwrap();
3749
3750 let state = state_box.take().expect(
3751 "reentrant call to with_element_state for the same state type and element id",
3752 );
3753 let (result, state) = f(Some(state), self);
3754 state_box.replace(state);
3755 self.next_frame.element_states.insert(
3756 key,
3757 ElementStateBox {
3758 inner: state_box,
3759 #[cfg(debug_assertions)]
3760 type_name,
3761 },
3762 );
3763 result
3764 } else {
3765 let (result, state) = f(None, self);
3766 self.next_frame.element_states.insert(
3767 key,
3768 ElementStateBox {
3769 inner: Box::new(Some(state)),
3770 #[cfg(debug_assertions)]
3771 type_name: std::any::type_name::<S>(),
3772 },
3773 );
3774 result
3775 }
3776 }
3777
3778 pub fn with_optional_element_state<S, R>(
3785 &mut self,
3786 global_id: Option<&GlobalElementId>,
3787 f: impl FnOnce(Option<Option<S>>, &mut Self) -> (R, Option<S>),
3788 ) -> R
3789 where
3790 S: 'static,
3791 {
3792 self.invalidator.debug_assert_paint_or_prepaint();
3793
3794 if let Some(global_id) = global_id {
3795 self.with_element_state(global_id, |state, cx| {
3796 let (result, state) = f(Some(state), cx);
3797 let state =
3798 state.expect("you must return some state when you pass some element id");
3799 (result, state)
3800 })
3801 } else {
3802 let (result, state) = f(None, self);
3803 debug_assert!(
3804 state.is_none(),
3805 "you must not return an element state when passing None for the global id"
3806 );
3807 result
3808 }
3809 }
3810
3811 pub fn use_transition<T: Lerp + Clone + PartialEq + 'static>(
3816 &mut self,
3817 cx: &mut App,
3818 duration: Duration,
3819 init: impl Fn(&mut Window, &mut Context<TransitionState<T>>) -> T,
3820 ) -> Transition<T> {
3821 let state = self.use_state(cx, |window, cx| TransitionState::new(init(window, cx)));
3822
3823 Transition::new(state, duration)
3824 }
3825
3826 pub fn use_keyed_transition<T: Lerp + Clone + PartialEq + 'static>(
3835 &mut self,
3836 key: impl Into<ElementId>,
3837 cx: &mut App,
3838 duration: Duration,
3839 init: impl Fn(&mut Window, &mut Context<TransitionState<T>>) -> T,
3840 ) -> Transition<T> {
3841 let state =
3842 self.use_keyed_state(key, cx, |window, cx| TransitionState::new(init(window, cx)));
3843
3844 Transition::new(state, duration)
3845 }
3846
3847 #[inline]
3849 pub fn with_tab_group<R>(&mut self, index: Option<isize>, f: impl FnOnce(&mut Self) -> R) -> R {
3850 if let Some(index) = index {
3851 self.next_frame.tab_stops.begin_group(index);
3852 let result = f(self);
3853 self.next_frame.tab_stops.end_group();
3854 result
3855 } else {
3856 f(self)
3857 }
3858 }
3859
3860 pub fn defer_draw(
3869 &mut self,
3870 element: AnyElement,
3871 absolute_offset: Point<Pixels>,
3872 priority: usize,
3873 content_mask: Option<ContentMask<Pixels>>,
3874 ) {
3875 self.invalidator.debug_assert_prepaint();
3876 let parent_node = self.next_frame.dispatch_tree.active_node_id().unwrap();
3877 self.next_frame.deferred_draws.push(DeferredDraw {
3878 current_view: self.current_view(),
3879 parent_node,
3880 element_id_stack: self.element_id_stack.clone(),
3881 text_style_stack: self.text_style_stack.clone(),
3882 content_mask,
3883 rem_size: self.rem_size(),
3884 priority,
3885 element: Some(element),
3886 absolute_offset,
3887 prepaint_range: PrepaintStateIndex::default()..PrepaintStateIndex::default(),
3888 paint_range: PaintIndex::default()..PaintIndex::default(),
3889 });
3890 }
3891
3892 pub fn paint_layer<R>(&mut self, bounds: Bounds<Pixels>, f: impl FnOnce(&mut Self) -> R) -> R {
3898 self.invalidator.debug_assert_paint();
3899
3900 let content_mask = self.content_mask();
3901 let clipped_bounds = bounds.intersect(&content_mask.bounds);
3902 if !clipped_bounds.is_empty() {
3903 self.next_frame
3904 .scene
3905 .push_layer(self.cover_bounds(clipped_bounds));
3906 }
3907
3908 let result = f(self);
3909
3910 if !clipped_bounds.is_empty() {
3911 self.next_frame.scene.pop_layer();
3912 }
3913
3914 result
3915 }
3916
3917 pub fn paint_drop_shadows(
3923 &mut self,
3924 bounds: Bounds<Pixels>,
3925 corner_radii: Corners<Pixels>,
3926 shadows: &[BoxShadow],
3927 ) {
3928 self.invalidator.debug_assert_paint();
3929
3930 let scale_factor = self.scale_factor();
3931 let content_mask = self.snapped_content_mask();
3932 let opacity = self.element_opacity();
3933 let element_bounds = self.cover_bounds(bounds);
3934 let element_corner_radii = corner_radii.scale(scale_factor);
3935 for shadow in shadows {
3936 if shadow.inset {
3937 continue;
3938 }
3939 let shadow_bounds = (bounds + shadow.offset).dilate(shadow.spread_radius);
3940 self.next_frame.scene.insert_primitive(Shadow {
3941 order: 0,
3942 blur_radius: shadow.blur_radius.scale(scale_factor),
3943 bounds: self.cover_bounds(shadow_bounds),
3944 content_mask,
3945 corner_radii: corner_radii.scale(scale_factor),
3946 color: shadow.color.opacity(opacity).into(),
3947 element_bounds,
3948 element_corner_radii,
3949 inset: 0,
3950 pad: 0,
3951 });
3952 }
3953 }
3954
3955 pub fn paint_inset_shadows(
3959 &mut self,
3960 bounds: Bounds<Pixels>,
3961 corner_radii: Corners<Pixels>,
3962 shadows: &[BoxShadow],
3963 ) {
3964 self.invalidator.debug_assert_paint();
3965
3966 let scale_factor = self.scale_factor();
3967 let content_mask = self.snapped_content_mask();
3968 let opacity = self.element_opacity();
3969 let element_bounds = self.cover_bounds(bounds);
3970 let element_corner_radii = corner_radii.scale(scale_factor);
3971 for shadow in shadows {
3972 if !shadow.inset {
3973 continue;
3974 }
3975 let hole = (bounds + shadow.offset).dilate(-shadow.spread_radius);
3976 let zero = Pixels::ZERO;
3979 let hole_corner_radii = Corners {
3980 top_left: (corner_radii.top_left - shadow.spread_radius).max(zero),
3981 top_right: (corner_radii.top_right - shadow.spread_radius).max(zero),
3982 bottom_right: (corner_radii.bottom_right - shadow.spread_radius).max(zero),
3983 bottom_left: (corner_radii.bottom_left - shadow.spread_radius).max(zero),
3984 };
3985 self.next_frame.scene.insert_primitive(Shadow {
3986 order: 0,
3987 blur_radius: shadow.blur_radius.scale(scale_factor),
3988 bounds: self.cover_bounds(hole),
3989 content_mask,
3990 corner_radii: hole_corner_radii.scale(scale_factor),
3991 color: shadow.color.opacity(opacity).into(),
3992 element_bounds,
3993 element_corner_radii,
3994 inset: 1,
3995 pad: 0,
3996 });
3997 }
3998 }
3999
4000 pub fn paint_backdrop_filter(
4010 &mut self,
4011 bounds: Bounds<Pixels>,
4012 corner_radii: Corners<Pixels>,
4013 filters: &[Filter],
4014 ) {
4015 self.invalidator.debug_assert_paint();
4016
4017 let scale_factor = self.scale_factor();
4018 let filters: SmallVec<[ScaledFilter; 4]> = filters
4019 .iter()
4020 .filter(|filter| !filter.is_identity())
4021 .map(|filter| filter.scale(scale_factor))
4022 .collect();
4023 if filters.is_empty() {
4024 return;
4025 }
4026
4027 self.next_frame.scene.insert_primitive(BackdropFilter {
4028 order: 0,
4029 bounds: self.snap_bounds(bounds),
4030 content_mask: self.snapped_content_mask(),
4031 corner_radii: corner_radii.scale(scale_factor),
4032 filters,
4033 opacity: self.element_opacity(),
4034 });
4035 }
4036
4037 pub fn with_filter_layer<R>(
4047 &mut self,
4048 bounds: Bounds<Pixels>,
4049 corner_radii: Corners<Pixels>,
4050 filters: &[Filter],
4051 f: impl FnOnce(&mut Self) -> R,
4052 ) -> R {
4053 self.invalidator.debug_assert_paint();
4054
4055 let scale_factor = self.scale_factor();
4056 let filters: SmallVec<[ScaledFilter; 4]> = filters
4057 .iter()
4058 .filter(|filter| !filter.is_identity())
4059 .map(|filter| filter.scale(scale_factor))
4060 .collect();
4061 if filters.is_empty() {
4062 return f(self);
4063 }
4064
4065 let boundary = FilterBoundary {
4073 order: 0,
4074 bounds: self.snap_bounds(bounds),
4075 content_mask: self.snapped_content_mask(),
4076 corner_radii: corner_radii.scale(scale_factor),
4077 filters,
4078 opacity: 1.0,
4079 is_start: true,
4080 };
4081
4082 self.next_frame.scene.insert_primitive(boundary.clone());
4083 let result = f(self);
4084 self.next_frame.scene.insert_primitive(FilterBoundary {
4085 is_start: false,
4086 ..boundary
4087 });
4088
4089 result
4090 }
4091
4092 pub fn paint_quad(&mut self, quad: PaintQuad) {
4102 self.invalidator.debug_assert_paint();
4103
4104 let opacity = self.element_opacity();
4105 let snapped_bounds = self.snap_bounds(quad.bounds);
4106 let snapped_border_widths = self.snap_border_widths(quad.border_widths);
4107 let quad = Quad {
4108 order: 0,
4109 bounds: snapped_bounds,
4110 content_mask: self.snapped_content_mask(),
4111 background: quad.background.opacity(opacity),
4112 border_color: quad.border_color.opacity(opacity).into(),
4113 corner_radii: quad.corner_radii.scale(self.scale_factor()),
4114 border_widths: snapped_border_widths,
4115 border_style: quad.border_style,
4116 };
4117
4118 if !quad.background.is_transparent() {
4119 self.next_frame.scene.insert_primitive(quad);
4120 return;
4121 }
4122
4123 let radii = &quad.corner_radii;
4129 let widths = &quad.border_widths;
4130
4131 let antialias_slack = point(ScaledPixels(1.0), ScaledPixels(1.0));
4132 let top_left_inset = point(
4133 widths.left,
4134 widths.top.max(radii.top_left).max(radii.top_right),
4135 ) + antialias_slack;
4136 let bottom_right_inset = point(
4137 widths.right,
4138 widths.bottom.max(radii.bottom_left).max(radii.bottom_right),
4139 ) + antialias_slack;
4140
4141 let outer_bounds = quad.bounds;
4142 let inner_bounds = Bounds::from_corners(
4143 outer_bounds.origin + top_left_inset,
4144 outer_bounds.bottom_right() - bottom_right_inset,
4145 );
4146
4147 if inner_bounds.is_empty() {
4148 self.next_frame.scene.insert_primitive(quad);
4149 return;
4150 }
4151
4152 let strips = [
4153 Bounds::from_corners(
4155 outer_bounds.origin,
4156 point(outer_bounds.right(), inner_bounds.top()),
4157 ),
4158 Bounds::from_corners(
4160 point(outer_bounds.left(), inner_bounds.bottom()),
4161 outer_bounds.bottom_right(),
4162 ),
4163 Bounds::from_corners(
4165 point(outer_bounds.left(), inner_bounds.top()),
4166 inner_bounds.bottom_left(),
4167 ),
4168 Bounds::from_corners(
4170 inner_bounds.top_right(),
4171 point(outer_bounds.right(), inner_bounds.bottom()),
4172 ),
4173 ];
4174
4175 for strip in strips {
4176 let content_mask_bounds = quad.content_mask.bounds.intersect(&strip);
4177 if !content_mask_bounds.is_empty() {
4178 self.next_frame.scene.insert_primitive(Quad {
4179 content_mask: ContentMask {
4180 bounds: content_mask_bounds,
4181 },
4182 ..quad
4183 });
4184 }
4185 }
4186 }
4187
4188 pub fn paint_path(&mut self, mut path: Path<Pixels>, color: impl Into<Background>) {
4192 self.invalidator.debug_assert_paint();
4193
4194 let scale_factor = self.scale_factor();
4195 let content_mask = self.content_mask();
4196 let opacity = self.element_opacity();
4197 path.content_mask = content_mask;
4198 let color: Background = color.into();
4199 path.color = color.opacity(opacity);
4200 self.next_frame
4201 .scene
4202 .insert_primitive(path.scale(scale_factor));
4203 }
4204
4205 pub fn paint_underline(
4209 &mut self,
4210 origin: Point<Pixels>,
4211 width: Pixels,
4212 style: &UnderlineStyle,
4213 ) {
4214 self.invalidator.debug_assert_paint();
4215
4216 let scale_factor = self.scale_factor();
4217 let thickness = self.snap_stroke(style.thickness);
4218 let height = if style.wavy {
4219 ScaledPixels(thickness.0 * 3.)
4220 } else {
4221 thickness
4222 };
4223 let bounds = Bounds {
4224 origin: origin.map(|c| ScaledPixels(round_to_device_pixel(c.0, scale_factor))),
4225 size: size(self.snap_stroke(width), height),
4226 };
4227 let element_opacity = self.element_opacity();
4228
4229 self.next_frame.scene.insert_primitive(Underline {
4230 order: 0,
4231 pad: 0,
4232 bounds,
4233 content_mask: self.snapped_content_mask(),
4234 color: style
4235 .color
4236 .unwrap_or_default()
4237 .opacity(element_opacity)
4238 .into(),
4239 thickness,
4240 wavy: style.wavy.into(),
4241 });
4242 }
4243
4244 pub fn paint_strikethrough(
4248 &mut self,
4249 origin: Point<Pixels>,
4250 width: Pixels,
4251 style: &StrikethroughStyle,
4252 ) {
4253 self.invalidator.debug_assert_paint();
4254
4255 let scale_factor = self.scale_factor();
4256 let height = style.thickness;
4257 let bounds = Bounds {
4258 origin: origin.map(|c| ScaledPixels(round_to_device_pixel(c.0, scale_factor))),
4259 size: size(self.snap_stroke(width), self.snap_stroke(height)),
4260 };
4261 let opacity = self.element_opacity();
4262
4263 self.next_frame.scene.insert_primitive(Underline {
4264 order: 0,
4265 pad: 0,
4266 bounds,
4267 content_mask: self.snapped_content_mask(),
4268 thickness: self.snap_stroke(style.thickness),
4269 color: style.color.unwrap_or_default().opacity(opacity).into(),
4270 wavy: false.into(),
4271 });
4272 }
4273
4274 pub fn paint_glyph(
4283 &mut self,
4284 origin: Point<Pixels>,
4285 font_id: FontId,
4286 glyph_id: GlyphId,
4287 font_size: Pixels,
4288 color: Hsla,
4289 ) -> Result<()> {
4290 self.invalidator.debug_assert_paint();
4291
4292 let element_opacity = self.element_opacity();
4293 let scale_factor = self.scale_factor();
4294 let glyph_origin = origin.scale(scale_factor);
4295
4296 let quantized_origin = Point::new(
4297 round_half_toward_zero(glyph_origin.x.0 * SUBPIXEL_VARIANTS_X as f32)
4298 / SUBPIXEL_VARIANTS_X as f32,
4299 round_half_toward_zero(glyph_origin.y.0 * SUBPIXEL_VARIANTS_Y as f32)
4300 / SUBPIXEL_VARIANTS_Y as f32,
4301 );
4302 let subpixel_variant = Point::new(
4303 (quantized_origin.x.fract() * SUBPIXEL_VARIANTS_X as f32) as u8,
4304 (quantized_origin.y.fract() * SUBPIXEL_VARIANTS_Y as f32) as u8,
4305 );
4306 let integer_origin = quantized_origin.map(|c| ScaledPixels(c.trunc()));
4307 let subpixel_rendering = self.should_use_subpixel_rendering(font_id, font_size);
4308 let dilation = self.text_system().glyph_dilation_for_color(color);
4309 let params = RenderGlyphParams {
4310 font_id,
4311 glyph_id,
4312 font_size,
4313 subpixel_variant,
4314 scale_factor,
4315 is_emoji: false,
4316 subpixel_rendering,
4317 dilation,
4318 };
4319
4320 let raster_bounds = self.text_system().raster_bounds(¶ms)?;
4321 if !raster_bounds.is_zero() {
4322 let tile = self
4323 .sprite_atlas
4324 .get_or_insert_with(¶ms.clone().into(), &mut || {
4325 let (size, bytes) = self.text_system().rasterize_glyph(¶ms)?;
4326 Ok(Some((size, Cow::Owned(bytes))))
4327 })?
4328 .expect("Callback above only errors or returns Some");
4329 let bounds = Bounds {
4330 origin: integer_origin + raster_bounds.origin.map(Into::into),
4331 size: tile.bounds.size.map(Into::into),
4332 };
4333 let content_mask = self.snapped_content_mask();
4334
4335 if subpixel_rendering {
4336 self.next_frame.scene.insert_primitive(SubpixelSprite {
4337 order: 0,
4338 pad: 0,
4339 bounds,
4340 content_mask,
4341 color: color.opacity(element_opacity).into(),
4342 tile,
4343 transformation: TransformationMatrix::unit(),
4344 });
4345 } else {
4346 self.next_frame.scene.insert_primitive(MonochromeSprite {
4347 order: 0,
4348 pad: 0,
4349 bounds,
4350 content_mask,
4351 color: color.opacity(element_opacity).into(),
4352 tile,
4353 transformation: TransformationMatrix::unit(),
4354 });
4355 }
4356 }
4357 Ok(())
4358 }
4359
4360 fn should_use_subpixel_rendering(&self, font_id: FontId, font_size: Pixels) -> bool {
4361 if self.platform_window.background_appearance() != WindowBackgroundAppearance::Opaque {
4362 return false;
4363 }
4364
4365 if !self.platform_window.is_subpixel_rendering_supported() {
4366 return false;
4367 }
4368
4369 let mode = match self.text_rendering_mode.get() {
4370 TextRenderingMode::PlatformDefault => self
4371 .text_system()
4372 .recommended_rendering_mode(font_id, font_size),
4373 mode => mode,
4374 };
4375
4376 mode == TextRenderingMode::Subpixel
4377 }
4378
4379 pub fn paint_emoji(
4388 &mut self,
4389 origin: Point<Pixels>,
4390 font_id: FontId,
4391 glyph_id: GlyphId,
4392 font_size: Pixels,
4393 ) -> Result<()> {
4394 self.invalidator.debug_assert_paint();
4395
4396 let scale_factor = self.scale_factor();
4397 let glyph_origin = origin.scale(scale_factor);
4398 let integer_origin = glyph_origin.map(|c| ScaledPixels(round_half_toward_zero(c.0)));
4399 let params = RenderGlyphParams {
4400 font_id,
4401 glyph_id,
4402 font_size,
4403 subpixel_variant: Default::default(),
4404 scale_factor,
4405 is_emoji: true,
4406 subpixel_rendering: false,
4407 dilation: 0,
4408 };
4409
4410 let raster_bounds = self.text_system().raster_bounds(¶ms)?;
4411 if !raster_bounds.is_zero() {
4412 let tile = self
4413 .sprite_atlas
4414 .get_or_insert_with(¶ms.clone().into(), &mut || {
4415 let (size, bytes) = self.text_system().rasterize_glyph(¶ms)?;
4416 Ok(Some((size, Cow::Owned(bytes))))
4417 })?
4418 .expect("Callback above only errors or returns Some");
4419
4420 let bounds = Bounds {
4421 origin: integer_origin + raster_bounds.origin.map(Into::into),
4422 size: tile.bounds.size.map(Into::into),
4423 };
4424 let content_mask = self.snapped_content_mask();
4425 let opacity = self.element_opacity();
4426
4427 self.next_frame.scene.insert_primitive(PolychromeSprite {
4428 order: 0,
4429 pad: 0,
4430 grayscale: false.into(),
4431 bounds,
4432 corner_radii: Default::default(),
4433 content_mask,
4434 tile,
4435 opacity,
4436 });
4437 }
4438 Ok(())
4439 }
4440
4441 pub fn paint_svg(
4445 &mut self,
4446 bounds: Bounds<Pixels>,
4447 path: SharedString,
4448 mut data: Option<&[u8]>,
4449 transformation: TransformationMatrix,
4450 color: Hsla,
4451 cx: &App,
4452 ) -> Result<()> {
4453 self.invalidator.debug_assert_paint();
4454
4455 let element_opacity = self.element_opacity();
4456 let bounds = self.snap_bounds(bounds);
4457
4458 let params = RenderSvgParams {
4459 path,
4460 size: bounds.size.map(|pixels| {
4461 DevicePixels::from((pixels.0 * SMOOTH_SVG_SCALE_FACTOR).ceil() as i32)
4462 }),
4463 };
4464
4465 let Some(tile) =
4466 self.sprite_atlas
4467 .get_or_insert_with(¶ms.clone().into(), &mut || {
4468 let Some((size, bytes)) = cx.svg_renderer.render_alpha_mask(¶ms, data)?
4469 else {
4470 return Ok(None);
4471 };
4472 Ok(Some((size, Cow::Owned(bytes))))
4473 })?
4474 else {
4475 return Ok(());
4476 };
4477 let content_mask = self.snapped_content_mask();
4478 let svg_bounds = Bounds {
4479 origin: bounds.center()
4480 - Point::new(
4481 ScaledPixels(tile.bounds.size.width.0 as f32 / SMOOTH_SVG_SCALE_FACTOR / 2.),
4482 ScaledPixels(tile.bounds.size.height.0 as f32 / SMOOTH_SVG_SCALE_FACTOR / 2.),
4483 ),
4484 size: tile
4485 .bounds
4486 .size
4487 .map(|value| ScaledPixels(value.0 as f32 / SMOOTH_SVG_SCALE_FACTOR)),
4488 };
4489 let final_bounds = svg_bounds
4490 .map_origin(|value| ScaledPixels(round_half_toward_zero(value.0)))
4491 .map_size(|size| size.ceil());
4492
4493 self.next_frame.scene.insert_primitive(MonochromeSprite {
4494 order: 0,
4495 pad: 0,
4496 bounds: final_bounds,
4497 content_mask,
4498 color: color.opacity(element_opacity).into(),
4499 tile,
4500 transformation,
4501 });
4502
4503 Ok(())
4504 }
4505
4506 pub fn paint_image(
4515 &mut self,
4516 bounds: Bounds<Pixels>,
4517 image_bounds: Bounds<Pixels>,
4518 corner_radii: Corners<Pixels>,
4519 data: Arc<RenderImage>,
4520 frame_index: usize,
4521 grayscale: bool,
4522 ) -> Result<()> {
4523 self.invalidator.debug_assert_paint();
4524
4525 let visible_bounds = bounds.intersect(&image_bounds);
4526 if visible_bounds.size.width <= Pixels::ZERO || visible_bounds.size.height <= Pixels::ZERO {
4527 return Ok(());
4528 }
4529 if image_bounds.size.width <= Pixels::ZERO || image_bounds.size.height <= Pixels::ZERO {
4530 return Ok(());
4531 }
4532
4533 let params = RenderImageParams {
4534 image_id: data.id,
4535 frame_index,
4536 };
4537
4538 let tile = self
4539 .sprite_atlas
4540 .get_or_insert_with(¶ms.into(), &mut || {
4541 Ok(Some((
4542 data.size(frame_index),
4543 Cow::Borrowed(
4544 data.as_bytes(frame_index)
4545 .expect("It's the caller's job to pass a valid frame index"),
4546 ),
4547 )))
4548 })?
4549 .expect("Callback above only returns Some");
4550
4551 let visible_bounds_snapped = self.snap_bounds(visible_bounds);
4552
4553 let sub_tile = if visible_bounds == image_bounds {
4554 tile
4555 } else {
4556 let x_offset_ratio =
4557 (visible_bounds.origin.x - image_bounds.origin.x) / image_bounds.size.width;
4558 let y_offset_ratio =
4559 (visible_bounds.origin.y - image_bounds.origin.y) / image_bounds.size.height;
4560 let width_ratio = visible_bounds.size.width / image_bounds.size.width;
4561 let height_ratio = visible_bounds.size.height / image_bounds.size.height;
4562
4563 let tile_origin_x = tile.bounds.origin.x.0;
4564 let tile_origin_y = tile.bounds.origin.y.0;
4565 let tile_width = tile.bounds.size.width.0;
4566 let tile_height = tile.bounds.size.height.0;
4567
4568 let sub_origin_x = tile_origin_x + (x_offset_ratio * tile_width as f32).round() as i32;
4569 let sub_origin_y = tile_origin_y + (y_offset_ratio * tile_height as f32).round() as i32;
4570 let sub_width = (width_ratio * tile_width as f32).round() as i32;
4571 let sub_height = (height_ratio * tile_height as f32).round() as i32;
4572
4573 let max_x = tile_origin_x + tile_width;
4574 let max_y = tile_origin_y + tile_height;
4575
4576 let clamped_origin_x = sub_origin_x.clamp(tile_origin_x, max_x);
4577 let clamped_origin_y = sub_origin_y.clamp(tile_origin_y, max_y);
4578 let clamped_width = sub_width.min(max_x - clamped_origin_x).max(0);
4579 let clamped_height = sub_height.min(max_y - clamped_origin_y).max(0);
4580
4581 AtlasTile {
4582 bounds: Bounds {
4583 origin: point(
4584 DevicePixels(clamped_origin_x),
4585 DevicePixels(clamped_origin_y),
4586 ),
4587 size: size(DevicePixels(clamped_width), DevicePixels(clamped_height)),
4588 },
4589 ..tile
4590 }
4591 };
4592
4593 let content_mask = self.snapped_content_mask();
4594 let corner_radii = corner_radii
4595 .clamp_radii_for_quad_size(visible_bounds.size)
4596 .scale(self.scale_factor());
4597 let opacity = self.element_opacity();
4598
4599 self.next_frame.scene.insert_primitive(PolychromeSprite {
4600 order: 0,
4601 pad: 0,
4602 grayscale: grayscale.into(),
4603 bounds: visible_bounds_snapped,
4604 content_mask,
4605 corner_radii,
4606 tile: sub_tile,
4607 opacity,
4608 });
4609 Ok(())
4610 }
4611
4612 #[cfg(target_os = "macos")]
4616 pub fn paint_surface(&mut self, bounds: Bounds<Pixels>, image_buffer: CVPixelBuffer) {
4617 use crate::PaintSurface;
4618
4619 self.invalidator.debug_assert_paint();
4620
4621 let bounds = self.snap_bounds(bounds);
4622 let content_mask = self.snapped_content_mask();
4623 self.next_frame.scene.insert_primitive(PaintSurface {
4624 order: 0,
4625 bounds,
4626 content_mask,
4627 image_buffer,
4628 });
4629 }
4630
4631 #[cfg(any(target_os = "linux", target_os = "freebsd"))]
4635 pub fn paint_surface(
4636 &mut self,
4637 bounds: Bounds<Pixels>,
4638 texture: std::sync::Arc<dyn std::any::Any + Send + Sync>,
4639 texture_size: Size<DevicePixels>,
4640 ) {
4641 use crate::PaintSurface;
4642
4643 self.invalidator.debug_assert_paint();
4644
4645 let scale_factor = self.scale_factor();
4646 let bounds = bounds.scale(scale_factor);
4647 let content_mask = self.content_mask().scale(scale_factor);
4648 self.next_frame.scene.insert_primitive(PaintSurface {
4649 order: 0,
4650 bounds,
4651 content_mask,
4652 texture,
4653 texture_size,
4654 });
4655 }
4656
4657 pub fn drop_image(&mut self, data: Arc<RenderImage>) -> Result<()> {
4659 for frame_index in 0..data.frame_count() {
4660 let params = RenderImageParams {
4661 image_id: data.id,
4662 frame_index,
4663 };
4664
4665 self.sprite_atlas.remove(¶ms.clone().into());
4666 }
4667
4668 Ok(())
4669 }
4670
4671 #[cfg(any(test, feature = "test-support"))]
4673 pub fn has_image_atlas_entry(&self, data: &RenderImage) -> bool {
4674 data.frame_count() > 0
4675 && (0..data.frame_count()).all(|frame_index| {
4676 self.sprite_atlas.contains(
4677 &RenderImageParams {
4678 image_id: data.id,
4679 frame_index,
4680 }
4681 .into(),
4682 )
4683 })
4684 }
4685
4686 #[must_use]
4692 pub fn request_layout(
4693 &mut self,
4694 style: Style,
4695 children: impl IntoIterator<Item = LayoutId>,
4696 cx: &mut App,
4697 ) -> LayoutId {
4698 self.invalidator.debug_assert_prepaint();
4699
4700 cx.layout_id_buffer.clear();
4701 cx.layout_id_buffer.extend(children);
4702 let rem_size = self.rem_size();
4703 let scale_factor = self.scale_factor();
4704
4705 self.layout_engine.as_mut().unwrap().request_layout(
4706 style,
4707 rem_size,
4708 scale_factor,
4709 &cx.layout_id_buffer,
4710 )
4711 }
4712
4713 pub fn request_measured_layout<F>(&mut self, style: Style, measure: F) -> LayoutId
4722 where
4723 F: Fn(Size<Option<Pixels>>, Size<AvailableSpace>, &mut Window, &mut App) -> Size<Pixels>
4724 + 'static,
4725 {
4726 self.invalidator.debug_assert_prepaint();
4727
4728 let rem_size = self.rem_size();
4729 let scale_factor = self.scale_factor();
4730 self.layout_engine
4731 .as_mut()
4732 .unwrap()
4733 .request_measured_layout(style, rem_size, scale_factor, measure)
4734 }
4735
4736 pub fn compute_layout(
4742 &mut self,
4743 layout_id: LayoutId,
4744 available_space: Size<AvailableSpace>,
4745 cx: &mut App,
4746 ) {
4747 self.invalidator.debug_assert_prepaint();
4748
4749 let mut layout_engine = self.layout_engine.take().unwrap();
4750 layout_engine.compute_layout(layout_id, available_space, self, cx);
4751 self.layout_engine = Some(layout_engine);
4752 }
4753
4754 pub fn layout_bounds(&mut self, layout_id: LayoutId) -> Bounds<Pixels> {
4759 self.invalidator.debug_assert_prepaint();
4760
4761 let scale_factor = self.scale_factor();
4762 let mut bounds = self
4763 .layout_engine
4764 .as_mut()
4765 .unwrap()
4766 .layout_bounds(layout_id, scale_factor)
4767 .map(Into::into);
4768 let snapped_offset = self.pixel_snap_point(self.element_offset());
4769 bounds.origin += snapped_offset;
4770 bounds
4771 }
4772
4773 pub fn insert_hitbox(&mut self, bounds: Bounds<Pixels>, behavior: HitboxBehavior) -> Hitbox {
4779 self.invalidator.debug_assert_prepaint();
4780
4781 let content_mask = self.content_mask();
4782 let mut id = self.next_hitbox_id;
4783 self.next_hitbox_id = self.next_hitbox_id.next();
4784 let hitbox = Hitbox {
4785 id,
4786 bounds,
4787 content_mask,
4788 behavior,
4789 };
4790 self.next_frame.hitboxes.push(hitbox.clone());
4791 hitbox
4792 }
4793
4794 pub fn insert_window_control_hitbox(&mut self, area: WindowControlArea, hitbox: Hitbox) {
4798 self.invalidator.debug_assert_paint();
4799 self.next_frame.window_control_hitboxes.push((area, hitbox));
4800 }
4801
4802 pub fn set_key_context(&mut self, context: KeyContext) {
4807 self.invalidator.debug_assert_paint();
4808 self.next_frame.dispatch_tree.set_key_context(context);
4809 }
4810
4811 pub fn set_focus_handle(&mut self, focus_handle: &FocusHandle, _: &App) {
4816 self.invalidator.debug_assert_prepaint();
4817 if focus_handle.is_focused(self) {
4818 self.next_frame.focus = Some(focus_handle.id);
4819 }
4820 self.next_frame.dispatch_tree.set_focus_id(focus_handle.id);
4821 }
4822
4823 pub fn set_view_id(&mut self, view_id: EntityId) {
4829 self.invalidator.debug_assert_prepaint();
4830 self.next_frame.dispatch_tree.set_view_id(view_id);
4831 }
4832
4833 pub fn current_view(&self) -> EntityId {
4835 self.invalidator.debug_assert_paint_or_prepaint();
4836 self.rendered_entity_stack.last().copied().unwrap()
4837 }
4838
4839 #[inline]
4840 pub(crate) fn with_rendered_view<R>(
4841 &mut self,
4842 id: EntityId,
4843 f: impl FnOnce(&mut Self) -> R,
4844 ) -> R {
4845 self.rendered_entity_stack.push(id);
4846 let result = f(self);
4847 self.rendered_entity_stack.pop();
4848 result
4849 }
4850
4851 pub fn with_image_cache<F, R>(&mut self, image_cache: Option<AnyImageCache>, f: F) -> R
4853 where
4854 F: FnOnce(&mut Self) -> R,
4855 {
4856 if let Some(image_cache) = image_cache {
4857 self.image_cache_stack.push(image_cache);
4858 let result = f(self);
4859 self.image_cache_stack.pop();
4860 result
4861 } else {
4862 f(self)
4863 }
4864 }
4865
4866 pub fn handle_input(
4875 &mut self,
4876 focus_handle: &FocusHandle,
4877 input_handler: impl InputHandler,
4878 cx: &App,
4879 ) {
4880 self.invalidator.debug_assert_paint();
4881
4882 if focus_handle.is_focused(self) {
4883 let cx = self.to_async(cx);
4884 self.next_frame
4885 .input_handlers
4886 .push(Some(PlatformInputHandler::new(cx, Box::new(input_handler))));
4887 }
4888 }
4889
4890 pub fn on_mouse_event<Event: MouseEvent>(
4896 &mut self,
4897 mut listener: impl FnMut(&Event, DispatchPhase, &mut Window, &mut App) + 'static,
4898 ) {
4899 self.invalidator.debug_assert_paint();
4900
4901 self.next_frame.mouse_listeners.push(Some(Box::new(
4902 move |event: &dyn Any, phase: DispatchPhase, window: &mut Window, cx: &mut App| {
4903 if let Some(event) = event.downcast_ref() {
4904 listener(event, phase, window, cx)
4905 }
4906 },
4907 )));
4908 }
4909
4910 pub fn on_key_event<Event: KeyEvent>(
4919 &mut self,
4920 listener: impl Fn(&Event, DispatchPhase, &mut Window, &mut App) + 'static,
4921 ) {
4922 self.invalidator.debug_assert_paint();
4923
4924 self.next_frame.dispatch_tree.on_key_event(Rc::new(
4925 move |event: &dyn Any, phase, window: &mut Window, cx: &mut App| {
4926 if let Some(event) = event.downcast_ref::<Event>() {
4927 listener(event, phase, window, cx)
4928 }
4929 },
4930 ));
4931 }
4932
4933 pub fn on_modifiers_changed(
4940 &mut self,
4941 listener: impl Fn(&ModifiersChangedEvent, &mut Window, &mut App) + 'static,
4942 ) {
4943 self.invalidator.debug_assert_paint();
4944
4945 self.next_frame.dispatch_tree.on_modifiers_changed(Rc::new(
4946 move |event: &ModifiersChangedEvent, window: &mut Window, cx: &mut App| {
4947 listener(event, window, cx)
4948 },
4949 ));
4950 }
4951
4952 pub fn on_focus_in(
4956 &mut self,
4957 handle: &FocusHandle,
4958 cx: &mut App,
4959 mut listener: impl FnMut(&mut Window, &mut App) + 'static,
4960 ) -> Subscription {
4961 let focus_id = handle.id;
4962 let (subscription, activate) =
4963 self.new_focus_listener(Box::new(move |event, window, cx| {
4964 if event.is_focus_in(focus_id) {
4965 listener(window, cx);
4966 }
4967 true
4968 }));
4969 cx.defer(move |_| activate());
4970 subscription
4971 }
4972
4973 pub fn on_focus_out(
4976 &mut self,
4977 handle: &FocusHandle,
4978 cx: &mut App,
4979 mut listener: impl FnMut(FocusOutEvent, &mut Window, &mut App) + 'static,
4980 ) -> Subscription {
4981 let focus_id = handle.id;
4982 let (subscription, activate) =
4983 self.new_focus_listener(Box::new(move |event, window, cx| {
4984 if let Some(blurred_id) = event.previous_focus_path.last().copied()
4985 && event.is_focus_out(focus_id)
4986 {
4987 let event = FocusOutEvent {
4988 blurred: WeakFocusHandle {
4989 id: blurred_id,
4990 handles: Arc::downgrade(&cx.focus_handles),
4991 },
4992 };
4993 listener(event, window, cx)
4994 }
4995 true
4996 }));
4997 cx.defer(move |_| activate());
4998 subscription
4999 }
5000
5001 fn reset_cursor_style(&self, cx: &mut App) {
5002 if self.is_window_hovered() {
5004 let style = self
5005 .rendered_frame
5006 .cursor_style(self)
5007 .unwrap_or(CursorStyle::Arrow);
5008 cx.platform.set_cursor_style(style);
5009 }
5010 }
5011
5012 pub fn dispatch_keystroke(&mut self, keystroke: Keystroke, cx: &mut App) -> bool {
5015 let keystroke = keystroke.with_simulated_ime();
5016 let result = self.dispatch_event(
5017 PlatformInput::KeyDown(KeyDownEvent {
5018 keystroke: keystroke.clone(),
5019 is_held: false,
5020 prefer_character_input: false,
5021 }),
5022 cx,
5023 );
5024 if !result.propagate {
5025 return true;
5026 }
5027
5028 if let Some(input) = keystroke.key_char
5029 && let Some(mut input_handler) = self.platform_window.take_input_handler()
5030 {
5031 input_handler.dispatch_input(&input, self, cx);
5032 self.platform_window.set_input_handler(input_handler);
5033 return true;
5034 }
5035
5036 false
5037 }
5038
5039 pub fn keystroke_text_for(&self, action: &dyn Action) -> String {
5042 self.highest_precedence_binding_for_action(action)
5043 .map(|binding| {
5044 binding
5045 .keystrokes()
5046 .iter()
5047 .map(ToString::to_string)
5048 .collect::<Vec<_>>()
5049 .join(" ")
5050 })
5051 .unwrap_or_else(|| action.name().to_string())
5052 }
5053
5054 #[profiling::function]
5056 pub fn dispatch_event(&mut self, event: PlatformInput, cx: &mut App) -> DispatchEventResult {
5057 #[cfg(feature = "input-latency-histogram")]
5058 let dispatch_time = Instant::now();
5059 let update_count_before = self.invalidator.update_count();
5060 let old_modality = self.last_input_modality;
5064 self.last_input_modality = match &event {
5065 PlatformInput::KeyDown(_) => InputModality::Keyboard,
5066 PlatformInput::MouseMove(_) | PlatformInput::MouseDown(_) => InputModality::Mouse,
5067 PlatformInput::Touch(_) => InputModality::Touch,
5068 _ => self.last_input_modality,
5069 };
5070 if self.last_input_modality != old_modality {
5071 self.refresh();
5072 }
5073
5074 cx.propagate_event = true;
5076 self.default_prevented = false;
5078
5079 let event = match event {
5080 PlatformInput::MouseMove(mouse_move) => {
5083 self.mouse_position = mouse_move.position;
5084 self.modifiers = mouse_move.modifiers;
5085 PlatformInput::MouseMove(mouse_move)
5086 }
5087 PlatformInput::MouseDown(mouse_down) => {
5088 self.mouse_position = mouse_down.position;
5089 self.modifiers = mouse_down.modifiers;
5090 PlatformInput::MouseDown(mouse_down)
5091 }
5092 PlatformInput::MouseUp(mouse_up) => {
5093 self.mouse_position = mouse_up.position;
5094 self.modifiers = mouse_up.modifiers;
5095 PlatformInput::MouseUp(mouse_up)
5096 }
5097 PlatformInput::MousePressure(mouse_pressure) => {
5098 PlatformInput::MousePressure(mouse_pressure)
5099 }
5100 PlatformInput::MouseExited(mouse_exited) => {
5101 self.modifiers = mouse_exited.modifiers;
5102 PlatformInput::MouseExited(mouse_exited)
5103 }
5104 PlatformInput::ModifiersChanged(modifiers_changed) => {
5105 self.modifiers = modifiers_changed.modifiers;
5106 self.capslock = modifiers_changed.capslock;
5107 PlatformInput::ModifiersChanged(modifiers_changed)
5108 }
5109 PlatformInput::ScrollWheel(scroll_wheel) => {
5110 self.mouse_position = scroll_wheel.position;
5111 self.modifiers = scroll_wheel.modifiers;
5112 PlatformInput::ScrollWheel(scroll_wheel)
5113 }
5114 PlatformInput::Pinch(pinch) => {
5115 self.mouse_position = pinch.position;
5116 self.modifiers = pinch.modifiers;
5117 PlatformInput::Pinch(pinch)
5118 }
5119 PlatformInput::FileDrop(file_drop) => match file_drop {
5122 FileDropEvent::Entered { position, paths } => {
5123 self.mouse_position = position;
5124 let source_window = self.handle.window_id();
5125 if !cx.restore_platform_drag(source_window) && cx.active_drag.is_none() {
5126 cx.active_drag = Some(AnyDrag {
5127 value: Arc::new(paths.clone()),
5128 view: cx.new(|_| paths).into(),
5129 cursor_offset: position,
5130 cursor_style: None,
5131 external_payload_source: None,
5132 });
5133 }
5134 PlatformInput::MouseMove(MouseMoveEvent {
5135 position,
5136 pressed_button: Some(MouseButton::Left),
5137 modifiers: Modifiers::default(),
5138 })
5139 }
5140 FileDropEvent::Pending { position } => {
5141 self.mouse_position = position;
5142 PlatformInput::MouseMove(MouseMoveEvent {
5143 position,
5144 pressed_button: Some(MouseButton::Left),
5145 modifiers: Modifiers::default(),
5146 })
5147 }
5148 FileDropEvent::Submit { position } => {
5149 cx.activate(true);
5150 self.mouse_position = position;
5151 PlatformInput::MouseUp(MouseUpEvent {
5152 button: MouseButton::Left,
5153 position,
5154 modifiers: Modifiers::default(),
5155 click_count: 1,
5156 })
5157 }
5158 FileDropEvent::Exited => {
5159 if !cx.hand_restored_drag_to_platform(self.handle.window_id()) {
5160 cx.active_drag.take();
5161 }
5162 self.refresh();
5163 PlatformInput::FileDrop(FileDropEvent::Exited)
5164 }
5165 FileDropEvent::Ended => {
5166 cx.end_platform_drag(self.handle.window_id());
5167 self.refresh();
5168 PlatformInput::FileDrop(FileDropEvent::Ended)
5169 }
5170 },
5171 PlatformInput::Touch(touch) => PlatformInput::Touch(touch),
5172 PlatformInput::KeyDown(_) | PlatformInput::KeyUp(_) => event,
5173 };
5174
5175 if let Some(any_mouse_event) = event.mouse_event() {
5176 self.dispatch_mouse_event(any_mouse_event, cx);
5177 } else if let Some(any_key_event) = event.keyboard_event() {
5178 self.dispatch_key_event(any_key_event, cx);
5179 }
5180
5181 self.promote_external_drag_to_platform(&event, cx);
5184
5185 if self.invalidator.update_count() > update_count_before {
5186 self.input_rate_tracker.borrow_mut().record_input();
5187 #[cfg(feature = "input-latency-histogram")]
5188 if self.invalidator.not_drawing() {
5189 self.input_latency_tracker.record_input(dispatch_time);
5190 } else {
5191 self.input_latency_tracker.record_mid_draw_input();
5192 }
5193 }
5194
5195 DispatchEventResult {
5196 propagate: cx.propagate_event,
5197 default_prevented: self.default_prevented,
5198 }
5199 }
5200
5201 fn promote_external_drag_to_platform(&mut self, event: &PlatformInput, cx: &mut App) {
5202 let PlatformInput::MouseMove(mouse_move) = event else {
5203 return;
5204 };
5205 if mouse_move.pressed_button != Some(MouseButton::Left) {
5206 return;
5207 }
5208 if Bounds::new(Point::default(), self.viewport_size).contains(&mouse_move.position) {
5209 return;
5210 }
5211 if !self.platform_window.can_start_external_drag() {
5212 return;
5213 }
5214 let Some(payload_source) = cx
5215 .active_drag
5216 .as_mut()
5217 .and_then(|drag| drag.external_payload_source.take())
5218 else {
5219 return;
5220 };
5221 let Some(payload) = payload_source(self, cx) else {
5222 return;
5223 };
5224 if self.platform_window.start_external_drag(&payload)
5225 && cx.hand_active_drag_to_platform(self.handle.window_id())
5226 {
5227 self.refresh();
5228 }
5229 }
5230
5231 fn dispatch_mouse_event(&mut self, event: &dyn Any, cx: &mut App) {
5232 let hit_test = self.rendered_frame.hit_test(self.mouse_position());
5233 if hit_test != self.mouse_hit_test {
5234 self.mouse_hit_test = hit_test;
5235 self.reset_cursor_style(cx);
5236 }
5237
5238 #[cfg(any(feature = "inspector", debug_assertions))]
5239 if self.is_inspector_picking(cx) {
5240 self.handle_inspector_mouse_event(event, cx);
5241 return;
5243 }
5244
5245 let mut mouse_listeners = mem::take(&mut self.rendered_frame.mouse_listeners);
5246
5247 for listener in &mut mouse_listeners {
5250 let listener = listener.as_mut().unwrap();
5251 listener(event, DispatchPhase::Capture, self, cx);
5252 if !cx.propagate_event {
5253 break;
5254 }
5255 }
5256
5257 if cx.propagate_event {
5259 for listener in mouse_listeners.iter_mut().rev() {
5260 let listener = listener.as_mut().unwrap();
5261 listener(event, DispatchPhase::Bubble, self, cx);
5262 if !cx.propagate_event {
5263 break;
5264 }
5265 }
5266 }
5267
5268 self.rendered_frame.mouse_listeners = mouse_listeners;
5269
5270 if cx.has_active_drag() {
5271 if event.is::<MouseMoveEvent>() {
5272 self.refresh();
5275 } else if event.is::<MouseUpEvent>() {
5276 cx.active_drag = None;
5279 self.refresh();
5280 }
5281 }
5282
5283 if event.is::<MouseUpEvent>() && self.captured_hitbox.is_some() {
5285 self.captured_hitbox = None;
5286 }
5287 }
5288
5289 fn dispatch_key_event(&mut self, event: &dyn Any, cx: &mut App) {
5290 if self.invalidator.is_dirty() {
5291 self.draw(cx).clear(cx);
5292 }
5293
5294 let node_id = self.focus_node_id_in_rendered_frame(self.focus);
5295 let dispatch_path = self.rendered_frame.dispatch_tree.dispatch_path(node_id);
5296
5297 let mut keystroke: Option<Keystroke> = None;
5298
5299 if let Some(event) = event.downcast_ref::<ModifiersChangedEvent>() {
5300 if event.modifiers.number_of_modifiers() == 0
5301 && self.pending_modifier.modifiers.number_of_modifiers() == 1
5302 && !self.pending_modifier.saw_keystroke
5303 {
5304 let key = match self.pending_modifier.modifiers {
5305 modifiers if modifiers.shift => Some("shift"),
5306 modifiers if modifiers.control => Some("control"),
5307 modifiers if modifiers.alt => Some("alt"),
5308 modifiers if modifiers.platform => Some("platform"),
5309 modifiers if modifiers.function => Some("function"),
5310 _ => None,
5311 };
5312 if let Some(key) = key {
5313 keystroke = Some(Keystroke {
5314 key: key.to_string(),
5315 key_char: None,
5316 modifiers: Modifiers::default(),
5317 });
5318 }
5319 }
5320
5321 if self.pending_modifier.modifiers.number_of_modifiers() == 0
5322 && event.modifiers.number_of_modifiers() == 1
5323 {
5324 self.pending_modifier.saw_keystroke = false
5325 }
5326 self.pending_modifier.modifiers = event.modifiers
5327 } else if let Some(key_down_event) = event.downcast_ref::<KeyDownEvent>() {
5328 self.pending_modifier.saw_keystroke = true;
5329 keystroke = Some(key_down_event.keystroke.clone());
5330 if key_down_event.keystroke.key_char.is_some()
5331 && matches!(
5332 cx.cursor_hide_mode,
5333 CursorHideMode::OnTyping | CursorHideMode::OnTypingAndAction
5334 )
5335 {
5336 cx.platform.hide_cursor_until_mouse_moves();
5337 }
5338 }
5339
5340 let Some(keystroke) = keystroke else {
5341 self.finish_dispatch_key_event(event, dispatch_path, self.context_stack(), cx);
5342 return;
5343 };
5344
5345 cx.propagate_event = true;
5346 self.dispatch_keystroke_interceptors(event, self.context_stack(), cx);
5347 if !cx.propagate_event {
5348 self.finish_dispatch_key_event(event, dispatch_path, self.context_stack(), cx);
5349 return;
5350 }
5351
5352 let mut currently_pending = self.pending_input.take().unwrap_or_default();
5353 if currently_pending.focus.is_some() && currently_pending.focus != self.focus {
5354 currently_pending = PendingInput::default();
5355 }
5356
5357 let match_result = self.rendered_frame.dispatch_tree.dispatch_key(
5358 currently_pending.keystrokes,
5359 keystroke,
5360 &dispatch_path,
5361 );
5362
5363 if !match_result.to_replay.is_empty() {
5364 self.replay_pending_input(match_result.to_replay, cx);
5365 cx.propagate_event = true;
5366 }
5367
5368 if !match_result.pending.is_empty() {
5369 currently_pending.timer.take();
5370 currently_pending.keystrokes = match_result.pending;
5371 currently_pending.focus = self.focus;
5372
5373 let text_input_requires_timeout = event
5374 .downcast_ref::<KeyDownEvent>()
5375 .filter(|key_down| key_down.keystroke.key_char.is_some())
5376 .and_then(|_| self.platform_window.take_input_handler())
5377 .map_or(false, |mut input_handler| {
5378 let accepts = input_handler.accepts_text_input(self, cx);
5379 self.platform_window.set_input_handler(input_handler);
5380 accepts
5381 });
5382
5383 currently_pending.needs_timeout |=
5384 match_result.pending_has_binding || text_input_requires_timeout;
5385
5386 if currently_pending.needs_timeout {
5387 currently_pending.timer = Some(self.spawn(cx, async move |cx| {
5388 cx.background_executor.timer(Duration::from_secs(1)).await;
5389 cx.update(move |window, cx| {
5390 let Some(currently_pending) = window
5391 .pending_input
5392 .take()
5393 .filter(|pending| pending.focus == window.focus)
5394 else {
5395 return;
5396 };
5397
5398 let node_id = window.focus_node_id_in_rendered_frame(window.focus);
5399 let dispatch_path =
5400 window.rendered_frame.dispatch_tree.dispatch_path(node_id);
5401
5402 let to_replay = window
5403 .rendered_frame
5404 .dispatch_tree
5405 .flush_dispatch(currently_pending.keystrokes, &dispatch_path);
5406
5407 window.pending_input_changed(cx);
5408 window.replay_pending_input(to_replay, cx)
5409 })
5410 .log_err();
5411 }));
5412 } else {
5413 currently_pending.timer = None;
5414 }
5415 self.pending_input = Some(currently_pending);
5416 self.pending_input_changed(cx);
5417 cx.propagate_event = false;
5418 return;
5419 }
5420
5421 let skip_bindings = event
5422 .downcast_ref::<KeyDownEvent>()
5423 .filter(|key_down_event| key_down_event.prefer_character_input)
5424 .map(|_| {
5425 self.platform_window
5426 .take_input_handler()
5427 .map_or(false, |mut input_handler| {
5428 let accepts = input_handler.accepts_text_input(self, cx);
5429 self.platform_window.set_input_handler(input_handler);
5430 accepts
5433 })
5434 })
5435 .unwrap_or(false);
5436
5437 if !skip_bindings {
5438 for binding in match_result.bindings {
5439 self.dispatch_action_on_node(node_id, binding.action.as_ref(), cx);
5440 if !cx.propagate_event {
5441 self.dispatch_keystroke_observers(
5442 event,
5443 Some(binding.action),
5444 match_result.context_stack,
5445 cx,
5446 );
5447 self.pending_input_changed(cx);
5448 return;
5449 }
5450 }
5451 }
5452
5453 self.finish_dispatch_key_event(event, dispatch_path, match_result.context_stack, cx);
5454 self.pending_input_changed(cx);
5455 }
5456
5457 fn finish_dispatch_key_event(
5458 &mut self,
5459 event: &dyn Any,
5460 dispatch_path: SmallVec<[DispatchNodeId; 32]>,
5461 context_stack: Vec<KeyContext>,
5462 cx: &mut App,
5463 ) {
5464 self.dispatch_key_down_up_event(event, &dispatch_path, cx);
5465 if !cx.propagate_event {
5466 return;
5467 }
5468
5469 self.dispatch_modifiers_changed_event(event, &dispatch_path, cx);
5470 if !cx.propagate_event {
5471 return;
5472 }
5473
5474 self.dispatch_keystroke_observers(event, None, context_stack, cx);
5475 }
5476
5477 pub(crate) fn pending_input_changed(&mut self, cx: &mut App) {
5478 self.pending_input_observers
5479 .clone()
5480 .retain(&(), |callback| callback(self, cx));
5481 }
5482
5483 fn dispatch_key_down_up_event(
5484 &mut self,
5485 event: &dyn Any,
5486 dispatch_path: &SmallVec<[DispatchNodeId; 32]>,
5487 cx: &mut App,
5488 ) {
5489 for node_id in dispatch_path {
5491 let node = self.rendered_frame.dispatch_tree.node(*node_id);
5492
5493 for key_listener in node.key_listeners.clone() {
5494 key_listener(event, DispatchPhase::Capture, self, cx);
5495 if !cx.propagate_event {
5496 return;
5497 }
5498 }
5499 }
5500
5501 for node_id in dispatch_path.iter().rev() {
5503 let node = self.rendered_frame.dispatch_tree.node(*node_id);
5505 for key_listener in node.key_listeners.clone() {
5506 key_listener(event, DispatchPhase::Bubble, self, cx);
5507 if !cx.propagate_event {
5508 return;
5509 }
5510 }
5511 }
5512 }
5513
5514 fn dispatch_modifiers_changed_event(
5515 &mut self,
5516 event: &dyn Any,
5517 dispatch_path: &SmallVec<[DispatchNodeId; 32]>,
5518 cx: &mut App,
5519 ) {
5520 let Some(event) = event.downcast_ref::<ModifiersChangedEvent>() else {
5521 return;
5522 };
5523 for node_id in dispatch_path.iter().rev() {
5524 let node = self.rendered_frame.dispatch_tree.node(*node_id);
5525 for listener in node.modifiers_changed_listeners.clone() {
5526 listener(event, self, cx);
5527 if !cx.propagate_event {
5528 return;
5529 }
5530 }
5531 }
5532 }
5533
5534 fn active_pending_input(&self) -> Option<&PendingInput> {
5537 self.pending_input
5538 .as_ref()
5539 .filter(|pending_input| pending_input.focus == self.focus)
5540 }
5541
5542 pub fn has_pending_keystrokes(&self) -> bool {
5544 self.active_pending_input().is_some()
5545 }
5546
5547 pub(crate) fn clear_pending_keystrokes(&mut self) {
5548 self.pending_input.take();
5549 }
5550
5551 pub fn pending_input_keystrokes(&self) -> Option<&[Keystroke]> {
5553 self.active_pending_input()
5554 .map(|pending_input| pending_input.keystrokes.as_slice())
5555 }
5556
5557 fn replay_pending_input(&mut self, replays: SmallVec<[Replay; 1]>, cx: &mut App) {
5558 let node_id = self.focus_node_id_in_rendered_frame(self.focus);
5559 let dispatch_path = self.rendered_frame.dispatch_tree.dispatch_path(node_id);
5560
5561 'replay: for replay in replays {
5562 let event = KeyDownEvent {
5563 keystroke: replay.keystroke.clone(),
5564 is_held: false,
5565 prefer_character_input: true,
5566 };
5567
5568 cx.propagate_event = true;
5569 for binding in replay.bindings {
5570 self.dispatch_action_on_node(node_id, binding.action.as_ref(), cx);
5571 if !cx.propagate_event {
5572 self.dispatch_keystroke_observers(
5573 &event,
5574 Some(binding.action),
5575 Vec::default(),
5576 cx,
5577 );
5578 continue 'replay;
5579 }
5580 }
5581
5582 self.dispatch_key_down_up_event(&event, &dispatch_path, cx);
5583 if !cx.propagate_event {
5584 continue 'replay;
5585 }
5586 if let Some(input) = replay.keystroke.key_char.as_ref().cloned()
5587 && let Some(mut input_handler) = self.platform_window.take_input_handler()
5588 {
5589 input_handler.dispatch_input(&input, self, cx);
5590 self.platform_window.set_input_handler(input_handler)
5591 }
5592 }
5593 }
5594
5595 fn focus_node_id_in_rendered_frame(&self, focus_id: Option<FocusId>) -> DispatchNodeId {
5596 focus_id
5597 .and_then(|focus_id| {
5598 self.rendered_frame
5599 .dispatch_tree
5600 .focusable_node_id(focus_id)
5601 })
5602 .unwrap_or_else(|| self.rendered_frame.dispatch_tree.root_node_id())
5603 }
5604
5605 fn dispatch_action_on_node(
5606 &mut self,
5607 node_id: DispatchNodeId,
5608 action: &dyn Action,
5609 cx: &mut App,
5610 ) {
5611 self.dispatch_action_on_node_inner(node_id, action, cx);
5612
5613 if !cx.propagate_event
5614 && cx.cursor_hide_mode == CursorHideMode::OnTypingAndAction
5615 && self.last_input_was_keyboard()
5616 {
5617 cx.platform.hide_cursor_until_mouse_moves();
5618 }
5619 }
5620
5621 fn dispatch_action_on_node_inner(
5622 &mut self,
5623 node_id: DispatchNodeId,
5624 action: &dyn Action,
5625 cx: &mut App,
5626 ) {
5627 let dispatch_path = self.rendered_frame.dispatch_tree.dispatch_path(node_id);
5628
5629 cx.propagate_event = true;
5631 if let Some(mut global_listeners) = cx
5632 .global_action_listeners
5633 .remove(&action.as_any().type_id())
5634 {
5635 for listener in &global_listeners {
5636 profiler::update_running_action(action, cx);
5637 listener(action.as_any(), DispatchPhase::Capture, cx);
5638 profiler::save_action_timing();
5639 if !cx.propagate_event {
5640 break;
5641 }
5642 }
5643
5644 global_listeners.extend(
5645 cx.global_action_listeners
5646 .remove(&action.as_any().type_id())
5647 .unwrap_or_default(),
5648 );
5649
5650 cx.global_action_listeners
5651 .insert(action.as_any().type_id(), global_listeners);
5652 }
5653
5654 if !cx.propagate_event {
5655 return;
5656 }
5657
5658 for node_id in &dispatch_path {
5660 let node = self.rendered_frame.dispatch_tree.node(*node_id);
5661 for DispatchActionListener {
5662 action_type,
5663 listener,
5664 } in node.action_listeners.clone()
5665 {
5666 let any_action = action.as_any();
5667 if action_type == any_action.type_id() {
5668 profiler::update_running_action(action, cx);
5669 listener(any_action, DispatchPhase::Capture, self, cx);
5670 profiler::save_action_timing();
5671
5672 if !cx.propagate_event {
5673 return;
5674 }
5675 }
5676 }
5677 }
5678
5679 for node_id in dispatch_path.iter().rev() {
5681 let node = self.rendered_frame.dispatch_tree.node(*node_id);
5682 for DispatchActionListener {
5683 action_type,
5684 listener,
5685 } in node.action_listeners.clone()
5686 {
5687 let any_action = action.as_any();
5688 if action_type == any_action.type_id() {
5689 cx.propagate_event = false; profiler::update_running_action(action, cx);
5691 listener(any_action, DispatchPhase::Bubble, self, cx);
5692 profiler::save_action_timing();
5693
5694 if !cx.propagate_event {
5695 return;
5696 }
5697 }
5698 }
5699 }
5700
5701 if let Some(mut global_listeners) = cx
5703 .global_action_listeners
5704 .remove(&action.as_any().type_id())
5705 {
5706 for listener in global_listeners.iter().rev() {
5707 cx.propagate_event = false; profiler::update_running_action(action, cx);
5710 listener(action.as_any(), DispatchPhase::Bubble, cx);
5711 profiler::save_action_timing();
5712 if !cx.propagate_event {
5713 break;
5714 }
5715 }
5716
5717 global_listeners.extend(
5718 cx.global_action_listeners
5719 .remove(&action.as_any().type_id())
5720 .unwrap_or_default(),
5721 );
5722
5723 cx.global_action_listeners
5724 .insert(action.as_any().type_id(), global_listeners);
5725 }
5726 }
5727
5728 pub fn observe_global<G: Global>(
5731 &mut self,
5732 cx: &mut App,
5733 f: impl Fn(&mut Window, &mut App) + 'static,
5734 ) -> Subscription {
5735 let window_handle = self.handle;
5736 let (subscription, activate) = cx.global_observers.insert(
5737 TypeId::of::<G>(),
5738 Box::new(move |cx| {
5739 window_handle
5740 .update(cx, |_, window, cx| f(window, cx))
5741 .is_ok()
5742 }),
5743 );
5744 cx.defer(move |_| activate());
5745 subscription
5746 }
5747
5748 pub fn activate_window(&self) {
5750 self.platform_window.activate();
5751 }
5752
5753 pub fn request_attention(&self) {
5755 self.platform_window.request_attention();
5756 }
5757
5758 pub fn minimize_window(&self) {
5760 self.platform_window.minimize();
5761 }
5762
5763 pub fn toggle_fullscreen(&self) {
5765 self.platform_window.toggle_fullscreen();
5766 }
5767
5768 pub fn invalidate_character_coordinates(&self) {
5770 self.on_next_frame(|window, cx| {
5771 if let Some(mut input_handler) = window.platform_window.take_input_handler() {
5772 if let Some(bounds) = input_handler.selected_bounds(window, cx) {
5773 window.platform_window.update_ime_position(bounds);
5774 }
5775 window.platform_window.set_input_handler(input_handler);
5776 }
5777 });
5778 }
5779
5780 pub fn prompt<T>(
5784 &mut self,
5785 level: PromptLevel,
5786 message: &str,
5787 detail: Option<&str>,
5788 answers: &[T],
5789 cx: &mut App,
5790 ) -> oneshot::Receiver<usize>
5791 where
5792 T: Clone + Into<PromptButton>,
5793 {
5794 let prompt_builder = cx.prompt_builder.take();
5795 let Some(prompt_builder) = prompt_builder else {
5796 unreachable!("Re-entrant window prompting is not supported by GPUI");
5797 };
5798
5799 let answers = answers
5800 .iter()
5801 .map(|answer| answer.clone().into())
5802 .collect::<Vec<_>>();
5803
5804 let receiver = match &prompt_builder {
5805 PromptBuilder::Default => self
5806 .platform_window
5807 .prompt(level, message, detail, &answers)
5808 .unwrap_or_else(|| {
5809 self.build_custom_prompt(&prompt_builder, level, message, detail, &answers, cx)
5810 }),
5811 PromptBuilder::Custom(_) => {
5812 self.build_custom_prompt(&prompt_builder, level, message, detail, &answers, cx)
5813 }
5814 };
5815
5816 cx.prompt_builder = Some(prompt_builder);
5817
5818 receiver
5819 }
5820
5821 fn build_custom_prompt(
5822 &mut self,
5823 prompt_builder: &PromptBuilder,
5824 level: PromptLevel,
5825 message: &str,
5826 detail: Option<&str>,
5827 answers: &[PromptButton],
5828 cx: &mut App,
5829 ) -> oneshot::Receiver<usize> {
5830 let (sender, receiver) = oneshot::channel();
5831 let handle = PromptHandle::new(sender);
5832 let handle = (prompt_builder)(level, message, detail, answers, handle, self, cx);
5833 self.prompt = Some(handle);
5834 receiver
5835 }
5836
5837 pub fn has_active_prompt(&self) -> bool {
5842 self.prompt.is_some()
5843 }
5844
5845 pub fn context_stack(&self) -> Vec<KeyContext> {
5847 let node_id = self.focus_node_id_in_rendered_frame(self.focus);
5848 let dispatch_tree = &self.rendered_frame.dispatch_tree;
5849 dispatch_tree
5850 .dispatch_path(node_id)
5851 .iter()
5852 .filter_map(move |&node_id| dispatch_tree.node(node_id).context.clone())
5853 .collect()
5854 }
5855
5856 pub fn available_actions(&self, cx: &App) -> Vec<Box<dyn Action>> {
5858 let node_id = self.focus_node_id_in_rendered_frame(self.focus);
5859 let mut actions = self.rendered_frame.dispatch_tree.available_actions(node_id);
5860 for action_type in cx.global_action_listeners.keys() {
5861 if let Err(ix) = actions.binary_search_by_key(action_type, |a| a.as_any().type_id()) {
5862 let action = cx.actions.build_action_type(action_type).ok();
5863 if let Some(action) = action {
5864 actions.insert(ix, action);
5865 }
5866 }
5867 }
5868 actions
5869 }
5870
5871 pub fn bindings_for_action(&self, action: &dyn Action) -> Vec<KeyBinding> {
5874 self.rendered_frame
5875 .dispatch_tree
5876 .bindings_for_action(action, &self.rendered_frame.dispatch_tree.context_stack)
5877 }
5878
5879 pub fn highest_precedence_binding_for_action(&self, action: &dyn Action) -> Option<KeyBinding> {
5882 self.rendered_frame
5883 .dispatch_tree
5884 .highest_precedence_binding_for_action(
5885 action,
5886 &self.rendered_frame.dispatch_tree.context_stack,
5887 )
5888 }
5889
5890 pub fn bindings_for_action_in_context(
5892 &self,
5893 action: &dyn Action,
5894 context: KeyContext,
5895 ) -> Vec<KeyBinding> {
5896 let dispatch_tree = &self.rendered_frame.dispatch_tree;
5897 dispatch_tree.bindings_for_action(action, &[context])
5898 }
5899
5900 pub fn highest_precedence_binding_for_action_in_context(
5903 &self,
5904 action: &dyn Action,
5905 context: KeyContext,
5906 ) -> Option<KeyBinding> {
5907 let dispatch_tree = &self.rendered_frame.dispatch_tree;
5908 dispatch_tree.highest_precedence_binding_for_action(action, &[context])
5909 }
5910
5911 pub fn bindings_for_action_in(
5915 &self,
5916 action: &dyn Action,
5917 focus_handle: &FocusHandle,
5918 ) -> Vec<KeyBinding> {
5919 let dispatch_tree = &self.rendered_frame.dispatch_tree;
5920 let Some(context_stack) = self.context_stack_for_focus_handle(focus_handle) else {
5921 return vec![];
5922 };
5923 dispatch_tree.bindings_for_action(action, &context_stack)
5924 }
5925
5926 pub fn highest_precedence_binding_for_action_in(
5930 &self,
5931 action: &dyn Action,
5932 focus_handle: &FocusHandle,
5933 ) -> Option<KeyBinding> {
5934 let dispatch_tree = &self.rendered_frame.dispatch_tree;
5935 let context_stack = self.context_stack_for_focus_handle(focus_handle)?;
5936 dispatch_tree.highest_precedence_binding_for_action(action, &context_stack)
5937 }
5938
5939 pub fn possible_bindings_for_input(&self, input: &[Keystroke]) -> Vec<KeyBinding> {
5941 self.rendered_frame
5942 .dispatch_tree
5943 .possible_next_bindings_for_input(input, &self.context_stack())
5944 }
5945
5946 fn context_stack_for_focus_handle(
5947 &self,
5948 focus_handle: &FocusHandle,
5949 ) -> Option<Vec<KeyContext>> {
5950 let dispatch_tree = &self.rendered_frame.dispatch_tree;
5951 let node_id = dispatch_tree.focusable_node_id(focus_handle.id)?;
5952 let context_stack: Vec<_> = dispatch_tree
5953 .dispatch_path(node_id)
5954 .into_iter()
5955 .filter_map(|node_id| dispatch_tree.node(node_id).context.clone())
5956 .collect();
5957 Some(context_stack)
5958 }
5959
5960 pub fn listener_for<T: 'static, E>(
5962 &self,
5963 view: &Entity<T>,
5964 f: impl Fn(&mut T, &E, &mut Window, &mut Context<T>) + 'static,
5965 ) -> impl Fn(&E, &mut Window, &mut App) + 'static {
5966 let view = view.downgrade();
5967 move |e: &E, window: &mut Window, cx: &mut App| {
5968 view.update(cx, |view, cx| f(view, e, window, cx)).ok();
5969 }
5970 }
5971
5972 pub fn handler_for<E: 'static, Callback: Fn(&mut E, &mut Window, &mut Context<E>) + 'static>(
5974 &self,
5975 entity: &Entity<E>,
5976 f: Callback,
5977 ) -> impl Fn(&mut Window, &mut App) + 'static {
5978 let entity = entity.downgrade();
5979 move |window: &mut Window, cx: &mut App| {
5980 entity.update(cx, |entity, cx| f(entity, window, cx)).ok();
5981 }
5982 }
5983
5984 pub fn on_window_should_close(
5987 &self,
5988 cx: &App,
5989 f: impl Fn(&mut Window, &mut App) -> bool + 'static,
5990 ) {
5991 let mut cx = self.to_async(cx);
5992 self.platform_window.on_should_close(Box::new(move || {
5993 cx.update(|window, cx| f(window, cx)).unwrap_or(true)
5994 }))
5995 }
5996
5997 pub fn on_action(
6006 &mut self,
6007 action_type: TypeId,
6008 listener: impl Fn(&dyn Any, DispatchPhase, &mut Window, &mut App) + 'static,
6009 ) {
6010 self.invalidator.debug_assert_paint();
6011
6012 self.next_frame
6013 .dispatch_tree
6014 .on_action(action_type, Rc::new(listener));
6015 }
6016
6017 pub fn on_action_when(
6026 &mut self,
6027 condition: bool,
6028 action_type: TypeId,
6029 listener: impl Fn(&dyn Any, DispatchPhase, &mut Window, &mut App) + 'static,
6030 ) {
6031 self.invalidator.debug_assert_paint();
6032
6033 if condition {
6034 self.next_frame
6035 .dispatch_tree
6036 .on_action(action_type, Rc::new(listener));
6037 }
6038 }
6039
6040 pub fn gpu_specs(&self) -> Option<GpuSpecs> {
6043 self.platform_window.gpu_specs()
6044 }
6045
6046 #[cfg(any(target_os = "linux", target_os = "freebsd"))]
6049 pub fn gpu_context(&self) -> Option<Box<dyn std::any::Any>> {
6050 self.platform_window.gpu_context()
6051 }
6052
6053 #[cfg(any(target_os = "linux", target_os = "freebsd"))]
6059 pub fn gpu_device_lost(&self) -> Option<bool> {
6060 self.platform_window.gpu_device_lost()
6061 }
6062
6063 pub fn titlebar_double_click(&self) {
6066 self.platform_window.titlebar_double_click();
6067 }
6068
6069 pub fn window_title(&self) -> String {
6072 self.platform_window.get_title()
6073 }
6074
6075 pub fn tabbed_windows(&self) -> Option<Vec<SystemWindowTab>> {
6078 self.platform_window.tabbed_windows()
6079 }
6080
6081 pub fn tab_bar_visible(&self) -> bool {
6084 self.platform_window.tab_bar_visible()
6085 }
6086
6087 pub fn merge_all_windows(&self) {
6090 self.platform_window.merge_all_windows()
6091 }
6092
6093 pub fn move_tab_to_new_window(&self) {
6096 self.platform_window.move_tab_to_new_window()
6097 }
6098
6099 pub fn toggle_window_tab_overview(&self) {
6102 self.platform_window.toggle_window_tab_overview()
6103 }
6104
6105 pub fn set_tabbing_identifier(&self, tabbing_identifier: Option<String>) {
6108 self.platform_window
6109 .set_tabbing_identifier(tabbing_identifier)
6110 }
6111
6112 pub fn play_system_bell(&self) {
6115 self.platform_window.play_system_bell()
6116 }
6117
6118 pub fn is_a11y_active(&self) -> bool {
6129 self.a11y.is_active()
6130 }
6131
6132 pub fn debug_a11y_tree_json(&self) -> Option<String> {
6134 self.a11y.debug_tree_json()
6135 }
6136
6137 pub fn on_a11y_action(
6143 &mut self,
6144 node_id: accesskit::NodeId,
6145 action: accesskit::Action,
6146 listener: impl FnMut(Option<&accesskit::ActionData>, &mut Window, &mut App) + 'static,
6147 ) {
6148 self.a11y
6149 .action_listeners
6150 .entry(node_id)
6151 .or_default()
6152 .push((action, Box::new(listener)));
6153 }
6154
6155 #[cfg(not(target_family = "wasm"))]
6156 pub(crate) fn handle_a11y_action(&mut self, request: accesskit::ActionRequest, cx: &mut App) {
6157 if let Some(mut listeners) = self.a11y.action_listeners.remove(&request.target_node) {
6160 let extra_data = request.data.as_ref();
6161 let mut matched = false;
6162 for (action, listener) in &mut listeners {
6163 if *action == request.action {
6164 listener(extra_data, self, cx);
6165 matched = true;
6166 }
6167 }
6168 self.a11y
6169 .action_listeners
6170 .insert(request.target_node, listeners);
6171 if matched {
6172 return;
6173 }
6174 }
6175
6176 match request.action {
6178 accesskit::Action::Click => {
6179 if let Some(bounds) = self.a11y.node_bounds.get(&request.target_node).copied() {
6180 let center = bounds.center();
6181 let mouse_down = PlatformInput::MouseDown(crate::MouseDownEvent {
6182 button: MouseButton::Left,
6183 position: center,
6184 modifiers: Modifiers::default(),
6185 click_count: 1,
6186 first_mouse: false,
6187 });
6188 let mouse_up = PlatformInput::MouseUp(MouseUpEvent {
6189 button: MouseButton::Left,
6190 position: center,
6191 modifiers: Modifiers::default(),
6192 click_count: 1,
6193 });
6194 self.dispatch_event(mouse_down, cx);
6195 self.dispatch_event(mouse_up, cx);
6196 }
6197 }
6198 accesskit::Action::Focus => {
6199 if let Some(focus_id) = self.a11y.focus_ids.get(&request.target_node).copied()
6200 && let Some(handle) = FocusHandle::for_id(focus_id, &cx.focus_handles)
6201 {
6202 self.focus(&handle, cx);
6203 }
6204 }
6205 accesskit::Action::Blur => {
6206 self.blur();
6207 }
6208 _ => {
6209 log::debug!(
6210 "Unhandled a11y action: {:?} on {:?}",
6211 request.action,
6212 request.target_node
6213 );
6214 }
6215 }
6216 }
6217
6218 #[cfg(any(feature = "inspector", debug_assertions))]
6220 pub fn toggle_inspector(&mut self, cx: &mut App) {
6221 self.inspector = match self.inspector {
6222 None => Some(cx.new(|_| Inspector::new())),
6223 Some(_) => None,
6224 };
6225 self.refresh();
6226 }
6227
6228 pub fn is_inspector_picking(&self, _cx: &App) -> bool {
6230 #[cfg(any(feature = "inspector", debug_assertions))]
6231 {
6232 if let Some(inspector) = &self.inspector {
6233 return inspector.read(_cx).is_picking();
6234 }
6235 }
6236 false
6237 }
6238
6239 #[cfg(any(feature = "inspector", debug_assertions))]
6241 pub fn with_inspector_state<T: 'static, R>(
6242 &mut self,
6243 _inspector_id: Option<&crate::InspectorElementId>,
6244 cx: &mut App,
6245 f: impl FnOnce(&mut Option<T>, &mut Self) -> R,
6246 ) -> R {
6247 if let Some(inspector_id) = _inspector_id
6248 && let Some(inspector) = &self.inspector
6249 {
6250 let inspector = inspector.clone();
6251 let active_element_id = inspector.read(cx).active_element_id();
6252 if Some(inspector_id) == active_element_id {
6253 return inspector.update(cx, |inspector, _cx| {
6254 inspector.with_active_element_state(self, f)
6255 });
6256 }
6257 }
6258 f(&mut None, self)
6259 }
6260
6261 #[cfg(any(feature = "inspector", debug_assertions))]
6262 pub(crate) fn build_inspector_element_id(
6263 &mut self,
6264 path: crate::InspectorElementPath,
6265 ) -> crate::InspectorElementId {
6266 self.invalidator.debug_assert_paint_or_prepaint();
6267 let path = Rc::new(path);
6268 let next_instance_id = self
6269 .next_frame
6270 .next_inspector_instance_ids
6271 .entry(path.clone())
6272 .or_insert(0);
6273 let instance_id = *next_instance_id;
6274 *next_instance_id += 1;
6275 crate::InspectorElementId { path, instance_id }
6276 }
6277
6278 #[cfg(any(feature = "inspector", debug_assertions))]
6279 fn prepaint_inspector(&mut self, inspector_width: Pixels, cx: &mut App) -> Option<AnyElement> {
6280 if let Some(inspector) = self.inspector.take() {
6281 let mut inspector_element = AnyView::from(inspector.clone()).into_any_element();
6282 inspector_element.prepaint_as_root(
6283 point(self.viewport_size.width - inspector_width, px(0.0)),
6284 size(inspector_width, self.viewport_size.height).into(),
6285 self,
6286 cx,
6287 );
6288 self.inspector = Some(inspector);
6289 Some(inspector_element)
6290 } else {
6291 None
6292 }
6293 }
6294
6295 #[cfg(any(feature = "inspector", debug_assertions))]
6296 fn paint_inspector(&mut self, mut inspector_element: Option<AnyElement>, cx: &mut App) {
6297 if let Some(mut inspector_element) = inspector_element {
6298 inspector_element.paint(self, cx);
6299 };
6300 }
6301
6302 #[cfg(any(feature = "inspector", debug_assertions))]
6305 pub fn insert_inspector_hitbox(
6306 &mut self,
6307 hitbox_id: HitboxId,
6308 inspector_id: Option<&crate::InspectorElementId>,
6309 cx: &App,
6310 ) {
6311 self.invalidator.debug_assert_paint_or_prepaint();
6312 if !self.is_inspector_picking(cx) {
6313 return;
6314 }
6315 if let Some(inspector_id) = inspector_id {
6316 self.next_frame
6317 .inspector_hitboxes
6318 .insert(hitbox_id, inspector_id.clone());
6319 }
6320 }
6321
6322 #[cfg(any(feature = "inspector", debug_assertions))]
6323 fn paint_inspector_hitbox(&mut self, cx: &App) {
6324 if let Some(inspector) = self.inspector.as_ref() {
6325 let inspector = inspector.read(cx);
6326 if let Some((hitbox_id, _)) = self.hovered_inspector_hitbox(inspector, &self.next_frame)
6327 && let Some(hitbox) = self
6328 .next_frame
6329 .hitboxes
6330 .iter()
6331 .find(|hitbox| hitbox.id == hitbox_id)
6332 {
6333 self.paint_quad(crate::fill(hitbox.bounds, crate::rgba(0x61afef4d)));
6334 }
6335 }
6336 }
6337
6338 #[cfg(any(feature = "inspector", debug_assertions))]
6339 fn handle_inspector_mouse_event(&mut self, event: &dyn Any, cx: &mut App) {
6340 let Some(inspector) = self.inspector.clone() else {
6341 return;
6342 };
6343 if event.downcast_ref::<MouseMoveEvent>().is_some() {
6344 inspector.update(cx, |inspector, _cx| {
6345 if let Some((_, inspector_id)) =
6346 self.hovered_inspector_hitbox(inspector, &self.rendered_frame)
6347 {
6348 inspector.hover(inspector_id, self);
6349 }
6350 });
6351 } else if event.downcast_ref::<crate::MouseDownEvent>().is_some() {
6352 inspector.update(cx, |inspector, _cx| {
6353 if let Some((_, inspector_id)) =
6354 self.hovered_inspector_hitbox(inspector, &self.rendered_frame)
6355 {
6356 inspector.select(inspector_id, self);
6357 }
6358 });
6359 } else if let Some(event) = event.downcast_ref::<crate::ScrollWheelEvent>() {
6360 const SCROLL_LINES: f32 = 3.0;
6362 const SCROLL_PIXELS_PER_LAYER: f32 = 36.0;
6363 let delta_y = event
6364 .delta
6365 .pixel_delta(px(SCROLL_PIXELS_PER_LAYER / SCROLL_LINES))
6366 .y;
6367 if let Some(inspector) = self.inspector.clone() {
6368 inspector.update(cx, |inspector, _cx| {
6369 if let Some(depth) = inspector.pick_depth.as_mut() {
6370 *depth += f32::from(delta_y) / SCROLL_PIXELS_PER_LAYER;
6371 let max_depth = self.mouse_hit_test.ids.len() as f32 - 0.5;
6372 if *depth < 0.0 {
6373 *depth = 0.0;
6374 } else if *depth > max_depth {
6375 *depth = max_depth;
6376 }
6377 if let Some((_, inspector_id)) =
6378 self.hovered_inspector_hitbox(inspector, &self.rendered_frame)
6379 {
6380 inspector.set_active_element_id(inspector_id, self);
6381 }
6382 }
6383 });
6384 }
6385 }
6386 }
6387
6388 #[cfg(any(feature = "inspector", debug_assertions))]
6389 fn hovered_inspector_hitbox(
6390 &self,
6391 inspector: &Inspector,
6392 frame: &Frame,
6393 ) -> Option<(HitboxId, crate::InspectorElementId)> {
6394 if let Some(pick_depth) = inspector.pick_depth {
6395 let depth = (pick_depth as i64).try_into().unwrap_or(0);
6396 let max_skipped = self.mouse_hit_test.ids.len().saturating_sub(1);
6397 let skip_count = (depth as usize).min(max_skipped);
6398 for hitbox_id in self.mouse_hit_test.ids.iter().skip(skip_count) {
6399 if let Some(inspector_id) = frame.inspector_hitboxes.get(hitbox_id) {
6400 return Some((*hitbox_id, inspector_id.clone()));
6401 }
6402 }
6403 }
6404 None
6405 }
6406
6407 #[cfg(any(test, feature = "test-support"))]
6410 pub fn set_modifiers(&mut self, modifiers: Modifiers) {
6411 self.modifiers = modifiers;
6412 }
6413
6414 #[cfg(any(test, feature = "test-support"))]
6418 pub fn simulate_mouse_move(&mut self, position: Point<Pixels>, cx: &mut App) {
6419 let event = PlatformInput::MouseMove(MouseMoveEvent {
6420 position,
6421 modifiers: self.modifiers,
6422 pressed_button: None,
6423 });
6424 let _ = self.dispatch_event(event, cx);
6425 }
6426}
6427
6428slotmap::new_key_type! {
6430 pub struct WindowId;
6432}
6433
6434impl WindowId {
6435 pub fn as_u64(&self) -> u64 {
6437 self.0.as_ffi()
6438 }
6439}
6440
6441impl From<u64> for WindowId {
6442 fn from(value: u64) -> Self {
6443 WindowId(slotmap::KeyData::from_ffi(value))
6444 }
6445}
6446
6447#[derive(Deref, DerefMut)]
6450pub struct WindowHandle<V> {
6451 #[deref]
6452 #[deref_mut]
6453 pub(crate) any_handle: AnyWindowHandle,
6454 state_type: PhantomData<fn(V) -> V>,
6455}
6456
6457impl<V> Debug for WindowHandle<V> {
6458 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
6459 f.debug_struct("WindowHandle")
6460 .field("any_handle", &self.any_handle.id.as_u64())
6461 .finish()
6462 }
6463}
6464
6465impl<V: 'static + Render> WindowHandle<V> {
6466 pub fn new(id: WindowId) -> Self {
6469 WindowHandle {
6470 any_handle: AnyWindowHandle {
6471 id,
6472 state_type: TypeId::of::<V>(),
6473 },
6474 state_type: PhantomData,
6475 }
6476 }
6477
6478 #[cfg(any(test, feature = "test-support"))]
6482 pub fn root<C>(&self, cx: &mut C) -> Result<Entity<V>>
6483 where
6484 C: AppContext,
6485 {
6486 cx.update_window(self.any_handle, |root_view, _, _| {
6487 root_view
6488 .downcast::<V>()
6489 .map_err(|_| anyhow!("the type of the window's root view has changed"))
6490 })?
6491 }
6492
6493 pub fn update<C, R>(
6497 &self,
6498 cx: &mut C,
6499 update: impl FnOnce(&mut V, &mut Window, &mut Context<V>) -> R,
6500 ) -> Result<R>
6501 where
6502 C: AppContext,
6503 {
6504 cx.update_window(self.any_handle, |root_view, window, cx| {
6505 let view = root_view
6506 .downcast::<V>()
6507 .map_err(|_| anyhow!("the type of the window's root view has changed"))?;
6508
6509 Ok(view.update(cx, |view, cx| update(view, window, cx)))
6510 })?
6511 }
6512
6513 pub fn read<'a>(&self, cx: &'a App) -> Result<&'a V> {
6517 let x = cx
6518 .windows
6519 .get(self.id)
6520 .and_then(|window| {
6521 window
6522 .as_deref()
6523 .and_then(|window| window.root.clone())
6524 .map(|root_view| root_view.downcast::<V>())
6525 })
6526 .context("window not found")?
6527 .map_err(|_| anyhow!("the type of the window's root view has changed"))?;
6528
6529 Ok(x.read(cx))
6530 }
6531
6532 pub fn read_with<C, R>(&self, cx: &C, read_with: impl FnOnce(&V, &App) -> R) -> Result<R>
6536 where
6537 C: AppContext,
6538 {
6539 cx.read_window(self, |root_view, cx| read_with(root_view.read(cx), cx))
6540 }
6541
6542 pub fn entity<C>(&self, cx: &C) -> Result<Entity<V>>
6546 where
6547 C: AppContext,
6548 {
6549 cx.read_window(self, |root_view, _cx| root_view)
6550 }
6551
6552 pub fn is_active(&self, cx: &mut App) -> Option<bool> {
6557 cx.update_window(self.any_handle, |_, window, _| window.is_window_active())
6558 .ok()
6559 }
6560}
6561
6562impl<V> Copy for WindowHandle<V> {}
6563
6564impl<V> Clone for WindowHandle<V> {
6565 fn clone(&self) -> Self {
6566 *self
6567 }
6568}
6569
6570impl<V> PartialEq for WindowHandle<V> {
6571 fn eq(&self, other: &Self) -> bool {
6572 self.any_handle == other.any_handle
6573 }
6574}
6575
6576impl<V> Eq for WindowHandle<V> {}
6577
6578impl<V> Hash for WindowHandle<V> {
6579 fn hash<H: Hasher>(&self, state: &mut H) {
6580 self.any_handle.hash(state);
6581 }
6582}
6583
6584impl<V: 'static> From<WindowHandle<V>> for AnyWindowHandle {
6585 fn from(val: WindowHandle<V>) -> Self {
6586 val.any_handle
6587 }
6588}
6589
6590#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
6592pub struct AnyWindowHandle {
6593 pub(crate) id: WindowId,
6594 state_type: TypeId,
6595}
6596
6597impl AnyWindowHandle {
6598 pub fn window_id(&self) -> WindowId {
6600 self.id
6601 }
6602
6603 pub fn downcast<T: 'static>(&self) -> Option<WindowHandle<T>> {
6606 if TypeId::of::<T>() == self.state_type {
6607 Some(WindowHandle {
6608 any_handle: *self,
6609 state_type: PhantomData,
6610 })
6611 } else {
6612 None
6613 }
6614 }
6615
6616 pub fn update<C, R>(
6620 self,
6621 cx: &mut C,
6622 update: impl FnOnce(AnyView, &mut Window, &mut App) -> R,
6623 ) -> Result<R>
6624 where
6625 C: AppContext,
6626 {
6627 cx.update_window(self, update)
6628 }
6629
6630 pub fn read<T, C, R>(self, cx: &C, read: impl FnOnce(Entity<T>, &App) -> R) -> Result<R>
6634 where
6635 C: AppContext,
6636 T: 'static,
6637 {
6638 let view = self
6639 .downcast::<T>()
6640 .context("the type of the window's root view has changed")?;
6641
6642 cx.read_window(&view, read)
6643 }
6644}
6645
6646impl HasWindowHandle for Window {
6647 fn window_handle(&self) -> Result<raw_window_handle::WindowHandle<'_>, HandleError> {
6648 self.platform_window.window_handle()
6649 }
6650}
6651
6652impl HasDisplayHandle for Window {
6653 fn display_handle(
6654 &self,
6655 ) -> std::result::Result<raw_window_handle::DisplayHandle<'_>, HandleError> {
6656 self.platform_window.display_handle()
6657 }
6658}
6659
6660#[derive(Clone, Debug, Eq, PartialEq, Hash)]
6665pub enum ElementId {
6666 View(EntityId),
6668 Integer(u64),
6670 Name(SharedString),
6672 Uuid(Uuid),
6674 FocusHandle(FocusId),
6676 NamedInteger(SharedString, u64),
6678 Path(Arc<std::path::Path>),
6680 CodeLocation(core::panic::Location<'static>),
6682 NamedChild(Arc<ElementId>, SharedString),
6684 OpaqueId([u8; 20]),
6686}
6687
6688impl ElementId {
6689 pub fn named_usize(name: impl Into<SharedString>, integer: usize) -> ElementId {
6691 Self::NamedInteger(name.into(), integer as u64)
6692 }
6693}
6694
6695impl Display for ElementId {
6696 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
6697 match self {
6698 ElementId::View(entity_id) => write!(f, "view-{}", entity_id)?,
6699 ElementId::Integer(ix) => write!(f, "{}", ix)?,
6700 ElementId::Name(name) => write!(f, "{}", name)?,
6701 ElementId::FocusHandle(_) => write!(f, "FocusHandle")?,
6702 ElementId::NamedInteger(s, i) => write!(f, "{}-{}", s, i)?,
6703 ElementId::Uuid(uuid) => write!(f, "{}", uuid)?,
6704 ElementId::Path(path) => write!(f, "{}", path.display())?,
6705 ElementId::CodeLocation(location) => write!(f, "{}", location)?,
6706 ElementId::NamedChild(id, name) => write!(f, "{}-{}", id, name)?,
6707 ElementId::OpaqueId(opaque_id) => write!(f, "{:x?}", opaque_id)?,
6708 }
6709
6710 Ok(())
6711 }
6712}
6713
6714impl TryInto<SharedString> for ElementId {
6715 type Error = anyhow::Error;
6716
6717 fn try_into(self) -> anyhow::Result<SharedString> {
6718 if let ElementId::Name(name) = self {
6719 Ok(name)
6720 } else {
6721 anyhow::bail!("element id is not string")
6722 }
6723 }
6724}
6725
6726impl From<usize> for ElementId {
6727 fn from(id: usize) -> Self {
6728 ElementId::Integer(id as u64)
6729 }
6730}
6731
6732impl From<i32> for ElementId {
6733 fn from(id: i32) -> Self {
6734 Self::Integer(id as u64)
6735 }
6736}
6737
6738impl From<SharedString> for ElementId {
6739 fn from(name: SharedString) -> Self {
6740 ElementId::Name(name)
6741 }
6742}
6743
6744impl From<String> for ElementId {
6745 fn from(name: String) -> Self {
6746 ElementId::Name(name.into())
6747 }
6748}
6749
6750impl From<Arc<str>> for ElementId {
6751 fn from(name: Arc<str>) -> Self {
6752 ElementId::Name(name.into())
6753 }
6754}
6755
6756impl From<Arc<std::path::Path>> for ElementId {
6757 fn from(path: Arc<std::path::Path>) -> Self {
6758 ElementId::Path(path)
6759 }
6760}
6761
6762impl From<&'static str> for ElementId {
6763 fn from(name: &'static str) -> Self {
6764 ElementId::Name(SharedString::new_static(name))
6765 }
6766}
6767
6768impl<'a> From<&'a FocusHandle> for ElementId {
6769 fn from(handle: &'a FocusHandle) -> Self {
6770 ElementId::FocusHandle(handle.id)
6771 }
6772}
6773
6774impl From<(&'static str, EntityId)> for ElementId {
6775 fn from((name, id): (&'static str, EntityId)) -> Self {
6776 ElementId::NamedInteger(SharedString::new_static(name), id.as_u64())
6777 }
6778}
6779
6780impl From<(&'static str, usize)> for ElementId {
6781 fn from((name, id): (&'static str, usize)) -> Self {
6782 ElementId::NamedInteger(SharedString::new_static(name), id as u64)
6783 }
6784}
6785
6786impl From<(SharedString, usize)> for ElementId {
6787 fn from((name, id): (SharedString, usize)) -> Self {
6788 ElementId::NamedInteger(name, id as u64)
6789 }
6790}
6791
6792impl From<(&'static str, u64)> for ElementId {
6793 fn from((name, id): (&'static str, u64)) -> Self {
6794 ElementId::NamedInteger(SharedString::new_static(name), id)
6795 }
6796}
6797
6798impl From<Uuid> for ElementId {
6799 fn from(value: Uuid) -> Self {
6800 Self::Uuid(value)
6801 }
6802}
6803
6804impl From<(&'static str, u32)> for ElementId {
6805 fn from((name, id): (&'static str, u32)) -> Self {
6806 ElementId::NamedInteger(SharedString::new_static(name), u64::from(id))
6807 }
6808}
6809
6810impl<T: Into<SharedString>> From<(ElementId, T)> for ElementId {
6811 fn from((id, name): (ElementId, T)) -> Self {
6812 ElementId::NamedChild(Arc::new(id), name.into())
6813 }
6814}
6815
6816impl From<&'static core::panic::Location<'static>> for ElementId {
6817 fn from(location: &'static core::panic::Location<'static>) -> Self {
6818 ElementId::CodeLocation(*location)
6819 }
6820}
6821
6822impl From<[u8; 20]> for ElementId {
6823 fn from(opaque_id: [u8; 20]) -> Self {
6824 ElementId::OpaqueId(opaque_id)
6825 }
6826}
6827
6828#[derive(Clone)]
6831pub struct PaintQuad {
6832 pub bounds: Bounds<Pixels>,
6834 pub corner_radii: Corners<Pixels>,
6836 pub background: Background,
6838 pub border_widths: Edges<Pixels>,
6840 pub border_color: Hsla,
6842 pub border_style: BorderStyle,
6844}
6845
6846impl PaintQuad {
6847 pub fn corner_radii(self, corner_radii: impl Into<Corners<Pixels>>) -> Self {
6849 PaintQuad {
6850 corner_radii: corner_radii.into(),
6851 ..self
6852 }
6853 }
6854
6855 pub fn border_widths(self, border_widths: impl Into<Edges<Pixels>>) -> Self {
6857 PaintQuad {
6858 border_widths: border_widths.into(),
6859 ..self
6860 }
6861 }
6862
6863 pub fn border_color(self, border_color: impl IntoColor<Hsla>) -> Self {
6865 PaintQuad {
6866 border_color: border_color.into_color(),
6867 ..self
6868 }
6869 }
6870
6871 pub fn background(self, background: impl Into<Background>) -> Self {
6873 PaintQuad {
6874 background: background.into(),
6875 ..self
6876 }
6877 }
6878}
6879
6880pub fn quad(
6882 bounds: Bounds<Pixels>,
6883 corner_radii: impl Into<Corners<Pixels>>,
6884 background: impl Into<Background>,
6885 border_widths: impl Into<Edges<Pixels>>,
6886 border_color: impl IntoColor<Hsla>,
6887 border_style: BorderStyle,
6888) -> PaintQuad {
6889 PaintQuad {
6890 bounds,
6891 corner_radii: corner_radii.into(),
6892 background: background.into(),
6893 border_widths: border_widths.into(),
6894 border_color: border_color.into_color(),
6895 border_style,
6896 }
6897}
6898
6899pub fn fill(bounds: impl Into<Bounds<Pixels>>, background: impl Into<Background>) -> PaintQuad {
6901 PaintQuad {
6902 bounds: bounds.into(),
6903 corner_radii: (0.).into(),
6904 background: background.into(),
6905 border_widths: (0.).into(),
6906 border_color: transparent_black(),
6907 border_style: BorderStyle::default(),
6908 }
6909}
6910
6911pub fn outline(
6913 bounds: impl Into<Bounds<Pixels>>,
6914 border_color: impl IntoColor<Hsla>,
6915 border_style: BorderStyle,
6916) -> PaintQuad {
6917 PaintQuad {
6918 bounds: bounds.into(),
6919 corner_radii: (0.).into(),
6920 background: transparent_black().into(),
6921 border_widths: (1.).into(),
6922 border_color: border_color.into_color(),
6923 border_style,
6924 }
6925}
6926
6927#[cfg(test)]
6928mod tests {
6929 use std::{
6930 cell::{Cell, RefCell},
6931 path::PathBuf,
6932 rc::Rc,
6933 };
6934
6935 use crate::{
6936 AnyWindowHandle, AppContext as _, Bounds, Context, DragMoveEvent, Empty,
6937 ExternalDragPayload, ExternalPaths, FileDragPaths, FileDropEvent, FocusHandle,
6938 InputEvent as _, InteractiveElement as _, IntoElement, MouseButton, MouseDownEvent,
6939 MouseMoveEvent, ParentElement, Pixels, Point, Render, StatefulInteractiveElement as _,
6940 Styled, TestAppContext, Window, WindowAppearance, WindowOptions, canvas, div, point, px,
6941 size,
6942 };
6943
6944 struct EmptyView;
6945
6946 impl Render for EmptyView {
6947 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
6948 div()
6949 }
6950 }
6951
6952 struct OpensWindowOnPaint {
6953 opened: Rc<Cell<bool>>,
6954 }
6955
6956 impl Render for OpensWindowOnPaint {
6957 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
6958 let opened = self.opened.clone();
6959 div()
6960 .size_full()
6961 .child(canvas(
6962 |_, _, _| {},
6963 move |_, _, _window, cx| {
6964 if !opened.replace(true) {
6965 cx.open_window(WindowOptions::default(), |_, cx| cx.new(|_| EmptyView))
6966 .unwrap();
6967 }
6968 },
6969 ))
6970 .child(div().child("after"))
6974 }
6975 }
6976
6977 #[test]
6983 fn test_window_opened_during_draw_defers_arena_clear() {
6984 let mut cx = TestAppContext::single();
6985
6986 let opened = Rc::new(Cell::new(false));
6987 let window = cx.add_window({
6989 let opened = opened.clone();
6990 move |_, _| OpensWindowOnPaint { opened }
6991 });
6992
6993 assert!(opened.get());
6994 assert_eq!(cx.windows().len(), 2);
6995
6996 cx.update_window(window.into(), |_, window, cx| window.draw(cx).clear(cx))
6999 .unwrap();
7000 }
7001
7002 #[gpui::test]
7003 fn test_appearance_change_runs_after_app_update(cx: &mut TestAppContext) {
7004 let window = cx.add_window(|_, _| EmptyView);
7005 let observed_appearance = Rc::new(Cell::new(None));
7006 let _subscription = window
7007 .update(cx, {
7008 let observed_appearance = observed_appearance.clone();
7009 move |_, window, _| {
7010 window.observe_window_appearance(move |window, _| {
7011 observed_appearance.set(Some(window.appearance()));
7012 })
7013 }
7014 })
7015 .unwrap();
7016 let test_window = cx.test_window(window.into());
7017
7018 cx.update(|_| {
7019 test_window.simulate_appearance_change(WindowAppearance::Dark);
7020 assert_eq!(observed_appearance.get(), None);
7021 });
7022 cx.run_until_parked();
7023
7024 assert_eq!(observed_appearance.get(), Some(WindowAppearance::Dark));
7025 }
7026
7027 struct RootView {
7028 explicit_size: bool,
7029 child_bounds: Rc<Cell<Bounds<Pixels>>>,
7030 }
7031
7032 impl Render for RootView {
7033 fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
7034 let child_bounds = self.child_bounds.clone();
7035 let root = div().flex().flex_col().child(
7036 canvas(
7037 move |bounds, _, _| child_bounds.set(bounds),
7038 |_, _, _, _| {},
7039 )
7040 .size_full(),
7041 );
7042 if self.explicit_size {
7043 root.w(px(300.)).h(px(200.))
7044 } else {
7045 root
7046 }
7047 }
7048 }
7049
7050 #[test]
7051 fn auto_sized_window_root_fills_the_window() {
7052 let mut cx = TestAppContext::single();
7053 let child_bounds = Rc::new(Cell::new(Bounds::default()));
7054 let window = cx.add_window({
7055 let child_bounds = child_bounds.clone();
7056 move |_, _| RootView {
7057 explicit_size: false,
7058 child_bounds,
7059 }
7060 });
7061
7062 let viewport_size = cx
7063 .update_window(window.into(), |_, window, cx| {
7064 window.draw(cx).clear(cx);
7065 window.viewport_size()
7066 })
7067 .unwrap();
7068
7069 assert_eq!(child_bounds.get().size, viewport_size);
7070 }
7071
7072 #[test]
7073 fn explicitly_sized_window_root_keeps_its_size() {
7074 let mut cx = TestAppContext::single();
7075 let child_bounds = Rc::new(Cell::new(Bounds::default()));
7076 let window = cx.add_window({
7077 let child_bounds = child_bounds.clone();
7078 move |_, _| RootView {
7079 explicit_size: true,
7080 child_bounds,
7081 }
7082 });
7083
7084 cx.update_window(window.into(), |_, window, cx| {
7085 window.draw(cx).clear(cx);
7086 })
7087 .unwrap();
7088
7089 assert_eq!(child_bounds.get().size, size(px(300.), px(200.)));
7090 }
7091
7092 struct FileDragView {
7093 path: PathBuf,
7094 observed_drag_moves: Rc<RefCell<Vec<Point<Pixels>>>>,
7095 observed_drops: Rc<RefCell<Vec<PathBuf>>>,
7096 }
7097
7098 impl Render for FileDragView {
7099 fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
7100 div()
7101 .id("file-drag")
7102 .size_full()
7103 .on_drag(self.path.clone(), |_, _, _, cx| cx.new(|_| Empty))
7104 .external_drag_payload(|path: &PathBuf, _, _| {
7105 Some(ExternalDragPayload::Files(FileDragPaths::new([(
7106 path.clone(),
7107 true,
7108 )])))
7109 })
7110 .on_drag_move({
7111 let observed_drag_moves = self.observed_drag_moves.clone();
7112 move |event: &DragMoveEvent<PathBuf>, _, _| {
7113 observed_drag_moves.borrow_mut().push(event.event.position);
7114 }
7115 })
7116 .on_drop({
7117 let observed_drops = self.observed_drops.clone();
7118 move |path: &PathBuf, _, _| observed_drops.borrow_mut().push(path.clone())
7119 })
7120 }
7121 }
7122
7123 #[gpui::test]
7124 fn file_drag_is_promoted_once_and_restored_in_source_window(cx: &mut TestAppContext) {
7125 struct Drag {
7126 window: AnyWindowHandle,
7127 observed_drag_moves: Rc<RefCell<Vec<Point<Pixels>>>>,
7128 observed_drops: Rc<RefCell<Vec<PathBuf>>>,
7129 }
7130
7131 fn start_drag(cx: &mut TestAppContext, path: PathBuf, platform_result: bool) -> Drag {
7132 let observed_drag_moves = Rc::new(RefCell::new(Vec::new()));
7133 let observed_drops = Rc::new(RefCell::new(Vec::new()));
7134 let window: AnyWindowHandle = cx
7135 .add_window({
7136 let observed_drag_moves = observed_drag_moves.clone();
7137 let observed_drops = observed_drops.clone();
7138 move |_, _| FileDragView {
7139 path,
7140 observed_drag_moves,
7141 observed_drops,
7142 }
7143 })
7144 .into();
7145 cx.test_window(window)
7146 .set_start_external_drag_result(platform_result);
7147
7148 let update_result = cx.update_window(window, |_, window, cx| {
7149 window.draw(cx).clear(cx);
7150 window.dispatch_event(
7151 MouseDownEvent {
7152 position: point(px(10.), px(10.)),
7153 button: MouseButton::Left,
7154 modifiers: Default::default(),
7155 click_count: 1,
7156 first_mouse: false,
7157 }
7158 .to_platform_input(),
7159 cx,
7160 );
7161 window.dispatch_event(
7162 MouseMoveEvent {
7163 position: point(px(20.), px(20.)),
7164 pressed_button: Some(MouseButton::Left),
7165 modifiers: Default::default(),
7166 }
7167 .to_platform_input(),
7168 cx,
7169 );
7170 assert!(cx.active_drag.is_some());
7171 });
7172 assert!(
7173 update_result.is_ok(),
7174 "failed to start drag: {update_result:?}"
7175 );
7176
7177 assert!(cx.test_window(window).external_drag_files().is_empty());
7178 Drag {
7179 window,
7180 observed_drag_moves,
7181 observed_drops,
7182 }
7183 }
7184
7185 let successful_path = PathBuf::from("/tmp/successful-drag");
7186 let successful = start_drag(cx, successful_path.clone(), true);
7187 let outside_position = point(px(-1.), px(20.));
7188 let update_result = cx.update_window(successful.window, |_, window, cx| {
7189 window.dispatch_event(
7190 MouseMoveEvent {
7191 position: outside_position,
7192 pressed_button: Some(MouseButton::Left),
7193 modifiers: Default::default(),
7194 }
7195 .to_platform_input(),
7196 cx,
7197 );
7198 assert!(cx.active_drag.is_none());
7199 });
7200 assert!(
7201 update_result.is_ok(),
7202 "failed to promote drag: {update_result:?}"
7203 );
7204 assert_eq!(
7205 cx.test_window(successful.window).external_drag_files(),
7206 [(successful_path.clone(), true)]
7207 );
7208 assert_eq!(
7211 successful.observed_drag_moves.borrow().last(),
7212 Some(&outside_position)
7213 );
7214
7215 let destination: AnyWindowHandle = cx.add_window(|_, _| EmptyView).into();
7216 let reentry_position = point(px(30.), px(30.));
7217 let external_paths = || ExternalPaths([successful_path.clone()].into_iter().collect());
7218 let update_result = cx.update_window(destination, |_, window, cx| {
7219 window.dispatch_event(
7220 FileDropEvent::Entered {
7221 position: reentry_position,
7222 paths: external_paths(),
7223 }
7224 .to_platform_input(),
7225 cx,
7226 );
7227 assert!(
7228 cx.active_drag
7229 .as_ref()
7230 .is_some_and(|drag| drag.value.downcast_ref::<ExternalPaths>().is_some())
7231 );
7232 window.dispatch_event(FileDropEvent::Exited.to_platform_input(), cx);
7233 assert!(cx.active_drag.is_none());
7234 });
7235 assert!(
7236 update_result.is_ok(),
7237 "failed to handle drag in destination window: {update_result:?}"
7238 );
7239
7240 let update_result = cx.update_window(successful.window, |_, window, cx| {
7241 window.dispatch_event(
7242 FileDropEvent::Entered {
7243 position: reentry_position,
7244 paths: external_paths(),
7245 }
7246 .to_platform_input(),
7247 cx,
7248 );
7249 assert!(
7250 cx.active_drag
7251 .as_ref()
7252 .is_some_and(|drag| drag.value.downcast_ref::<PathBuf>().is_some())
7253 );
7254 assert_eq!(
7255 successful.observed_drag_moves.borrow().last(),
7256 Some(&reentry_position)
7257 );
7258
7259 window.dispatch_event(FileDropEvent::Exited.to_platform_input(), cx);
7260 assert!(cx.active_drag.is_none());
7261
7262 window.dispatch_event(
7263 FileDropEvent::Entered {
7264 position: reentry_position,
7265 paths: external_paths(),
7266 }
7267 .to_platform_input(),
7268 cx,
7269 );
7270 assert!(
7271 cx.active_drag
7272 .as_ref()
7273 .is_some_and(|drag| drag.value.downcast_ref::<PathBuf>().is_some())
7274 );
7275
7276 window.dispatch_event(
7277 FileDropEvent::Submit {
7278 position: reentry_position,
7279 }
7280 .to_platform_input(),
7281 cx,
7282 );
7283 assert_eq!(
7284 successful.observed_drops.borrow().as_slice(),
7285 std::slice::from_ref(&successful_path)
7286 );
7287 assert!(cx.active_drag.is_none());
7288
7289 window.dispatch_event(FileDropEvent::Exited.to_platform_input(), cx);
7290 assert!(cx.active_drag.is_none());
7291 window.dispatch_event(FileDropEvent::Ended.to_platform_input(), cx);
7292 assert!(cx.active_drag.is_none());
7293
7294 window.dispatch_event(
7295 FileDropEvent::Entered {
7296 position: reentry_position,
7297 paths: external_paths(),
7298 }
7299 .to_platform_input(),
7300 cx,
7301 );
7302 assert!(
7303 cx.active_drag
7304 .as_ref()
7305 .is_some_and(|drag| drag.value.downcast_ref::<ExternalPaths>().is_some())
7306 );
7307 window.dispatch_event(FileDropEvent::Exited.to_platform_input(), cx);
7308 });
7309 assert!(
7310 update_result.is_ok(),
7311 "failed to restore drag in source window: {update_result:?}"
7312 );
7313
7314 let cancelled_path = PathBuf::from("/tmp/cancelled-drag");
7315 let cancelled = start_drag(cx, cancelled_path.clone(), true);
7316 let update_result = cx.update_window(cancelled.window, |_, window, cx| {
7317 window.dispatch_event(
7318 MouseMoveEvent {
7319 position: outside_position,
7320 pressed_button: Some(MouseButton::Left),
7321 modifiers: Default::default(),
7322 }
7323 .to_platform_input(),
7324 cx,
7325 );
7326 assert!(cx.active_drag.is_none());
7327
7328 window.dispatch_event(
7329 FileDropEvent::Entered {
7330 position: reentry_position,
7331 paths: ExternalPaths([cancelled_path].into_iter().collect()),
7332 }
7333 .to_platform_input(),
7334 cx,
7335 );
7336 assert!(
7337 cx.active_drag
7338 .as_ref()
7339 .is_some_and(|drag| drag.value.downcast_ref::<PathBuf>().is_some())
7340 );
7341 assert!(cx.stop_active_drag(window));
7342 assert!(cx.active_drag.is_none());
7343 });
7344 assert!(
7345 update_result.is_ok(),
7346 "failed to cancel restored drag: {update_result:?}"
7347 );
7348 assert!(!cx.update(|cx| cx.end_platform_drag(cancelled.window.window_id())));
7349
7350 let removed_path = PathBuf::from("/tmp/removed-window-drag");
7351 let removed = start_drag(cx, removed_path, true);
7352 let removed_window_id = removed.window.window_id();
7353 let update_result = cx.update_window(removed.window, |_, window, cx| {
7354 window.dispatch_event(
7355 MouseMoveEvent {
7356 position: outside_position,
7357 pressed_button: Some(MouseButton::Left),
7358 modifiers: Default::default(),
7359 }
7360 .to_platform_input(),
7361 cx,
7362 );
7363 assert!(cx.active_drag.is_none());
7364 window.remove_window();
7365 });
7366 assert!(
7367 update_result.is_ok(),
7368 "failed to remove drag source window: {update_result:?}"
7369 );
7370 assert!(!cx.update(|cx| cx.end_platform_drag(removed_window_id)));
7371
7372 let failed_path = PathBuf::from("/tmp/failed-drag");
7373 let failed = start_drag(cx, failed_path.clone(), false);
7374 let update_result = cx.update_window(failed.window, |_, window, cx| {
7375 for x_position in [-1., -2.] {
7376 window.dispatch_event(
7377 MouseMoveEvent {
7378 position: point(px(x_position), px(20.)),
7379 pressed_button: Some(MouseButton::Left),
7380 modifiers: Default::default(),
7381 }
7382 .to_platform_input(),
7383 cx,
7384 );
7385 }
7386 assert!(cx.active_drag.is_some());
7387 });
7388 assert!(
7389 update_result.is_ok(),
7390 "failed to retain drag after platform failure: {update_result:?}"
7391 );
7392 assert_eq!(
7393 cx.test_window(failed.window).external_drag_files(),
7394 [(failed_path, true)]
7395 );
7396 }
7397
7398 struct FocusForwarder {
7399 a: FocusHandle,
7400 b: FocusHandle,
7401 }
7402
7403 impl Render for FocusForwarder {
7404 fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
7405 div()
7406 .size_full()
7407 .child(div().w(px(50.)).h(px(50.)).track_focus(&self.a))
7408 .child(div().w(px(50.)).h(px(50.)).track_focus(&self.b))
7409 }
7410 }
7411
7412 #[gpui::test]
7416 fn test_focus_moved_by_focus_listener_is_dispatched(cx: &mut TestAppContext) {
7417 let b_focus_count = Rc::new(Cell::new(0));
7418 let window = cx.add_window({
7419 let b_focus_count = b_focus_count.clone();
7420 move |window, cx| {
7421 let a = cx.focus_handle();
7422 let b = cx.focus_handle();
7423 cx.on_focus(&a, window, |this: &mut FocusForwarder, window, cx| {
7424 let b = this.b.clone();
7425 window.focus(&b, cx);
7426 })
7427 .detach();
7428 cx.on_focus(&b, window, move |_, _, _| {
7429 b_focus_count.set(b_focus_count.get() + 1);
7430 })
7431 .detach();
7432 FocusForwarder { a, b }
7433 }
7434 });
7435
7436 window
7437 .update(cx, |_, window, _| window.activate_window())
7438 .unwrap();
7439 cx.executor().run_until_parked();
7440
7441 window
7442 .update(cx, |this, window, cx| {
7443 let a = this.a.clone();
7444 window.focus(&a, cx);
7445 })
7446 .unwrap();
7447 cx.executor().run_until_parked();
7448
7449 window
7450 .update(cx, |this, window, _| {
7451 assert!(this.b.is_focused(window));
7452 })
7453 .unwrap();
7454 assert_eq!(b_focus_count.get(), 1);
7455 }
7456}