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