1#[cfg(any(feature = "inspector", debug_assertions))]
2use crate::Inspector;
3use crate::{
4 Action, AnyDrag, AnyElement, AnyImageCache, AnyTooltip, AnyView, App, AppContext, Arena, Asset,
5 AsyncWindowContext, AtlasTile, AvailableSpace, Background, BlendMode, BorderStyle, Bounds,
6 BoxShadow, Capslock, Context, Corners, CursorStyle, Decorations, DevicePixels,
7 DispatchActionListener, DispatchNodeId, DispatchTree, DisplayId, Edges, Effect, Entity,
8 EntityId, EventEmitter, FileDropEvent, FontId, Global, GlobalElementId, GlyphId, GpuSpecs,
9 Hsla, InputHandler, InputPreference, IsZero, KeyBinding, KeyContext, KeyDownEvent, KeyEvent,
10 Keystroke, KeystrokeEvent, LayoutId, LineLayoutIndex, Modifiers, ModifiersChangedEvent,
11 MonochromeSprite, MouseButton, MouseEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels,
12 PlatformAtlas, PlatformDisplay, PlatformInput, PlatformInputHandler, PlatformWindow, Point,
13 PolychromeSprite, ProgressBarState, PromptButton, PromptLevel, Quad, Render, RenderGlyphParams,
14 RenderImage, RenderImageParams, RenderSvgParams, Replay, ResizeAnchor, ResizeEdge,
15 SMOOTH_SVG_SCALE_FACTOR, SUBPIXEL_VARIANTS_X, SUBPIXEL_VARIANTS_Y, ScaledPixels, Scene, Shadow,
16 SharedString, Size, StrikethroughStyle, Style, SubscriberSet, Subscription, SystemWindowTab,
17 SystemWindowTabController, TabStopMap, TaffyLayoutEngine, Task, TextStyle, TextStyleRefinement,
18 ThermalState, TransformationMatrix, Underline, UnderlineStyle, WindowAppearance,
19 WindowBackgroundAppearance, WindowBounds, WindowControls, WindowDecorations, WindowOptions,
20 WindowParams, WindowState, WindowTextSystem, WindowVisibility, point, prelude::*, px, rems,
21 size, transparent_black,
22};
23use anyhow::{Context as _, Result, anyhow};
24use collections::{FxHashMap, FxHashSet};
25#[cfg(target_os = "macos")]
26use core_video::pixel_buffer::CVPixelBuffer;
27use derive_more::{Deref, DerefMut};
28use futures::channel::oneshot;
29#[cfg(feature = "input-latency-histogram")]
30use hdrhistogram::Histogram;
31use itertools::FoldWhile::{Continue, Done};
32use itertools::Itertools;
33use parking_lot::{RwLock, RwLockUpgradableReadGuard};
34use raw_window_handle::{HandleError, HasDisplayHandle, HasWindowHandle};
35use refineable::Refineable;
36use slotmap::SlotMap;
37use smallvec::SmallVec;
38use std::{
39 any::{Any, TypeId},
40 borrow::Cow,
41 cell::{Cell, RefCell},
42 cmp,
43 fmt::{Debug, Display},
44 hash::{Hash, Hasher},
45 marker::PhantomData,
46 mem,
47 ops::{DerefMut, Range},
48 rc::Rc,
49 sync::{
50 Arc, Weak,
51 atomic::{AtomicBool, AtomicUsize, Ordering::SeqCst},
52 },
53 time::{Duration, Instant},
54};
55use util::post_inc;
56use util::{ResultExt, measure};
57use uuid::Uuid;
58
59pub(crate) mod a11y;
60mod prompts;
61
62use crate::util::{
63 atomic_incr_if_not_zero, ceil_to_device_pixel, floor_to_device_pixel, round_half_toward_zero,
64 round_half_toward_zero_f64, round_stroke_to_device_pixel, round_to_device_pixel,
65};
66use a11y::{A11y, ROOT_NODE_ID};
67pub use prompts::*;
68
69#[doc(hidden)]
70pub const DEFAULT_WINDOW_SIZE: Size<Pixels> = size(px(1536.), px(864.));
71
72#[derive(Default, Copy, Clone, Debug, Eq, PartialEq)]
74pub enum DispatchPhase {
75 #[default]
80 Bubble,
81 Capture,
87}
88
89impl DispatchPhase {
90 #[inline]
92 pub fn bubble(self) -> bool {
93 self == DispatchPhase::Bubble
94 }
95
96 #[inline]
98 pub fn capture(self) -> bool {
99 self == DispatchPhase::Capture
100 }
101}
102
103struct WindowInvalidatorInner {
104 pub dirty: bool,
105 pub draw_phase: DrawPhase,
106 pub dirty_views: FxHashSet<EntityId>,
107 pub update_count: usize,
108}
109
110#[derive(Clone)]
111pub(crate) struct WindowInvalidator {
112 inner: Rc<RefCell<WindowInvalidatorInner>>,
113}
114
115impl WindowInvalidator {
116 pub fn new() -> Self {
117 WindowInvalidator {
118 inner: Rc::new(RefCell::new(WindowInvalidatorInner {
119 dirty: true,
120 draw_phase: DrawPhase::None,
121 dirty_views: FxHashSet::default(),
122 update_count: 0,
123 })),
124 }
125 }
126
127 pub fn invalidate_view(&self, entity: EntityId, cx: &mut App) -> bool {
128 let mut inner = self.inner.borrow_mut();
129 inner.update_count += 1;
130 inner.dirty_views.insert(entity);
131 if inner.draw_phase == DrawPhase::None {
132 inner.dirty = true;
133 cx.push_effect(Effect::Notify { emitter: entity });
134 true
135 } else {
136 false
137 }
138 }
139
140 pub fn is_dirty(&self) -> bool {
141 self.inner.borrow().dirty
142 }
143
144 pub fn set_dirty(&self, dirty: bool) {
145 let mut inner = self.inner.borrow_mut();
146 inner.dirty = dirty;
147 if dirty {
148 inner.update_count += 1;
149 }
150 }
151
152 pub fn set_phase(&self, phase: DrawPhase) {
153 self.inner.borrow_mut().draw_phase = phase
154 }
155
156 pub fn update_count(&self) -> usize {
157 self.inner.borrow().update_count
158 }
159
160 pub fn take_views(&self) -> FxHashSet<EntityId> {
161 mem::take(&mut self.inner.borrow_mut().dirty_views)
162 }
163
164 pub fn replace_views(&self, views: FxHashSet<EntityId>) {
165 self.inner.borrow_mut().dirty_views = views;
166 }
167
168 pub fn not_drawing(&self) -> bool {
169 self.inner.borrow().draw_phase == DrawPhase::None
170 }
171
172 #[track_caller]
173 pub fn debug_assert_paint(&self) {
174 debug_assert!(
175 matches!(self.inner.borrow().draw_phase, DrawPhase::Paint),
176 "this method can only be called during paint"
177 );
178 }
179
180 #[track_caller]
181 pub fn debug_assert_prepaint(&self) {
182 debug_assert!(
183 matches!(self.inner.borrow().draw_phase, DrawPhase::Prepaint),
184 "this method can only be called during request_layout, or prepaint"
185 );
186 }
187
188 #[track_caller]
189 pub fn debug_assert_paint_or_prepaint(&self) {
190 debug_assert!(
191 matches!(
192 self.inner.borrow().draw_phase,
193 DrawPhase::Paint | DrawPhase::Prepaint
194 ),
195 "this method can only be called during request_layout, prepaint, or paint"
196 );
197 }
198}
199
200type AnyObserver = Box<dyn FnMut(&mut Window, &mut App) -> bool + 'static>;
201
202pub(crate) type AnyWindowFocusListener =
203 Box<dyn FnMut(&WindowFocusEvent, &mut Window, &mut App) -> bool + 'static>;
204
205pub(crate) struct WindowFocusEvent {
206 pub(crate) previous_focus_path: SmallVec<[FocusId; 8]>,
207 pub(crate) current_focus_path: SmallVec<[FocusId; 8]>,
208}
209
210impl WindowFocusEvent {
211 pub fn is_focus_in(&self, focus_id: FocusId) -> bool {
212 !self.previous_focus_path.contains(&focus_id) && self.current_focus_path.contains(&focus_id)
213 }
214
215 pub fn is_focus_out(&self, focus_id: FocusId) -> bool {
216 self.previous_focus_path.contains(&focus_id) && !self.current_focus_path.contains(&focus_id)
217 }
218}
219
220pub struct FocusOutEvent {
222 pub blurred: WeakFocusHandle,
224}
225
226slotmap::new_key_type! {
227 pub struct FocusId;
229}
230
231pub(crate) static ELEMENT_ARENA_SIZE: std::sync::atomic::AtomicUsize =
234 std::sync::atomic::AtomicUsize::new(1024 * 1024);
235
236thread_local! {
237 pub(crate) static ELEMENT_ARENA: RefCell<Arena> = RefCell::new(
238 Arena::new(ELEMENT_ARENA_SIZE.load(std::sync::atomic::Ordering::Relaxed))
239 );
240}
241
242struct ElementArenaScope;
244
245impl ElementArenaScope {
246 fn enter() -> Self {
247 ELEMENT_ARENA.with_borrow_mut(Arena::begin_scope);
248 Self
249 }
250}
251
252impl Drop for ElementArenaScope {
253 fn drop(&mut self) {
254 ELEMENT_ARENA.with_borrow_mut(Arena::end_scope);
255 }
256}
257
258fn draw_in_progress() -> bool {
267 ELEMENT_ARENA.with(|arena| {
268 arena
269 .try_borrow()
270 .map(|arena| arena.has_active_scope())
271 .unwrap_or(true)
272 })
273}
274
275#[must_use]
277pub struct ArenaClearNeeded;
278
279impl ArenaClearNeeded {
280 pub fn clear(self) {
282 ELEMENT_ARENA.with_borrow_mut(|element_arena| {
283 element_arena.clear();
284 });
285 }
286}
287
288#[derive(Default)]
289pub(crate) struct FocusMap {
290 pub(crate) handles: SlotMap<FocusId, FocusRef>,
291 pub(crate) dropped_handles: Vec<FocusId>,
292}
293pub(crate) struct FocusRef {
294 pub(crate) ref_count: AtomicUsize,
295 pub(crate) tab_index: isize,
296 pub(crate) tab_stop: bool,
297}
298
299impl FocusId {
300 pub fn is_focused(&self, window: &Window) -> bool {
302 window.focus == Some(*self)
303 }
304
305 pub fn contains_focused(&self, window: &Window, cx: &App) -> bool {
308 window
309 .focused(cx)
310 .is_some_and(|focused| self.contains(focused.id, window))
311 }
312
313 pub fn within_focused(&self, window: &Window, cx: &App) -> bool {
316 let focused = window.focused(cx);
317 focused.is_some_and(|focused| focused.id.contains(*self, window))
318 }
319
320 pub(crate) fn contains(&self, other: Self, window: &Window) -> bool {
322 window
323 .rendered_frame
324 .dispatch_tree
325 .focus_contains(*self, other)
326 }
327}
328
329pub struct FocusHandle {
331 pub(crate) id: FocusId,
332 handles: Arc<RwLock<FocusMap>>,
333 pub tab_index: isize,
335 pub tab_stop: bool,
337}
338
339impl std::fmt::Debug for FocusHandle {
340 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
341 f.write_fmt(format_args!("FocusHandle({:?})", self.id))
342 }
343}
344
345impl FocusHandle {
346 pub(crate) fn new(handles: &Arc<RwLock<FocusMap>>) -> Self {
347 let id = handles.write().handles.insert(FocusRef {
348 ref_count: AtomicUsize::new(1),
349 tab_index: 0,
350 tab_stop: false,
351 });
352
353 Self {
354 id,
355 tab_index: 0,
356 tab_stop: false,
357 handles: handles.clone(),
358 }
359 }
360
361 pub(crate) fn for_id(id: FocusId, handles: &Arc<RwLock<FocusMap>>) -> Option<Self> {
362 let lock = handles.read();
363 let focus = lock.handles.get(id)?;
364 if atomic_incr_if_not_zero(&focus.ref_count) == 0 {
365 return None;
366 }
367 Some(Self {
368 id,
369 tab_index: focus.tab_index,
370 tab_stop: focus.tab_stop,
371 handles: handles.clone(),
372 })
373 }
374
375 pub fn tab_index(mut self, index: isize) -> Self {
377 self.tab_index = index;
378 if let Some(focus) = self.handles.write().handles.get_mut(self.id) {
379 focus.tab_index = index;
380 }
381 self
382 }
383
384 pub fn tab_stop(mut self, tab_stop: bool) -> Self {
388 self.tab_stop = tab_stop;
389 if let Some(focus) = self.handles.write().handles.get_mut(self.id) {
390 focus.tab_stop = tab_stop;
391 }
392 self
393 }
394
395 pub fn downgrade(&self) -> WeakFocusHandle {
397 WeakFocusHandle {
398 id: self.id,
399 handles: Arc::downgrade(&self.handles),
400 }
401 }
402
403 pub fn focus(&self, window: &mut Window) {
405 window.focus(self)
406 }
407
408 pub fn is_focused(&self, window: &Window) -> bool {
410 self.id.is_focused(window)
411 }
412
413 pub fn contains_focused(&self, window: &Window, cx: &App) -> bool {
416 self.id.contains_focused(window, cx)
417 }
418
419 pub fn within_focused(&self, window: &Window, cx: &mut App) -> bool {
422 self.id.within_focused(window, cx)
423 }
424
425 pub fn contains(&self, other: &Self, window: &Window) -> bool {
427 self.id.contains(other.id, window)
428 }
429
430 pub fn dispatch_action(&self, action: &dyn Action, window: &mut Window, cx: &mut App) {
432 if let Some(node_id) = window
433 .rendered_frame
434 .dispatch_tree
435 .focusable_node_id(self.id)
436 {
437 window.dispatch_action_on_node(node_id, action, cx)
438 }
439 }
440}
441
442impl Clone for FocusHandle {
443 fn clone(&self) -> Self {
444 Self::for_id(self.id, &self.handles).unwrap()
445 }
446}
447
448impl PartialEq for FocusHandle {
449 fn eq(&self, other: &Self) -> bool {
450 self.id == other.id
451 }
452}
453
454impl Eq for FocusHandle {}
455
456impl Drop for FocusHandle {
457 fn drop(&mut self) {
458 let handles = self.handles.upgradable_read();
459 let focus = handles.handles.get(self.id).expect("focus handle missing");
460 let previous_count = focus.ref_count.fetch_sub(1, SeqCst);
461 assert_ne!(previous_count, 0, "over-released focus handle");
462 if previous_count == 1 {
463 RwLockUpgradableReadGuard::upgrade(handles)
464 .dropped_handles
465 .push(self.id);
466 }
467 }
468}
469
470#[derive(Clone, Debug)]
472pub struct WeakFocusHandle {
473 pub(crate) id: FocusId,
474 pub(crate) handles: Weak<RwLock<FocusMap>>,
475}
476
477impl WeakFocusHandle {
478 pub fn upgrade(&self) -> Option<FocusHandle> {
480 let handles = self.handles.upgrade()?;
481 FocusHandle::for_id(self.id, &handles)
482 }
483}
484
485impl PartialEq for WeakFocusHandle {
486 fn eq(&self, other: &WeakFocusHandle) -> bool {
487 self.id == other.id
488 }
489}
490
491impl Eq for WeakFocusHandle {}
492
493impl PartialEq<FocusHandle> for WeakFocusHandle {
494 fn eq(&self, other: &FocusHandle) -> bool {
495 self.id == other.id
496 }
497}
498
499impl PartialEq<WeakFocusHandle> for FocusHandle {
500 fn eq(&self, other: &WeakFocusHandle) -> bool {
501 self.id == other.id
502 }
503}
504
505pub trait Focusable: 'static {
508 fn focus_handle(&self, cx: &App) -> FocusHandle;
510}
511
512impl<V: Focusable> Focusable for Entity<V> {
513 fn focus_handle(&self, cx: &App) -> FocusHandle {
514 self.read(cx).focus_handle(cx)
515 }
516}
517
518pub trait ManagedView: Focusable + EventEmitter<DismissEvent> + Render {}
521
522impl<M: Focusable + EventEmitter<DismissEvent> + Render> ManagedView for M {}
523
524pub struct DismissEvent;
526
527type FrameCallback = Box<dyn FnOnce(&mut Window, &mut App)>;
528
529pub(crate) type AnyMouseListener =
530 Box<dyn FnMut(&dyn Any, DispatchPhase, &mut Window, &mut App) + 'static>;
531
532#[derive(Clone)]
533pub(crate) struct CursorStyleRequest {
534 pub(crate) hitbox_id: Option<HitboxId>,
535 pub(crate) style: CursorStyle,
536}
537
538#[derive(Default, Eq, PartialEq)]
539pub(crate) struct HitTest {
540 pub(crate) ids: SmallVec<[HitboxId; 8]>,
541 pub(crate) hover_hitbox_count: usize,
542}
543
544#[derive(Clone, Copy, Debug, Eq, PartialEq)]
546pub enum WindowControlArea {
547 Drag,
549 Close,
551 Max,
553 Min,
555}
556
557#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
559pub struct HitboxId(u64);
560
561impl HitboxId {
562 pub fn is_hovered(self, window: &Window) -> bool {
568 if window.captured_hitbox == Some(self) {
570 return true;
571 }
572 if window.last_input_was_keyboard() {
573 return false;
574 }
575 self.hit_test(window)
576 }
577
578 pub(crate) fn is_hovered_ignoring_last_input(self, window: &Window) -> bool {
583 if window.captured_hitbox == Some(self) {
585 return true;
586 }
587 self.hit_test(window)
588 }
589
590 fn hit_test(self, window: &Window) -> bool {
591 let hit_test = &window.mouse_hit_test;
592 for id in hit_test.ids.iter().take(hit_test.hover_hitbox_count) {
593 if self == *id {
594 return true;
595 }
596 }
597 false
598 }
599
600 pub fn should_handle_scroll(self, window: &Window) -> bool {
605 window.mouse_hit_test.ids.contains(&self)
606 }
607
608 fn next(mut self) -> HitboxId {
609 HitboxId(self.0.wrapping_add(1))
610 }
611}
612
613#[derive(Clone, Debug, Deref)]
616pub struct Hitbox {
617 pub id: HitboxId,
619 #[deref]
621 pub bounds: Bounds<Pixels>,
622 pub content_mask: ContentMask<Pixels>,
624 pub behavior: HitboxBehavior,
626}
627
628impl Hitbox {
629 pub fn is_hovered(&self, window: &Window) -> bool {
644 self.id.is_hovered(window)
645 }
646
647 pub fn is_hovered_at(&self, position: Point<Pixels>, window: &Window) -> bool {
656 let hit_test = window.rendered_frame.hit_test(position);
657 hit_test
658 .ids
659 .iter()
660 .take(hit_test.hover_hitbox_count)
661 .any(|id| self.id == *id)
662 }
663
664 pub fn should_handle_scroll(&self, window: &Window) -> bool {
671 self.id.should_handle_scroll(window)
672 }
673}
674
675#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
677pub enum HitboxBehavior {
678 #[default]
680 Normal,
681
682 BlockMouse,
704
705 BlockMouseExceptScroll,
732}
733
734#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
736pub struct TooltipId(usize);
737
738impl TooltipId {
739 pub fn is_hovered(&self, window: &Window) -> bool {
741 window
742 .tooltip_bounds
743 .as_ref()
744 .is_some_and(|tooltip_bounds| {
745 tooltip_bounds.id == *self
746 && tooltip_bounds.bounds.contains(&window.mouse_position())
747 })
748 }
749}
750
751pub(crate) struct TooltipBounds {
752 id: TooltipId,
753 bounds: Bounds<Pixels>,
754}
755
756#[derive(Clone)]
757pub(crate) struct TooltipRequest {
758 id: TooltipId,
759 tooltip: AnyTooltip,
760}
761
762pub(crate) struct DeferredDraw {
763 current_view: EntityId,
764 priority: usize,
765 parent_node: DispatchNodeId,
766 element_id_stack: SmallVec<[ElementId; 32]>,
767 text_style_stack: SmallVec<[TextStyleRefinement; 4]>,
768 element: Option<AnyElement>,
769 absolute_offset: Point<Pixels>,
770 prepaint_range: Range<PrepaintStateIndex>,
771 paint_range: Range<PaintIndex>,
772}
773
774pub(crate) struct Frame {
775 pub(crate) focus: Option<FocusId>,
776 pub(crate) window_active: bool,
777 pub(crate) element_states: FxHashMap<(GlobalElementId, TypeId), ElementStateBox>,
778 accessed_element_states: Vec<(GlobalElementId, TypeId)>,
779 pub(crate) mouse_listeners: Vec<Option<AnyMouseListener>>,
780 pub(crate) dispatch_tree: DispatchTree,
781 pub(crate) scene: Scene,
782 pub(crate) hitboxes: Vec<Hitbox>,
783 pub(crate) window_control_hitboxes: Vec<(WindowControlArea, Hitbox)>,
784 pub(crate) deferred_draws: Vec<DeferredDraw>,
785 pub(crate) input_handlers: Vec<Option<PlatformInputHandler>>,
786 pub(crate) tooltip_requests: Vec<Option<TooltipRequest>>,
787 pub(crate) cursor_styles: Vec<CursorStyleRequest>,
788 #[cfg(any(test, feature = "test-support"))]
789 pub(crate) debug_bounds: FxHashMap<String, Bounds<Pixels>>,
790 #[cfg(any(test, feature = "test-support"))]
791 debug_bounds_records: Vec<(String, Bounds<Pixels>)>,
792 #[cfg(any(feature = "inspector", debug_assertions))]
793 pub(crate) next_inspector_instance_ids: FxHashMap<Rc<crate::InspectorElementPath>, usize>,
794 #[cfg(any(feature = "inspector", debug_assertions))]
795 pub(crate) inspector_hitboxes: FxHashMap<HitboxId, crate::InspectorElementId>,
796 pub(crate) tab_stops: TabStopMap,
797}
798
799#[derive(Clone, Default)]
800pub(crate) struct PrepaintStateIndex {
801 hitboxes_index: usize,
802 tooltips_index: usize,
803 deferred_draws_index: usize,
804 dispatch_tree_index: usize,
805 accessed_element_states_index: usize,
806 line_layout_index: LineLayoutIndex,
807}
808
809#[derive(Clone, Default)]
810pub(crate) struct PaintIndex {
811 scene_index: usize,
812 #[cfg(any(test, feature = "test-support"))]
813 debug_bounds_index: usize,
814 mouse_listeners_index: usize,
815 input_handlers_index: usize,
816 cursor_styles_index: usize,
817 accessed_element_states_index: usize,
818 tab_handle_index: usize,
819 line_layout_index: LineLayoutIndex,
820}
821
822impl Frame {
823 #[cfg(any(test, feature = "test-support"))]
824 pub(crate) fn record_debug_bounds(&mut self, selector: String, bounds: Bounds<Pixels>) {
825 self.debug_bounds.insert(selector.clone(), bounds);
826 self.debug_bounds_records.push((selector, bounds));
827 }
828
829 pub(crate) fn new(dispatch_tree: DispatchTree) -> Self {
830 Frame {
831 focus: None,
832 window_active: false,
833 element_states: FxHashMap::default(),
834 accessed_element_states: Vec::new(),
835 mouse_listeners: Vec::new(),
836 dispatch_tree,
837 scene: Scene::default(),
838 hitboxes: Vec::new(),
839 window_control_hitboxes: Vec::new(),
840 deferred_draws: Vec::new(),
841 input_handlers: Vec::new(),
842 tooltip_requests: Vec::new(),
843 cursor_styles: Vec::new(),
844
845 #[cfg(any(test, feature = "test-support"))]
846 debug_bounds: FxHashMap::default(),
847 #[cfg(any(test, feature = "test-support"))]
848 debug_bounds_records: Vec::new(),
849
850 #[cfg(any(feature = "inspector", debug_assertions))]
851 next_inspector_instance_ids: FxHashMap::default(),
852
853 #[cfg(any(feature = "inspector", debug_assertions))]
854 inspector_hitboxes: FxHashMap::default(),
855 tab_stops: TabStopMap::default(),
856 }
857 }
858
859 pub(crate) fn clear(&mut self) {
860 self.element_states.clear();
861 self.accessed_element_states.clear();
862 self.mouse_listeners.clear();
863 self.dispatch_tree.clear();
864 self.scene.clear();
865 self.input_handlers.clear();
866 self.tooltip_requests.clear();
867 self.cursor_styles.clear();
868 self.hitboxes.clear();
869 self.window_control_hitboxes.clear();
870 self.deferred_draws.clear();
871 self.tab_stops.clear();
872 self.focus = None;
873
874 #[cfg(any(test, feature = "test-support"))]
875 {
876 self.debug_bounds.clear();
877 self.debug_bounds_records.clear();
878 }
879
880 #[cfg(any(feature = "inspector", debug_assertions))]
881 {
882 self.next_inspector_instance_ids.clear();
883 self.inspector_hitboxes.clear();
884 }
885 }
886
887 pub(crate) fn cursor_style(&self, window: &Window) -> Option<CursorStyle> {
888 self.cursor_styles
889 .iter()
890 .rev()
891 .fold_while(None, |style, request| match request.hitbox_id {
892 None => Done(Some(request.style)),
893 Some(hitbox_id) => Continue(style.or_else(|| {
894 hitbox_id
895 .is_hovered_ignoring_last_input(window)
896 .then_some(request.style)
897 })),
898 })
899 .into_inner()
900 }
901
902 pub(crate) fn hit_test(&self, position: Point<Pixels>) -> HitTest {
903 let mut set_hover_hitbox_count = false;
904 let mut hit_test = HitTest::default();
905 for hitbox in self.hitboxes.iter().rev() {
906 let bounds = hitbox.bounds.intersect(&hitbox.content_mask.bounds);
907 if bounds.contains(&position) {
908 hit_test.ids.push(hitbox.id);
909 if !set_hover_hitbox_count
910 && hitbox.behavior == HitboxBehavior::BlockMouseExceptScroll
911 {
912 hit_test.hover_hitbox_count = hit_test.ids.len();
913 set_hover_hitbox_count = true;
914 }
915 if hitbox.behavior == HitboxBehavior::BlockMouse {
916 break;
917 }
918 }
919 }
920 if !set_hover_hitbox_count {
921 hit_test.hover_hitbox_count = hit_test.ids.len();
922 }
923 hit_test
924 }
925
926 pub(crate) fn focus_path(&self) -> SmallVec<[FocusId; 8]> {
927 self.focus
928 .map(|focus_id| self.dispatch_tree.focus_path(focus_id))
929 .unwrap_or_default()
930 }
931
932 pub(crate) fn finish(&mut self, prev_frame: &mut Self) {
933 for element_state_key in &self.accessed_element_states {
934 if let Some((element_state_key, element_state)) =
935 prev_frame.element_states.remove_entry(element_state_key)
936 {
937 self.element_states.insert(element_state_key, element_state);
938 }
939 }
940
941 self.scene.finish();
942 }
943}
944
945#[derive(Clone, Debug)]
948pub(crate) struct InputRateTracker {
949 timestamps: Vec<Instant>,
950 window: Duration,
951 inputs_per_second: u32,
952 sustain_until: Instant,
953 sustain_duration: Duration,
954}
955
956impl Default for InputRateTracker {
957 fn default() -> Self {
958 Self {
959 timestamps: Vec::new(),
960 window: Duration::from_millis(100),
961 inputs_per_second: 60,
962 sustain_until: Instant::now(),
963 sustain_duration: Duration::from_secs(1),
964 }
965 }
966}
967
968impl InputRateTracker {
969 pub fn record_input(&mut self) {
970 let now = Instant::now();
971 self.timestamps.push(now);
972 self.timestamps
973 .retain(|&t| now.duration_since(t) <= self.window);
974 let min_events = self.inputs_per_second as u128 * self.window.as_millis() / 1000;
975 if self.timestamps.len() as u128 >= min_events {
976 self.sustain_until = now + self.sustain_duration;
977 }
978 }
979
980 pub fn is_high_rate(&self) -> bool {
981 Instant::now() < self.sustain_until
982 }
983}
984
985const THIRTY_FPS_INTERVAL: Duration = Duration::from_micros(33333);
986const SIXTY_FPS_INTERVAL: Duration = Duration::from_micros(16667);
987const FRAME_INTERVAL_TOLERANCE: Duration = Duration::from_millis(1);
988
989#[derive(Default)]
991struct FramePacer {
992 last_frame: Option<Instant>,
993}
994
995impl FramePacer {
996 fn should_defer(&mut self, now: Instant, minimum_interval: Option<Duration>) -> bool {
997 if let Some(interval) = minimum_interval
998 && let Some(last_frame) = self.last_frame
999 {
1000 let deadline = last_frame + interval;
1001 if now + FRAME_INTERVAL_TOLERANCE < deadline {
1002 return true;
1003 }
1004 self.last_frame = Some(if now.saturating_duration_since(deadline) <= interval / 4 {
1008 deadline
1009 } else {
1010 now
1011 });
1012 } else {
1013 self.last_frame = Some(now);
1014 }
1015 false
1016 }
1017}
1018
1019fn minimum_frame_interval(
1020 should_throttle: bool,
1021 inactive_without_high_rate_input: bool,
1022 inactive_frame_interval: Option<Duration>,
1023 thermal_state: ThermalState,
1024 power_mode: crate::PowerMode,
1025) -> Option<Duration> {
1026 if !should_throttle {
1027 return None;
1028 }
1029
1030 [
1034 inactive_frame_interval.filter(|_| inactive_without_high_rate_input),
1035 (power_mode == crate::PowerMode::LowPower).then_some(THIRTY_FPS_INTERVAL),
1036 matches!(
1037 thermal_state,
1038 ThermalState::Critical | ThermalState::Serious
1039 )
1040 .then_some(SIXTY_FPS_INTERVAL),
1041 ]
1042 .into_iter()
1043 .flatten()
1044 .max()
1045}
1046
1047#[cfg(feature = "input-latency-histogram")]
1049pub struct InputLatencySnapshot {
1050 pub latency_histogram: Histogram<u64>,
1052 pub events_per_frame_histogram: Histogram<u64>,
1054 pub mid_draw_events_dropped: u64,
1056}
1057
1058#[cfg(feature = "input-latency-histogram")]
1059struct InputLatencyTracker {
1060 first_input_at: Option<Instant>,
1061 pending_input_count: u64,
1062 latency_histogram: Histogram<u64>,
1063 events_per_frame_histogram: Histogram<u64>,
1064 mid_draw_events_dropped: u64,
1065}
1066
1067#[cfg(feature = "input-latency-histogram")]
1068impl InputLatencyTracker {
1069 fn new() -> Result<Self> {
1070 Ok(Self {
1071 first_input_at: None,
1072 pending_input_count: 0,
1073 latency_histogram: Histogram::new(3)
1074 .map_err(|error| anyhow!("failed to create input latency histogram: {error}"))?,
1075 events_per_frame_histogram: Histogram::new(3)
1076 .map_err(|error| anyhow!("failed to create events per frame histogram: {error}"))?,
1077 mid_draw_events_dropped: 0,
1078 })
1079 }
1080
1081 fn record_input(&mut self, dispatch_time: Instant) {
1082 self.first_input_at.get_or_insert(dispatch_time);
1083 self.pending_input_count += 1;
1084 }
1085
1086 fn record_mid_draw_input(&mut self) {
1087 self.mid_draw_events_dropped += 1;
1088 }
1089
1090 fn record_frame_presented(&mut self) {
1091 if let Some(first_input_at) = self.first_input_at.take() {
1092 self.latency_histogram
1093 .record(first_input_at.elapsed().as_nanos() as u64)
1094 .ok();
1095 }
1096
1097 if self.pending_input_count > 0 {
1098 self.events_per_frame_histogram
1099 .record(self.pending_input_count)
1100 .ok();
1101 self.pending_input_count = 0;
1102 }
1103 }
1104
1105 fn snapshot(&self) -> InputLatencySnapshot {
1106 InputLatencySnapshot {
1107 latency_histogram: self.latency_histogram.clone(),
1108 events_per_frame_histogram: self.events_per_frame_histogram.clone(),
1109 mid_draw_events_dropped: self.mid_draw_events_dropped,
1110 }
1111 }
1112}
1113
1114pub struct Window {
1116 pub(crate) handle: AnyWindowHandle,
1117 pub(crate) invalidator: WindowInvalidator,
1118 pub(crate) removed: bool,
1119 pub(crate) platform_window: Box<dyn PlatformWindow>,
1120 pub(crate) a11y: A11y,
1121 display_id: Option<DisplayId>,
1122 sprite_atlas: Arc<dyn PlatformAtlas>,
1123 text_system: Arc<WindowTextSystem>,
1124 rem_size: Pixels,
1125 rem_size_override_stack: SmallVec<[Pixels; 8]>,
1130 pub(crate) viewport_size: Size<Pixels>,
1131 layout_engine: Option<TaffyLayoutEngine>,
1132 pub(crate) root: Option<AnyView>,
1133 pub(crate) element_id_stack: SmallVec<[ElementId; 32]>,
1134 pub(crate) text_style_stack: SmallVec<[TextStyleRefinement; 4]>,
1135 pub(crate) rendered_entity_stack: SmallVec<[EntityId; 16]>,
1136 pub(crate) element_offset_stack: SmallVec<[Point<Pixels>; 16]>,
1137 pub(crate) element_opacity: f32,
1138 pub(crate) content_mask_stack: SmallVec<[ContentMask<Pixels>; 16]>,
1139 pub(crate) requested_autoscroll: Option<Bounds<Pixels>>,
1140 pub(crate) image_cache_stack: SmallVec<[AnyImageCache; 4]>,
1141 pub(crate) rendered_frame: Frame,
1142 pub(crate) next_frame: Frame,
1143 next_hitbox_id: HitboxId,
1144 pub(crate) next_tooltip_id: TooltipId,
1145 pub(crate) tooltip_bounds: Option<TooltipBounds>,
1146 pub(crate) next_frame_callbacks: Rc<RefCell<Vec<FrameCallback>>>,
1147 pub(crate) dirty_views: FxHashSet<EntityId>,
1148 focus_listeners: SubscriberSet<(), AnyWindowFocusListener>,
1149 pub(crate) focus_lost_listeners: SubscriberSet<(), AnyObserver>,
1150 focus_lost_path: SmallVec<[FocusId; 8]>,
1151 default_prevented: bool,
1152 mouse_position: Point<Pixels>,
1153 mouse_hit_test: HitTest,
1154 modifiers: Modifiers,
1155 capslock: Capslock,
1156 scale_factor: f32,
1157 pub(crate) bounds_observers: SubscriberSet<(), AnyObserver>,
1158 appearance: WindowAppearance,
1159 pub(crate) appearance_observers: SubscriberSet<(), AnyObserver>,
1160 active: Rc<Cell<bool>>,
1161 visibility: WindowVisibility,
1162 pub(crate) visibility_observers:
1163 SubscriberSet<(), Box<dyn FnMut(WindowVisibility, &mut Window, &mut App) -> bool>>,
1164 hovered: Rc<Cell<bool>>,
1165 pub(crate) needs_present: Rc<Cell<bool>>,
1166 pub(crate) input_rate_tracker: Rc<RefCell<InputRateTracker>>,
1167 #[cfg(feature = "input-latency-histogram")]
1168 input_latency_tracker: InputLatencyTracker,
1169 pub(crate) last_input_was_keyboard: Cell<bool>,
1170 pub(crate) refreshing: bool,
1171 pub(crate) activation_observers: SubscriberSet<(), AnyObserver>,
1172 pub(crate) focus: Option<FocusId>,
1173 focus_enabled: bool,
1174 pending_input: Option<PendingInput>,
1175 pending_modifier: ModifierState,
1176 pub(crate) pending_input_observers: SubscriberSet<(), AnyObserver>,
1177 prompt: Option<RenderablePromptHandle>,
1178 pub(crate) client_inset: Option<Pixels>,
1179 captured_hitbox: Option<HitboxId>,
1182 #[cfg(any(feature = "inspector", debug_assertions))]
1183 inspector: Option<Entity<Inspector>>,
1184}
1185
1186#[derive(Clone, Debug, Default)]
1187struct ModifierState {
1188 modifiers: Modifiers,
1189 saw_other_input: bool,
1190}
1191
1192#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1193pub(crate) enum DrawPhase {
1194 None,
1195 Prepaint,
1196 Paint,
1197 Focus,
1198}
1199
1200pub(crate) const PENDING_INPUT_TIMEOUT: Duration = Duration::from_secs(1);
1201
1202pub struct PendingInputStatus<'a> {
1204 keystrokes: &'a [Keystroke],
1205 timeout: Option<PendingInputTimeoutStatus>,
1206}
1207
1208impl<'a> PendingInputStatus<'a> {
1209 pub fn keystrokes(&self) -> &'a [Keystroke] {
1211 self.keystrokes
1212 }
1213
1214 pub fn timeout(&self) -> Option<PendingInputTimeoutStatus> {
1216 self.timeout
1217 }
1218}
1219
1220#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1222pub struct PendingInputTimeoutStatus {
1223 duration: Duration,
1224 remaining: Duration,
1225 started_at: Option<Instant>,
1226 paused: bool,
1227}
1228
1229impl PendingInputTimeoutStatus {
1230 pub fn duration(&self) -> Duration {
1232 self.duration
1233 }
1234
1235 pub fn remaining(&self, cx: &App) -> Duration {
1237 self.started_at
1238 .map(|started_at| {
1239 self.remaining
1240 .saturating_sub(cx.background_executor().now() - started_at)
1241 })
1242 .unwrap_or(self.remaining)
1243 }
1244
1245 pub fn is_paused(&self) -> bool {
1247 self.paused
1248 }
1249}
1250
1251#[derive(Debug)]
1252struct PendingInputTimeout {
1253 duration: Duration,
1254 remaining: Duration,
1255 state: PendingInputTimeoutState,
1256}
1257
1258#[derive(Debug)]
1259enum PendingInputTimeoutState {
1260 Running { started_at: Instant, task: Task<()> },
1261 Paused { pause: PendingInputTimeoutPause },
1262}
1263
1264struct PendingInputTimeoutPause {
1265 owner_id: EntityId,
1266 _release_subscription: Subscription,
1267}
1268
1269impl std::fmt::Debug for PendingInputTimeoutPause {
1270 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1271 f.debug_struct("PendingInputTimeoutPause")
1272 .field("owner_id", &self.owner_id)
1273 .finish_non_exhaustive()
1274 }
1275}
1276
1277impl PendingInputTimeout {
1278 fn is_paused(&self) -> bool {
1279 matches!(&self.state, PendingInputTimeoutState::Paused { .. })
1280 }
1281
1282 fn pause(&mut self, pause: PendingInputTimeoutPause, now: Instant) -> bool {
1283 match mem::replace(&mut self.state, PendingInputTimeoutState::Paused { pause }) {
1284 PendingInputTimeoutState::Running { started_at, task } => {
1285 self.remaining = self.remaining.saturating_sub(now - started_at);
1286 drop(task);
1287 true
1288 }
1289 previous_state @ PendingInputTimeoutState::Paused { .. } => {
1290 self.state = previous_state;
1291 false
1292 }
1293 }
1294 }
1295
1296 fn pause_owner_id(&self) -> Option<EntityId> {
1297 match &self.state {
1298 PendingInputTimeoutState::Running { .. } => None,
1299 PendingInputTimeoutState::Paused { pause } => Some(pause.owner_id),
1300 }
1301 }
1302
1303 fn resume(&mut self, owner_id: EntityId, started_at: Instant, task: Task<()>) -> bool {
1304 match mem::replace(
1305 &mut self.state,
1306 PendingInputTimeoutState::Running { started_at, task },
1307 ) {
1308 PendingInputTimeoutState::Paused { pause } if pause.owner_id == owner_id => true,
1309 previous_state => {
1310 self.state = previous_state;
1311 false
1312 }
1313 }
1314 }
1315
1316 fn reset_duration(&mut self, duration: Duration) {
1317 self.duration = duration;
1318 self.remaining = duration;
1319 }
1320
1321 fn status(&self) -> PendingInputTimeoutStatus {
1322 let (started_at, paused) = match &self.state {
1323 PendingInputTimeoutState::Running { started_at, .. } => (Some(*started_at), false),
1324 PendingInputTimeoutState::Paused { .. } => (None, true),
1325 };
1326 PendingInputTimeoutStatus {
1327 duration: self.duration,
1328 remaining: self.remaining,
1329 started_at,
1330 paused,
1331 }
1332 }
1333}
1334
1335#[derive(Default, Debug)]
1336struct PendingInput {
1337 keystrokes: SmallVec<[Keystroke; 1]>,
1338 focus: Option<FocusId>,
1339 timeout: Option<PendingInputTimeout>,
1340}
1341
1342pub(crate) struct ElementStateBox {
1343 pub(crate) inner: Box<dyn Any>,
1344 #[cfg(debug_assertions)]
1345 pub(crate) type_name: &'static str,
1346}
1347
1348fn default_bounds(display_id: Option<DisplayId>, cx: &mut App) -> Bounds<Pixels> {
1349 const DEFAULT_WINDOW_OFFSET: Point<Pixels> = point(px(0.), px(35.));
1350
1351 cx.active_window()
1355 .and_then(|w| w.update(cx, |_, window, _| window.bounds()).ok())
1356 .map(|mut bounds| {
1357 bounds.origin += DEFAULT_WINDOW_OFFSET;
1358 bounds
1359 })
1360 .unwrap_or_else(|| {
1361 let display = display_id
1362 .map(|id| cx.find_display(id))
1363 .unwrap_or_else(|| cx.primary_display());
1364
1365 display
1366 .map(|display| display.default_bounds())
1367 .unwrap_or_else(|| Bounds::new(point(px(0.), px(0.)), DEFAULT_WINDOW_SIZE))
1368 })
1369}
1370
1371fn border_only_quad_strips(
1372 outer_bounds: Bounds<ScaledPixels>,
1373 widths: Edges<ScaledPixels>,
1374 radii: Corners<ScaledPixels>,
1375) -> Option<[Bounds<ScaledPixels>; 4]> {
1376 let antialias_slack = point(ScaledPixels(1.0), ScaledPixels(1.0));
1377 let top_left_inset = point(
1378 widths.left,
1379 widths.top.max(radii.top_left).max(radii.top_right),
1380 ) + antialias_slack;
1381 let bottom_right_inset = point(
1382 widths.right,
1383 widths.bottom.max(radii.bottom_left).max(radii.bottom_right),
1384 ) + antialias_slack;
1385 let inner_bounds = Bounds::from_corners(
1386 outer_bounds.origin + top_left_inset,
1387 outer_bounds.bottom_right() - bottom_right_inset,
1388 );
1389 if inner_bounds.is_empty() {
1390 return None;
1391 }
1392
1393 Some([
1394 Bounds::from_corners(
1395 outer_bounds.origin,
1396 point(outer_bounds.right(), inner_bounds.top()),
1397 ),
1398 Bounds::from_corners(
1399 point(outer_bounds.left(), inner_bounds.bottom()),
1400 outer_bounds.bottom_right(),
1401 ),
1402 Bounds::from_corners(
1403 point(outer_bounds.left(), inner_bounds.top()),
1404 inner_bounds.bottom_left(),
1405 ),
1406 Bounds::from_corners(
1407 inner_bounds.top_right(),
1408 point(outer_bounds.right(), inner_bounds.bottom()),
1409 ),
1410 ])
1411}
1412
1413impl Window {
1414 pub(crate) fn new(
1415 handle: AnyWindowHandle,
1416 options: WindowOptions,
1417 cx: &mut App,
1418 ) -> Result<Self> {
1419 let WindowOptions {
1420 window_bounds,
1421 titlebar,
1422 focus,
1423 show,
1424 kind,
1425 is_movable,
1426 app_owns_titlebar_drag,
1427 inactive_frame_interval,
1428 is_resizable,
1429 is_minimizable,
1430 display_id,
1431 window_background,
1432 app_id,
1433 window_min_size,
1434 window_decorations,
1435 #[cfg_attr(not(target_os = "macos"), allow(unused_variables))]
1436 tabbing_identifier,
1437 mouse_passthrough,
1438 icon,
1439 } = options;
1440
1441 let bounds = window_bounds
1442 .map(|bounds| bounds.get_bounds())
1443 .unwrap_or_else(|| default_bounds(display_id, cx));
1444 let mut platform_window = cx.platform.open_window(
1445 handle,
1446 WindowParams {
1447 bounds,
1448 titlebar,
1449 kind,
1450 is_movable,
1451 app_owns_titlebar_drag,
1452 is_resizable,
1453 is_minimizable,
1454 focus,
1455 app_id: app_id.clone(),
1456 show,
1457 display_id,
1458 window_min_size,
1459 #[cfg(target_os = "macos")]
1460 tabbing_identifier,
1461 mouse_passthrough,
1462 icon,
1463 },
1464 )?;
1465
1466 let tab_bar_visible = platform_window.tab_bar_visible();
1467 SystemWindowTabController::init_visible(cx, tab_bar_visible);
1468 if let Some(tabs) = platform_window.tabbed_windows() {
1469 SystemWindowTabController::add_tab(cx, handle.window_id(), tabs);
1470 }
1471
1472 let display_id = platform_window.display().map(|display| display.id());
1473 let sprite_atlas = platform_window.sprite_atlas();
1474 let mouse_position = platform_window.mouse_position();
1475 let modifiers = platform_window.modifiers();
1476 let capslock = platform_window.capslock();
1477 let content_size = platform_window.content_size();
1478 let scale_factor = platform_window.scale_factor();
1479 let appearance = platform_window.appearance();
1480 let text_system = Arc::new(WindowTextSystem::new(cx.text_system().clone()));
1481 let invalidator = WindowInvalidator::new();
1482 let active = Rc::new(Cell::new(platform_window.is_active()));
1483 let visibility = platform_window.visibility();
1484 let hovered = Rc::new(Cell::new(platform_window.is_hovered()));
1485 let needs_present = Rc::new(Cell::new(false));
1486 let next_frame_callbacks: Rc<RefCell<Vec<FrameCallback>>> = Default::default();
1487 let input_rate_tracker = Rc::new(RefCell::new(InputRateTracker::default()));
1488
1489 platform_window
1490 .request_decorations(window_decorations.unwrap_or(WindowDecorations::Server));
1491 platform_window.set_background_appearance(window_background);
1492
1493 if let Some(ref window_open_state) = window_bounds {
1494 match window_open_state {
1495 WindowBounds::Fullscreen(_) => platform_window.toggle_fullscreen(),
1496 WindowBounds::Maximized(_) => platform_window.zoom(),
1497 WindowBounds::Windowed(_) => {}
1498 }
1499 }
1500
1501 let accessibility_force_disabled =
1502 cx.accessibility_force_disabled || !cfg!(feature = "accessibility");
1503 let a11y_active_flag = Arc::new(AtomicBool::new(false));
1504
1505 #[cfg(not(target_family = "wasm"))]
1506 if !accessibility_force_disabled {
1507 let initial_tree = accesskit::TreeUpdate {
1508 nodes: vec![(ROOT_NODE_ID, accesskit::Node::new(accesskit::Role::Window))],
1509 tree: Some(accesskit::TreeInfo::new(ROOT_NODE_ID)),
1510 tree_id: accesskit::TreeId::ROOT,
1511 focus: ROOT_NODE_ID,
1512 };
1513 let (activation_sender, activation_receiver) = async_channel::unbounded::<()>();
1514 let (deactivation_sender, deactivation_receiver) = async_channel::unbounded::<()>();
1515 let (action_sender, action_receiver) =
1516 async_channel::unbounded::<accesskit::ActionRequest>();
1517
1518 platform_window.a11y_init(crate::A11yCallbacks {
1519 activation: {
1520 let active_flag = a11y_active_flag.clone();
1521 Box::new(move || {
1522 log::info!("Accessibility activated");
1523 active_flag.store(true, SeqCst);
1524 activation_sender.send_blocking(()).log_err();
1525 Some(initial_tree.clone())
1526 })
1527 },
1528 action: Box::new(move |request| {
1529 action_sender.send_blocking(request).log_err();
1530 }),
1531 deactivation: {
1532 let active_flag = a11y_active_flag.clone();
1533 Box::new(move || {
1534 log::info!("Accessibility deactivated");
1535 active_flag.store(false, SeqCst);
1536 deactivation_sender.send_blocking(()).log_err();
1537 })
1538 },
1539 });
1540
1541 let mut async_cx = cx.to_async();
1542 cx.foreground_executor()
1543 .spawn(async move {
1544 while activation_receiver.recv().await.is_ok() {
1545 handle
1546 .update(&mut async_cx, |_, window, _| window.refresh())
1547 .log_err();
1548 }
1549 })
1550 .detach();
1551
1552 let mut async_cx = cx.to_async();
1553 cx.foreground_executor()
1554 .spawn(async move {
1555 while deactivation_receiver.recv().await.is_ok() {
1556 handle
1557 .update(&mut async_cx, |_, window, _| window.refresh())
1558 .log_err();
1559 }
1560 })
1561 .detach();
1562
1563 let mut async_cx = cx.to_async();
1564 cx.foreground_executor()
1565 .spawn(async move {
1566 while let Ok(request) = action_receiver.recv().await {
1567 handle
1568 .update(&mut async_cx, |_, window, cx| {
1569 window.handle_a11y_action(request, cx);
1570 })
1571 .log_err();
1572 }
1573 })
1574 .detach();
1575 }
1576
1577 platform_window.on_close(Box::new({
1578 let window_id = handle.window_id();
1579 let cx = cx.to_async();
1580 move || {
1581 cx.spawn(async move |cx| {
1584 cx.update(|cx| {
1585 if cx.windows.contains_key(window_id) {
1587 handle
1588 .update(cx, |_, window, _| window.remove_window())
1589 .log_err();
1590 }
1591 SystemWindowTabController::remove_tab(cx, window_id);
1592 })
1593 .log_err();
1594 })
1595 .detach();
1596 }
1597 }));
1598 platform_window.on_request_frame(Box::new({
1599 let mut cx = cx.to_async();
1600 let invalidator = invalidator.clone();
1601 let active = active.clone();
1602 let needs_present = needs_present.clone();
1603 let next_frame_callbacks = next_frame_callbacks.clone();
1604 let input_rate_tracker = input_rate_tracker.clone();
1605 let mut deferred_force_render = false;
1606 let mut frame_pacer = FramePacer::default();
1607 move |request_frame_options| {
1608 if draw_in_progress() {
1624 log::debug!("deferring re-entrant window draw request");
1625 deferred_force_render |= request_frame_options.force_render;
1626 return;
1627 }
1628 let force_render =
1632 mem::take(&mut deferred_force_render) || request_frame_options.force_render;
1633
1634 let power_state = handle
1635 .update(&mut cx, |_, _, cx| (cx.thermal_state(), cx.power_mode()))
1636 .log_err();
1637
1638 let high_rate_input = input_rate_tracker.borrow().is_high_rate();
1641 let has_next_frame_callbacks = !next_frame_callbacks.borrow().is_empty();
1642 let has_frame_demand = invalidator.is_dirty()
1643 || force_render
1644 || has_next_frame_callbacks
1645 || request_frame_options.require_presentation
1646 || needs_present.get()
1647 || high_rate_input;
1648
1649 let should_throttle = !request_frame_options.require_presentation;
1656 let inactive_without_high_rate_input =
1657 should_throttle && !active.get() && !high_rate_input;
1658 let (thermal_state, power_mode) =
1659 power_state.unwrap_or((ThermalState::Nominal, crate::PowerMode::Unknown));
1660 let min_frame_interval = minimum_frame_interval(
1661 should_throttle,
1662 inactive_without_high_rate_input,
1663 inactive_frame_interval,
1664 thermal_state,
1665 power_mode,
1666 );
1667
1668 let now = Instant::now();
1669 if has_frame_demand && frame_pacer.should_defer(now, min_frame_interval) {
1672 deferred_force_render |= force_render;
1674 handle
1677 .update(&mut cx, |_, window, _| {
1678 window.platform_window.schedule_frame();
1679 })
1680 .log_err();
1681 return;
1682 }
1683
1684 let pending_next_frame_callbacks = next_frame_callbacks.take();
1685 if !pending_next_frame_callbacks.is_empty() {
1686 handle
1687 .update(&mut cx, |_, window, cx| {
1688 for callback in pending_next_frame_callbacks {
1689 callback(window, cx);
1690 }
1691 })
1692 .log_err();
1693 }
1694
1695 let needs_present = request_frame_options.require_presentation
1698 || needs_present.get()
1699 || high_rate_input;
1700
1701 if invalidator.is_dirty() || force_render {
1702 measure("frame duration", || {
1703 handle
1704 .update(&mut cx, |_, window, cx| {
1705 if force_render {
1706 window.refresh();
1707 }
1708 let arena_clear_needed = window.draw(cx);
1709 window.present();
1710 arena_clear_needed.clear();
1712 })
1713 .log_err();
1714 })
1715 } else if needs_present {
1716 handle
1717 .update(&mut cx, |_, window, _| window.present())
1718 .log_err();
1719 }
1720
1721 handle
1722 .update(&mut cx, |_, window, _| {
1723 if window.invalidator.is_dirty()
1724 || !window.next_frame_callbacks.borrow().is_empty()
1725 {
1726 window.platform_window.schedule_frame();
1727 }
1728 })
1729 .log_err();
1730 }
1731 }));
1732 platform_window.on_resize(Box::new({
1733 let mut cx = cx.to_async();
1734 let foreground_executor = cx.foreground_executor().clone();
1735 move |_, _| {
1736 if handle
1742 .update(&mut cx, |_, window, cx| window.bounds_changed(cx))
1743 .is_err()
1744 {
1745 let mut cx = cx.clone();
1746 foreground_executor
1747 .spawn(async move {
1748 handle
1749 .update(&mut cx, |_, window, cx| window.bounds_changed(cx))
1750 .log_err();
1751 })
1752 .detach();
1753 }
1754 }
1755 }));
1756 platform_window.on_moved(Box::new({
1757 let mut cx = cx.to_async();
1758 let foreground_executor = cx.foreground_executor().clone();
1759 move || {
1760 if handle
1763 .update(&mut cx, |_, window, cx| window.bounds_changed(cx))
1764 .is_err()
1765 {
1766 let mut cx = cx.clone();
1767 foreground_executor
1768 .spawn(async move {
1769 handle
1770 .update(&mut cx, |_, window, cx| window.bounds_changed(cx))
1771 .log_err();
1772 })
1773 .detach();
1774 }
1775 }
1776 }));
1777 platform_window.on_appearance_changed(Box::new({
1778 let cx = cx.to_async();
1779 let foreground_executor = cx.foreground_executor().clone();
1780 move || {
1781 let mut cx = cx.clone();
1782 foreground_executor
1785 .spawn(async move {
1786 handle
1787 .update(&mut cx, |_, window, cx| window.appearance_changed(cx))
1788 .log_err();
1789 })
1790 .detach();
1791 }
1792 }));
1793 platform_window.on_active_status_change(Box::new({
1794 let mut cx = cx.to_async();
1795 move |active| {
1796 handle
1797 .update(&mut cx, |_, window, cx| {
1798 if !active {
1799 window.platform_window.set_cursor_style(CursorStyle::Arrow);
1802 cx.platform.set_cursor_style(CursorStyle::Arrow);
1803 }
1804
1805 window.active.set(active);
1806 window.modifiers = window.platform_window.modifiers();
1807 window.capslock = window.platform_window.capslock();
1808 window
1809 .activation_observers
1810 .clone()
1811 .retain(&(), |callback| callback(window, cx));
1812
1813 window.bounds_changed(cx);
1814 window.refresh();
1815
1816 SystemWindowTabController::update_last_active(cx, window.handle.id);
1817 })
1818 .log_err();
1819 }
1820 }));
1821 platform_window.on_visibility_change(Box::new({
1822 let mut cx = cx.to_async();
1823 move |visibility| {
1824 handle
1825 .update(&mut cx, |_, window, cx| {
1826 if window.visibility == visibility {
1827 return;
1828 }
1829 window.visibility = visibility;
1830 window
1831 .visibility_observers
1832 .clone()
1833 .retain(&(), |callback| callback(visibility, window, cx));
1834 })
1835 .log_err();
1836 }
1837 }));
1838 platform_window.on_hover_status_change(Box::new({
1839 let mut cx = cx.to_async();
1840 move |active| {
1841 handle
1842 .update(&mut cx, |_, window, _| {
1843 window.hovered.set(active);
1844 window.refresh();
1845 })
1846 .log_err();
1847 }
1848 }));
1849 platform_window.on_input({
1850 let mut cx = cx.to_async();
1851 Box::new(move |event| {
1852 handle
1853 .update(&mut cx, |_, window, cx| window.dispatch_event(event, cx))
1854 .log_err()
1855 .unwrap_or(DispatchEventResult::default())
1856 })
1857 });
1858 platform_window.on_hit_test_window_control({
1859 let mut cx = cx.to_async();
1860 Box::new(move || {
1861 handle
1862 .update(&mut cx, |_, window, _cx| {
1863 for (area, hitbox) in &window.rendered_frame.window_control_hitboxes {
1864 if window.mouse_hit_test.ids.contains(&hitbox.id) {
1865 return Some(*area);
1866 }
1867 }
1868 None
1869 })
1870 .log_err()
1871 .unwrap_or(None)
1872 })
1873 });
1874 platform_window.on_move_tab_to_new_window({
1875 let mut cx = cx.to_async();
1876 Box::new(move || {
1877 handle
1878 .update(&mut cx, |_, _window, cx| {
1879 SystemWindowTabController::move_tab_to_new_window(cx, handle.window_id());
1880 })
1881 .log_err();
1882 })
1883 });
1884 platform_window.on_merge_all_windows({
1885 let mut cx = cx.to_async();
1886 Box::new(move || {
1887 handle
1888 .update(&mut cx, |_, _window, cx| {
1889 SystemWindowTabController::merge_all_windows(cx, handle.window_id());
1890 })
1891 .log_err();
1892 })
1893 });
1894 platform_window.on_select_next_tab({
1895 let mut cx = cx.to_async();
1896 Box::new(move || {
1897 handle
1898 .update(&mut cx, |_, _window, cx| {
1899 SystemWindowTabController::select_next_tab(cx, handle.window_id());
1900 })
1901 .log_err();
1902 })
1903 });
1904 platform_window.on_select_previous_tab({
1905 let mut cx = cx.to_async();
1906 Box::new(move || {
1907 handle
1908 .update(&mut cx, |_, _window, cx| {
1909 SystemWindowTabController::select_previous_tab(cx, handle.window_id())
1910 })
1911 .log_err();
1912 })
1913 });
1914 platform_window.on_toggle_tab_bar({
1915 let mut cx = cx.to_async();
1916 Box::new(move || {
1917 handle
1918 .update(&mut cx, |_, window, cx| {
1919 let tab_bar_visible = window.platform_window.tab_bar_visible();
1920 SystemWindowTabController::set_visible(cx, tab_bar_visible);
1921 })
1922 .log_err();
1923 })
1924 });
1925
1926 if let Some(app_id) = app_id {
1927 platform_window.set_app_id(&app_id);
1928 }
1929
1930 if show {
1935 platform_window.map_window()?;
1936 }
1937
1938 Ok(Window {
1939 handle,
1940 invalidator,
1941 removed: false,
1942 platform_window,
1943 a11y: A11y::new(a11y_active_flag, accessibility_force_disabled),
1944 display_id,
1945 sprite_atlas,
1946 text_system,
1947 rem_size: px(16.),
1948 rem_size_override_stack: SmallVec::new(),
1949 viewport_size: content_size,
1950 layout_engine: Some(TaffyLayoutEngine::new()),
1951 root: None,
1952 element_id_stack: SmallVec::default(),
1953 text_style_stack: SmallVec::new(),
1954 rendered_entity_stack: SmallVec::new(),
1955 element_offset_stack: SmallVec::new(),
1956 content_mask_stack: SmallVec::new(),
1957 element_opacity: 1.0,
1958 requested_autoscroll: None,
1959 rendered_frame: Frame::new(DispatchTree::new(cx.keymap.clone(), cx.actions.clone())),
1960 next_frame: Frame::new(DispatchTree::new(cx.keymap.clone(), cx.actions.clone())),
1961 next_frame_callbacks,
1962 next_hitbox_id: HitboxId(0),
1963 next_tooltip_id: TooltipId::default(),
1964 tooltip_bounds: None,
1965 dirty_views: FxHashSet::default(),
1966 focus_listeners: SubscriberSet::new(),
1967 focus_lost_listeners: SubscriberSet::new(),
1968 focus_lost_path: SmallVec::new(),
1969 default_prevented: true,
1970 mouse_position,
1971 mouse_hit_test: HitTest::default(),
1972 modifiers,
1973 capslock,
1974 scale_factor,
1975 bounds_observers: SubscriberSet::new(),
1976 appearance,
1977 appearance_observers: SubscriberSet::new(),
1978 active,
1979 visibility,
1980 visibility_observers: SubscriberSet::new(),
1981 hovered,
1982 needs_present,
1983 input_rate_tracker,
1984 #[cfg(feature = "input-latency-histogram")]
1985 input_latency_tracker: InputLatencyTracker::new()?,
1986 last_input_was_keyboard: Cell::new(false),
1987 refreshing: false,
1988 activation_observers: SubscriberSet::new(),
1989 focus: None,
1990 focus_enabled: true,
1991 pending_input: None,
1992 pending_modifier: ModifierState::default(),
1993 pending_input_observers: SubscriberSet::new(),
1994 prompt: None,
1995 client_inset: None,
1996 image_cache_stack: SmallVec::new(),
1997 captured_hitbox: None,
1998 #[cfg(any(feature = "inspector", debug_assertions))]
1999 inspector: None,
2000 })
2001 }
2002
2003 pub(crate) fn new_focus_listener(
2004 &self,
2005 value: AnyWindowFocusListener,
2006 ) -> (Subscription, impl FnOnce() + use<>) {
2007 self.focus_listeners.insert((), value)
2008 }
2009}
2010
2011#[derive(Clone, Debug, Default, PartialEq, Eq)]
2012#[allow(missing_docs)]
2013pub struct DispatchEventResult {
2014 pub propagate: bool,
2015 pub default_prevented: bool,
2016}
2017
2018#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
2022#[repr(C)]
2023pub struct ContentMask<P: Clone + Debug + Default + PartialEq> {
2024 pub bounds: Bounds<P>,
2026}
2027
2028impl ContentMask<Pixels> {
2029 pub fn scale(&self, factor: f32) -> ContentMask<ScaledPixels> {
2031 ContentMask {
2032 bounds: self.bounds.scale(factor),
2033 }
2034 }
2035
2036 pub fn intersect(&self, other: &Self) -> Self {
2038 let bounds = self.bounds.intersect(&other.bounds);
2039 ContentMask { bounds }
2040 }
2041}
2042
2043impl Window {
2044 fn mark_view_dirty(&mut self, view_id: EntityId) {
2045 for view_id in self
2048 .rendered_frame
2049 .dispatch_tree
2050 .view_path(view_id)
2051 .into_iter()
2052 .rev()
2053 {
2054 if !self.dirty_views.insert(view_id) {
2055 break;
2056 }
2057 }
2058 }
2059
2060 pub fn visibility(&self) -> WindowVisibility {
2063 self.visibility
2064 }
2065
2066 pub fn is_visible(&self) -> bool {
2073 self.visibility.is_visible()
2074 }
2075
2076 pub fn observe_window_visibility(
2078 &self,
2079 mut callback: impl FnMut(WindowVisibility, &mut Window, &mut App) + 'static,
2080 ) -> Subscription {
2081 let (subscription, activate) = self.visibility_observers.insert(
2082 (),
2083 Box::new(move |visibility, window, cx| {
2084 callback(visibility, window, cx);
2085 true
2086 }),
2087 );
2088 activate();
2089 subscription
2090 }
2091
2092 pub fn observe_window_appearance(
2094 &self,
2095 mut callback: impl FnMut(&mut Window, &mut App) + 'static,
2096 ) -> Subscription {
2097 let (subscription, activate) = self.appearance_observers.insert(
2098 (),
2099 Box::new(move |window, cx| {
2100 callback(window, cx);
2101 true
2102 }),
2103 );
2104 activate();
2105 subscription
2106 }
2107
2108 pub fn replace_root<E>(
2110 &mut self,
2111 cx: &mut App,
2112 build_view: impl FnOnce(&mut Window, &mut Context<E>) -> E,
2113 ) -> Entity<E>
2114 where
2115 E: 'static + Render,
2116 {
2117 let view = cx.new(|cx| build_view(self, cx));
2118 self.root = Some(view.clone().into());
2119 self.refresh();
2120 view
2121 }
2122
2123 pub fn root<E>(&self) -> Option<Option<Entity<E>>>
2125 where
2126 E: 'static + Render,
2127 {
2128 self.root
2129 .as_ref()
2130 .map(|view| view.clone().downcast::<E>().ok())
2131 }
2132
2133 pub fn window_handle(&self) -> AnyWindowHandle {
2135 self.handle
2136 }
2137
2138 pub fn refresh(&mut self) {
2140 if self.invalidator.not_drawing() {
2141 self.refreshing = true;
2142 self.invalidator.set_dirty(true);
2143 }
2144 }
2145
2146 pub fn remove_window(&mut self) {
2148 self.removed = true;
2149 }
2150
2151 pub fn focused(&self, cx: &App) -> Option<FocusHandle> {
2153 self.focus
2154 .and_then(|id| FocusHandle::for_id(id, &cx.focus_handles))
2155 }
2156
2157 pub fn focus_lost_restore_target(&self, cx: &App) -> Option<FocusHandle> {
2161 let (_leaf, ancestors) = self.focus_lost_path.split_last()?;
2162 ancestors.iter().rev().find_map(|id| {
2163 self.rendered_frame.dispatch_tree.focusable_node_id(*id)?;
2164 FocusHandle::for_id(*id, &cx.focus_handles)
2165 })
2166 }
2167
2168 pub fn focus(&mut self, handle: &FocusHandle) {
2170 if !self.focus_enabled || self.focus == Some(handle.id) {
2171 return;
2172 }
2173
2174 self.focus = Some(handle.id);
2175 self.pending_input.take();
2176 self.refresh();
2177 }
2178
2179 pub fn blur(&mut self, cx: &mut App) {
2181 self.clear_pending_keystrokes(cx);
2182
2183 if !self.focus_enabled {
2184 return;
2185 }
2186
2187 self.focus = None;
2188 self.refresh();
2189 }
2190
2191 pub fn disable_focus(&mut self, cx: &mut App) {
2193 self.blur(cx);
2194 self.focus_enabled = false;
2195 }
2196
2197 pub fn focus_next(&mut self) {
2199 if !self.focus_enabled {
2200 return;
2201 }
2202
2203 if let Some(handle) = self.rendered_frame.tab_stops.next(self.focus.as_ref()) {
2204 self.focus(&handle)
2205 }
2206 }
2207
2208 pub fn focus_prev(&mut self) {
2210 if !self.focus_enabled {
2211 return;
2212 }
2213
2214 if let Some(handle) = self.rendered_frame.tab_stops.prev(self.focus.as_ref()) {
2215 self.focus(&handle)
2216 }
2217 }
2218
2219 pub fn text_system(&self) -> &Arc<WindowTextSystem> {
2221 &self.text_system
2222 }
2223
2224 pub fn text_style(&self) -> TextStyle {
2226 let mut style = TextStyle::default();
2227 for refinement in &self.text_style_stack {
2228 style.refine(refinement);
2229 }
2230 style
2231 }
2232
2233 pub fn is_maximized(&self) -> bool {
2236 self.platform_window.is_maximized()
2237 }
2238
2239 pub fn request_decorations(&self, decorations: WindowDecorations) {
2241 self.platform_window.request_decorations(decorations);
2242 }
2243
2244 pub fn set_exclusive_zone(&self, zone: Pixels) {
2246 self.platform_window.set_exclusive_zone(zone);
2247 }
2248
2249 #[cfg(all(any(target_os = "linux", target_os = "freebsd"), feature = "wayland"))]
2252 pub fn set_exclusive_edge(&self, edge: crate::layer_shell::Anchor) {
2253 self.platform_window.set_exclusive_edge(edge);
2254 }
2255
2256 pub fn start_window_resize(&self, edge: ResizeEdge) {
2258 self.platform_window.start_window_resize(edge);
2259 }
2260
2261 pub fn window_bounds(&self) -> WindowBounds {
2264 self.platform_window.window_bounds()
2265 }
2266
2267 pub fn inner_window_bounds(&self) -> WindowBounds {
2269 self.platform_window.inner_window_bounds()
2270 }
2271
2272 pub fn native_window_state(&self) -> Option<Vec<u8>> {
2275 self.platform_window.native_window_state()
2276 }
2277
2278 pub fn restore_native_window_state(&self, state: &[u8]) {
2281 self.platform_window.restore_native_window_state(state);
2282 }
2283
2284 pub fn dispatch_action(&mut self, action: Box<dyn Action>, cx: &mut App) {
2286 let focus_id = self.focused(cx).map(|handle| handle.id);
2287
2288 let window = self.handle;
2289 cx.defer(move |cx| {
2290 window
2291 .update(cx, |_, window, cx| {
2292 let node_id = window.focus_node_id_in_rendered_frame(focus_id);
2293 window.dispatch_action_on_node(node_id, action.as_ref(), cx);
2294 })
2295 .log_err();
2296 })
2297 }
2298
2299 pub(crate) fn dispatch_keystroke_observers(
2300 &mut self,
2301 keystroke: &Keystroke,
2302 input_preference: InputPreference,
2303 action: Option<&dyn Action>,
2304 context_stack: Vec<KeyContext>,
2305 cx: &mut App,
2306 ) {
2307 cx.keystroke_observers.clone().retain(&(), move |callback| {
2308 (callback)(
2309 &KeystrokeEvent {
2310 keystroke: keystroke.clone(),
2311 input_preference,
2312 action: action.map(|action| action.boxed_clone()),
2313 context_stack: context_stack.clone(),
2314 },
2315 self,
2316 cx,
2317 )
2318 });
2319 }
2320
2321 pub(crate) fn dispatch_keystroke_interceptors(
2322 &mut self,
2323 keystroke: &Keystroke,
2324 input_preference: InputPreference,
2325 context_stack: Vec<KeyContext>,
2326 cx: &mut App,
2327 ) {
2328 cx.keystroke_interceptors
2329 .clone()
2330 .retain(&(), move |callback| {
2331 (callback)(
2332 &KeystrokeEvent {
2333 keystroke: keystroke.clone(),
2334 input_preference,
2335 action: None,
2336 context_stack: context_stack.clone(),
2337 },
2338 self,
2339 cx,
2340 )
2341 });
2342 }
2343
2344 pub fn defer(&self, cx: &mut App, f: impl FnOnce(&mut Window, &mut App) + 'static) {
2347 let handle = self.handle;
2348 cx.defer(move |cx| {
2349 handle.update(cx, |_, window, cx| f(window, cx)).ok();
2350 });
2351 }
2352
2353 pub fn observe<T: 'static>(
2357 &mut self,
2358 observed: &Entity<T>,
2359 cx: &mut App,
2360 mut on_notify: impl FnMut(Entity<T>, &mut Window, &mut App) + 'static,
2361 ) -> Subscription {
2362 let entity_id = observed.entity_id();
2363 let observed = observed.downgrade();
2364 let window_handle = self.handle;
2365 cx.new_observer(
2366 entity_id,
2367 Box::new(move |cx| {
2368 window_handle
2369 .update(cx, |_, window, cx| {
2370 if let Some(handle) = observed.upgrade() {
2371 on_notify(handle, window, cx);
2372 true
2373 } else {
2374 false
2375 }
2376 })
2377 .unwrap_or(false)
2378 }),
2379 )
2380 }
2381
2382 pub fn subscribe<Emitter, Evt>(
2386 &mut self,
2387 entity: &Entity<Emitter>,
2388 cx: &mut App,
2389 mut on_event: impl FnMut(Entity<Emitter>, &Evt, &mut Window, &mut App) + 'static,
2390 ) -> Subscription
2391 where
2392 Emitter: EventEmitter<Evt>,
2393 Evt: 'static,
2394 {
2395 let entity_id = entity.entity_id();
2396 let handle = entity.downgrade();
2397 let window_handle = self.handle;
2398 cx.new_subscription(
2399 entity_id,
2400 (
2401 TypeId::of::<Evt>(),
2402 Box::new(move |event, cx| {
2403 window_handle
2404 .update(cx, |_, window, cx| {
2405 if let Some(entity) = handle.upgrade() {
2406 let event = event.downcast_ref().expect("invalid event type");
2407 on_event(entity, event, window, cx);
2408 true
2409 } else {
2410 false
2411 }
2412 })
2413 .unwrap_or(false)
2414 }),
2415 ),
2416 )
2417 }
2418
2419 pub fn observe_release<T>(
2421 &self,
2422 entity: &Entity<T>,
2423 cx: &mut App,
2424 mut on_release: impl FnOnce(&mut T, &mut Window, &mut App) + 'static,
2425 ) -> Subscription
2426 where
2427 T: 'static,
2428 {
2429 let entity_id = entity.entity_id();
2430 let window_handle = self.handle;
2431 let (subscription, activate) = cx.release_listeners.insert(
2432 entity_id,
2433 Box::new(move |entity, cx| {
2434 let entity = entity.downcast_mut().expect("invalid entity type");
2435 let _ = window_handle.update(cx, |_, window, cx| on_release(entity, window, cx));
2436 }),
2437 );
2438 activate();
2439 subscription
2440 }
2441
2442 pub fn to_async(&self, cx: &App) -> AsyncWindowContext {
2445 AsyncWindowContext::new_context(cx.to_async(), self.handle)
2446 }
2447
2448 pub fn on_next_frame(&self, callback: impl FnOnce(&mut Window, &mut App) + 'static) {
2450 RefCell::borrow_mut(&self.next_frame_callbacks).push(Box::new(callback));
2451 self.platform_window.schedule_frame();
2452 }
2453
2454 pub fn request_animation_frame(&self) {
2461 let entity = self.current_view();
2462 self.on_next_frame(move |_, cx| cx.notify(entity));
2463 }
2464
2465 #[track_caller]
2469 pub fn spawn<AsyncFn, R>(&self, cx: &App, f: AsyncFn) -> Task<R>
2470 where
2471 R: 'static,
2472 AsyncFn: AsyncFnOnce(&mut AsyncWindowContext) -> R + 'static,
2473 {
2474 let handle = self.handle;
2475 cx.spawn(async move |app| {
2476 let mut async_window_cx = AsyncWindowContext::new_context(app.clone(), handle);
2477 f(&mut async_window_cx).await
2478 })
2479 }
2480
2481 fn bounds_changed(&mut self, cx: &mut App) {
2482 self.scale_factor = self.platform_window.scale_factor();
2483 self.viewport_size = self.platform_window.content_size();
2484 self.display_id = self.platform_window.display().map(|display| display.id());
2485 self.mouse_position = self.platform_window.mouse_position();
2486 self.platform_window.a11y_update_window_bounds();
2487
2488 self.refresh();
2489
2490 self.bounds_observers
2491 .clone()
2492 .retain(&(), |callback| callback(self, cx));
2493 }
2494
2495 pub fn bounds(&self) -> Bounds<Pixels> {
2497 self.platform_window.bounds()
2498 }
2499
2500 pub fn resize(&mut self, size: Size<Pixels>) {
2502 self.platform_window.resize(size);
2503 }
2504
2505 pub fn resize_anchored(&mut self, size: Size<Pixels>, anchor: ResizeAnchor) {
2512 self.platform_window.resize_anchored(size, anchor);
2513 }
2514
2515 pub fn is_fullscreen(&self) -> bool {
2517 self.platform_window.is_fullscreen()
2518 }
2519
2520 pub fn is_simple_fullscreen(&self) -> bool {
2524 self.platform_window.is_simple_fullscreen()
2525 }
2526
2527 pub(crate) fn appearance_changed(&mut self, cx: &mut App) {
2528 self.appearance = self.platform_window.appearance();
2529
2530 self.appearance_observers
2531 .clone()
2532 .retain(&(), |callback| callback(self, cx));
2533 }
2534
2535 pub fn appearance(&self) -> WindowAppearance {
2537 self.appearance
2538 }
2539
2540 pub fn viewport_size(&self) -> Size<Pixels> {
2542 self.viewport_size
2543 }
2544
2545 pub fn is_window_active(&self) -> bool {
2547 self.active.get()
2548 }
2549
2550 pub fn is_window_hovered(&self) -> bool {
2554 if cfg!(any(
2555 target_os = "windows",
2556 target_os = "linux",
2557 target_os = "freebsd"
2558 )) {
2559 self.hovered.get()
2560 } else {
2561 self.is_window_active()
2562 }
2563 }
2564
2565 pub fn last_input_was_keyboard(&self) -> bool {
2568 self.last_input_was_keyboard.get()
2569 }
2570
2571 pub fn zoom_window(&self) {
2573 self.platform_window.zoom();
2574 }
2575
2576 pub fn show_window_menu(&self, position: Point<Pixels>) {
2578 self.platform_window.show_window_menu(position)
2579 }
2580
2581 pub fn start_window_move(&self) {
2585 self.platform_window.start_window_move()
2586 }
2587
2588 pub fn set_client_inset(&mut self, inset: Pixels) {
2590 self.client_inset = Some(inset);
2591 self.platform_window.set_client_inset(inset);
2592 }
2593
2594 pub fn set_client_corner_radii(&mut self, radii: Corners<Pixels>) {
2596 self.platform_window.set_client_corner_radii(radii);
2597 }
2598
2599 pub fn client_inset(&self) -> Option<Pixels> {
2601 self.client_inset
2602 }
2603
2604 pub fn window_decorations(&self) -> Decorations {
2606 self.platform_window.window_decorations()
2607 }
2608
2609 pub fn window_controls(&self) -> WindowControls {
2611 self.platform_window.window_controls()
2612 }
2613
2614 pub fn set_window_title(&mut self, title: &str) {
2616 self.platform_window.set_title(title);
2617 }
2618
2619 pub fn set_app_id(&mut self, app_id: &str) {
2621 self.platform_window.set_app_id(app_id);
2622 }
2623
2624 pub fn set_background_appearance(&self, background_appearance: WindowBackgroundAppearance) {
2626 self.platform_window
2627 .set_background_appearance(background_appearance);
2628 }
2629
2630 pub fn set_window_edited(&mut self, edited: bool) {
2632 self.platform_window.set_edited(edited);
2633 }
2634
2635 pub fn display(&self, cx: &App) -> Option<Rc<dyn PlatformDisplay>> {
2637 cx.platform
2638 .displays()
2639 .into_iter()
2640 .find(|display| Some(display.id()) == self.display_id)
2641 }
2642
2643 pub fn show_character_palette(&self) {
2645 self.platform_window.show_character_palette();
2646 }
2647
2648 pub fn scale_factor(&self) -> f32 {
2652 self.scale_factor
2653 }
2654
2655 pub fn rem_size(&self) -> Pixels {
2658 self.rem_size_override_stack
2659 .last()
2660 .copied()
2661 .unwrap_or(self.rem_size)
2662 }
2663
2664 pub fn set_rem_size(&mut self, rem_size: impl Into<Pixels>) {
2667 self.rem_size = rem_size.into();
2668 }
2669
2670 pub fn with_global_id<R>(
2673 &mut self,
2674 element_id: ElementId,
2675 f: impl FnOnce(&GlobalElementId, &mut Self) -> R,
2676 ) -> R {
2677 self.element_id_stack.push(element_id);
2678 let global_id = GlobalElementId(self.element_id_stack.clone());
2679 let result = f(&global_id, self);
2680 self.element_id_stack.pop();
2681 result
2682 }
2683
2684 pub fn with_rem_size<F, R>(&mut self, rem_size: Option<impl Into<Pixels>>, f: F) -> R
2688 where
2689 F: FnOnce(&mut Self) -> R,
2690 {
2691 self.invalidator.debug_assert_paint_or_prepaint();
2692
2693 if let Some(rem_size) = rem_size {
2694 self.rem_size_override_stack.push(rem_size.into());
2695 let result = f(self);
2696 self.rem_size_override_stack.pop();
2697 result
2698 } else {
2699 f(self)
2700 }
2701 }
2702
2703 pub fn line_height(&self) -> Pixels {
2705 self.text_style().line_height_in_pixels(self.rem_size())
2706 }
2707
2708 #[inline]
2710 pub fn pixel_snap(&self, value: Pixels) -> Pixels {
2711 px(round_to_device_pixel(value.0, self.scale_factor()) / self.scale_factor())
2712 }
2713
2714 #[inline]
2716 pub fn pixel_snap_f64(&self, value: f64) -> f64 {
2717 let scale_factor = f64::from(self.scale_factor());
2718 round_half_toward_zero_f64(value * scale_factor) / scale_factor
2719 }
2720
2721 #[inline]
2723 pub fn pixel_snap_bounds(&self, bounds: Bounds<Pixels>) -> Bounds<Pixels> {
2724 bounds.map(|c| self.pixel_snap(c))
2725 }
2726
2727 #[inline]
2729 pub fn pixel_snap_point(&self, position: Point<Pixels>) -> Point<Pixels> {
2730 position.map(|c| self.pixel_snap(c))
2731 }
2732
2733 #[inline]
2734 fn snap_bounds(&self, bounds: Bounds<Pixels>) -> Bounds<ScaledPixels> {
2735 let scale_factor = self.scale_factor();
2736 let left = round_to_device_pixel(bounds.left().0, scale_factor);
2737 let top = round_to_device_pixel(bounds.top().0, scale_factor);
2738 let right = round_to_device_pixel(bounds.right().0, scale_factor).max(left);
2739 let bottom = round_to_device_pixel(bounds.bottom().0, scale_factor).max(top);
2740 Bounds::from_corners(
2741 point(ScaledPixels(left), ScaledPixels(top)),
2742 point(ScaledPixels(right), ScaledPixels(bottom)),
2743 )
2744 }
2745
2746 #[inline]
2747 fn snap_stroke(&self, value: Pixels) -> ScaledPixels {
2748 ScaledPixels(round_stroke_to_device_pixel(value.0, self.scale_factor()))
2749 }
2750
2751 #[inline]
2752 fn snap_border_widths(&self, edges: Edges<Pixels>) -> Edges<ScaledPixels> {
2753 edges.map(|e| self.snap_stroke(*e))
2754 }
2755
2756 #[inline]
2757 fn cover_bounds(&self, bounds: Bounds<Pixels>) -> Bounds<ScaledPixels> {
2758 let scale_factor = self.scale_factor();
2759 let left = floor_to_device_pixel(bounds.left().0, scale_factor);
2760 let top = floor_to_device_pixel(bounds.top().0, scale_factor);
2761 let right = ceil_to_device_pixel(bounds.right().0, scale_factor).max(left);
2762 let bottom = ceil_to_device_pixel(bounds.bottom().0, scale_factor).max(top);
2763 Bounds::from_corners(
2764 point(ScaledPixels(left), ScaledPixels(top)),
2765 point(ScaledPixels(right), ScaledPixels(bottom)),
2766 )
2767 }
2768
2769 #[inline]
2770 fn snapped_content_mask(&self) -> ContentMask<ScaledPixels> {
2771 ContentMask {
2772 bounds: self.cover_bounds(self.content_mask().bounds),
2773 }
2774 }
2775
2776 pub fn prevent_default(&mut self) {
2779 self.default_prevented = true;
2780 }
2781
2782 pub fn default_prevented(&self) -> bool {
2784 self.default_prevented
2785 }
2786
2787 pub fn is_action_available(&self, action: &dyn Action, cx: &mut App) -> bool {
2789 let node_id =
2790 self.focus_node_id_in_rendered_frame(self.focused(cx).map(|handle| handle.id));
2791 self.rendered_frame
2792 .dispatch_tree
2793 .is_action_available(action, node_id)
2794 }
2795
2796 pub fn mouse_position(&self) -> Point<Pixels> {
2798 self.mouse_position
2799 }
2800
2801 pub fn capture_pointer(&mut self, hitbox_id: HitboxId) {
2808 self.captured_hitbox = Some(hitbox_id);
2809 }
2810
2811 pub fn release_pointer(&mut self) {
2813 self.captured_hitbox = None;
2814 }
2815
2816 pub fn captured_hitbox(&self) -> Option<HitboxId> {
2818 self.captured_hitbox
2819 }
2820
2821 pub fn modifiers(&self) -> Modifiers {
2823 self.modifiers
2824 }
2825
2826 pub fn capslock(&self) -> Capslock {
2828 self.capslock
2829 }
2830
2831 #[profiling::function]
2834 pub fn draw(&mut self, cx: &mut App) -> ArenaClearNeeded {
2835 let arena_scope = ElementArenaScope::enter();
2836 self.invalidate_entities();
2837 cx.entities.clear_accessed();
2838 debug_assert!(self.rendered_entity_stack.is_empty());
2839 self.invalidator.set_dirty(false);
2840 self.requested_autoscroll = None;
2841
2842 if let Some(input_handler) = self.platform_window.take_input_handler() {
2844 if let Some(slot) = self
2845 .rendered_frame
2846 .input_handlers
2847 .iter_mut()
2848 .rev()
2849 .find(|handler| handler.is_none())
2850 {
2851 *slot = Some(input_handler);
2852 } else {
2853 self.rendered_frame.input_handlers.push(Some(input_handler));
2854 }
2855 }
2856 self.draw_roots(cx);
2857 self.dirty_views.clear();
2858 self.next_frame.window_active = self.active.get();
2859
2860 if let Some(input_handler) = self
2862 .next_frame
2863 .input_handlers
2864 .iter_mut()
2865 .rev()
2866 .find_map(|handler| handler.take())
2867 {
2868 self.platform_window.set_input_handler(input_handler);
2869 }
2870
2871 self.layout_engine.as_mut().unwrap().clear();
2872 self.text_system().finish_frame();
2873 self.next_frame.finish(&mut self.rendered_frame);
2874
2875 self.invalidator.set_phase(DrawPhase::Focus);
2876 let previous_focus_path = self.rendered_frame.focus_path();
2877 let previous_window_active = self.rendered_frame.window_active;
2878 mem::swap(&mut self.rendered_frame, &mut self.next_frame);
2879 self.next_frame.clear();
2880 let current_focus_path = self.rendered_frame.focus_path();
2881 let current_window_active = self.rendered_frame.window_active;
2882
2883 if previous_focus_path != current_focus_path
2884 || previous_window_active != current_window_active
2885 {
2886 if !previous_focus_path.is_empty() && current_focus_path.is_empty() {
2887 self.focus_lost_path = previous_focus_path.clone();
2888 self.focus_lost_listeners
2889 .clone()
2890 .retain(&(), |listener| listener(self, cx));
2891 self.focus_lost_path = SmallVec::new();
2892 }
2893
2894 let event = WindowFocusEvent {
2895 previous_focus_path: if previous_window_active {
2896 previous_focus_path
2897 } else {
2898 Default::default()
2899 },
2900 current_focus_path: if current_window_active {
2901 current_focus_path
2902 } else {
2903 Default::default()
2904 },
2905 };
2906 self.focus_listeners
2907 .clone()
2908 .retain(&(), |listener| listener(&event, self, cx));
2909 }
2910
2911 debug_assert!(self.rendered_entity_stack.is_empty());
2912 self.record_entities_accessed(cx);
2913 self.reset_cursor_style(cx);
2914 self.refreshing = false;
2915 self.invalidator.set_phase(DrawPhase::None);
2916 self.needs_present.set(true);
2917
2918 drop(arena_scope);
2919 ArenaClearNeeded
2920 }
2921
2922 #[cfg(any(test, feature = "test-support"))]
2924 pub fn visual_render_artifact(&self) -> crate::VisualRenderArtifact {
2925 crate::VisualRenderArtifact::from_scene(&self.rendered_frame.scene)
2926 }
2927
2928 #[cfg(any(test, feature = "test-support"))]
2930 pub fn present_for_visual_test(&mut self) {
2931 self.present();
2932 }
2933
2934 #[cfg(any(test, feature = "test-support"))]
2936 pub fn render_to_image(&self) -> anyhow::Result<image::RgbaImage> {
2937 self.platform_window
2938 .render_to_image(&self.rendered_frame.scene)
2939 }
2940
2941 #[cfg(any(test, feature = "test-support"))]
2946 pub fn painted_quads(&self) -> Vec<Quad> {
2947 self.rendered_frame.scene.quads.clone()
2948 }
2949
2950 fn record_entities_accessed(&mut self, cx: &mut App) {
2951 let mut entities_ref = cx.entities.accessed_entities.borrow_mut();
2952 let mut entities = mem::take(entities_ref.deref_mut());
2953 drop(entities_ref);
2954 let handle = self.handle;
2955 cx.record_entities_accessed(
2956 handle,
2957 self.invalidator.clone(),
2959 &entities,
2960 );
2961 let mut entities_ref = cx.entities.accessed_entities.borrow_mut();
2962 mem::swap(&mut entities, entities_ref.deref_mut());
2963 }
2964
2965 fn invalidate_entities(&mut self) {
2966 let mut views = self.invalidator.take_views();
2967 for entity in views.drain() {
2968 self.mark_view_dirty(entity);
2969 }
2970 self.invalidator.replace_views(views);
2971 }
2972
2973 #[profiling::function]
2974 fn present(&mut self) {
2975 self.platform_window.draw(&self.rendered_frame.scene);
2976 #[cfg(feature = "input-latency-histogram")]
2977 self.input_latency_tracker.record_frame_presented();
2978 self.needs_present.set(false);
2979 profiling::finish_frame!();
2980 }
2981
2982 #[cfg(feature = "input-latency-histogram")]
2984 pub fn input_latency_snapshot(&self) -> InputLatencySnapshot {
2985 self.input_latency_tracker.snapshot()
2986 }
2987
2988 fn draw_roots(&mut self, cx: &mut App) {
2989 self.invalidator.set_phase(DrawPhase::Prepaint);
2990 self.tooltip_bounds.take();
2991
2992 self.a11y.sync_active_flag();
2993 if self.a11y.is_active() {
2994 self.a11y.begin_frame();
2995 }
2996
2997 let _inspector_width: Pixels = rems(30.0).to_pixels(self.rem_size());
2998 let root_size = {
2999 #[cfg(any(feature = "inspector", debug_assertions))]
3000 {
3001 if self.inspector.is_some() {
3002 let mut size = self.viewport_size;
3003 size.width = (size.width - _inspector_width).max(px(0.0));
3004 size
3005 } else {
3006 self.viewport_size
3007 }
3008 }
3009 #[cfg(not(any(feature = "inspector", debug_assertions)))]
3010 {
3011 self.viewport_size
3012 }
3013 };
3014
3015 let scale_factor = self.scale_factor();
3017 let mut root_element = self.root.as_ref().unwrap().clone().into_any();
3018 let root_layout_id = root_element.request_layout(self, cx);
3019 self.layout_engine
3020 .as_mut()
3021 .unwrap()
3022 .stretch_auto_size_to_fill(root_layout_id, root_size, scale_factor);
3023 root_element.prepaint_as_root(Point::default(), root_size.into(), self, cx);
3024
3025 #[cfg(any(feature = "inspector", debug_assertions))]
3026 let inspector_element = self.prepaint_inspector(_inspector_width, cx);
3027
3028 self.prepaint_deferred_draws(cx);
3029
3030 let mut prompt_element = None;
3031 let mut active_drag_element = None;
3032 let mut tooltip_element = None;
3033 if let Some(prompt) = self.prompt.take() {
3034 let mut element = prompt.view.any_view().into_any();
3035 let prompt_layout_id = element.request_layout(self, cx);
3036 self.layout_engine
3037 .as_mut()
3038 .unwrap()
3039 .stretch_auto_size_to_fill(prompt_layout_id, root_size, scale_factor);
3040 element.prepaint_as_root(Point::default(), root_size.into(), self, cx);
3041 prompt_element = Some(element);
3042 self.prompt = Some(prompt);
3043 } else if let Some(active_drag) = cx.active_drag.take() {
3044 let mut element = active_drag.view.clone().into_any();
3045 let offset = self.mouse_position() - active_drag.cursor_offset;
3046 element.prepaint_as_root(offset, AvailableSpace::min_size(), self, cx);
3047 active_drag_element = Some(element);
3048 cx.active_drag = Some(active_drag);
3049 } else {
3050 tooltip_element = self.prepaint_tooltip(cx);
3051 }
3052
3053 self.mouse_hit_test = self.next_frame.hit_test(self.mouse_position);
3054
3055 self.invalidator.set_phase(DrawPhase::Paint);
3057 root_element.paint(self, cx);
3058
3059 #[cfg(any(feature = "inspector", debug_assertions))]
3060 self.paint_inspector(inspector_element, cx);
3061
3062 let mut sorted_deferred_draws =
3063 (0..self.next_frame.deferred_draws.len()).collect::<SmallVec<[_; 8]>>();
3064 sorted_deferred_draws.sort_by_key(|ix| self.next_frame.deferred_draws[*ix].priority);
3065 self.paint_deferred_draws(&sorted_deferred_draws, cx);
3066
3067 if let Some(mut prompt_element) = prompt_element {
3068 prompt_element.paint(self, cx);
3069 } else if let Some(mut drag_element) = active_drag_element {
3070 drag_element.paint(self, cx);
3071 } else if let Some(mut tooltip_element) = tooltip_element {
3072 tooltip_element.paint(self, cx);
3073 }
3074
3075 #[cfg(any(feature = "inspector", debug_assertions))]
3076 self.paint_inspector_hitbox(cx);
3077
3078 let a11y_active_start_of_frame = self.a11y.is_active();
3079 self.a11y.sync_active_flag();
3080 let a11y_active_end_of_frame = self.a11y.is_active();
3081
3082 if a11y_active_start_of_frame {
3083 let tree_update = self.a11y.end_frame();
3084 if a11y_active_end_of_frame {
3085 log::debug!(
3086 "Sending a11y tree update: {} nodes",
3087 tree_update.nodes.len()
3088 );
3089 self.platform_window.a11y_tree_update(tree_update);
3090 }
3091 }
3092 }
3093
3094 fn prepaint_tooltip(&mut self, cx: &mut App) -> Option<AnyElement> {
3095 for tooltip_request_index in (0..self.next_frame.tooltip_requests.len()).rev() {
3097 let Some(Some(tooltip_request)) = self
3098 .next_frame
3099 .tooltip_requests
3100 .get(tooltip_request_index)
3101 .cloned()
3102 else {
3103 log::error!("Unexpectedly absent TooltipRequest");
3104 continue;
3105 };
3106 let mut element = tooltip_request.tooltip.view.clone().into_any();
3107 let mouse_position = tooltip_request.tooltip.mouse_position;
3108 let tooltip_size = element.layout_as_root(AvailableSpace::min_size(), self, cx);
3109
3110 let mut tooltip_bounds =
3111 Bounds::new(mouse_position + point(px(1.), px(1.)), tooltip_size);
3112 let window_bounds = Bounds {
3113 origin: Point::default(),
3114 size: self.viewport_size(),
3115 };
3116
3117 if tooltip_bounds.right() > window_bounds.right() {
3118 let new_x = mouse_position.x - tooltip_bounds.size.width - px(1.);
3119 if new_x >= Pixels::ZERO {
3120 tooltip_bounds.origin.x = new_x;
3121 } else {
3122 tooltip_bounds.origin.x = cmp::max(
3123 Pixels::ZERO,
3124 tooltip_bounds.origin.x - tooltip_bounds.right() - window_bounds.right(),
3125 );
3126 }
3127 }
3128
3129 if tooltip_bounds.bottom() > window_bounds.bottom() {
3130 let new_y = mouse_position.y - tooltip_bounds.size.height - px(1.);
3131 if new_y >= Pixels::ZERO {
3132 tooltip_bounds.origin.y = new_y;
3133 } else {
3134 tooltip_bounds.origin.y = cmp::max(
3135 Pixels::ZERO,
3136 tooltip_bounds.origin.y - tooltip_bounds.bottom() - window_bounds.bottom(),
3137 );
3138 }
3139 }
3140
3141 let is_visible =
3145 (tooltip_request.tooltip.check_visible_and_update)(tooltip_bounds, self, cx);
3146 if !is_visible {
3147 continue;
3148 }
3149
3150 self.with_absolute_element_offset(tooltip_bounds.origin, |window| {
3151 element.prepaint(window, cx)
3152 });
3153
3154 self.tooltip_bounds = Some(TooltipBounds {
3155 id: tooltip_request.id,
3156 bounds: tooltip_bounds,
3157 });
3158 return Some(element);
3159 }
3160 None
3161 }
3162
3163 fn prepaint_deferred_draws(&mut self, cx: &mut App) {
3164 assert_eq!(self.element_id_stack.len(), 0);
3165
3166 let mut round_start = 0;
3169 let mut depth = 0;
3170 loop {
3171 let round_end = self.next_frame.deferred_draws.len();
3172 if round_start == round_end {
3173 break;
3174 }
3175
3176 assert!(depth < 10, "Exceeded maximum (10) deferred depth");
3177 depth += 1;
3178
3179 let mut traversal_order = (round_start..round_end).collect::<SmallVec<[usize; 8]>>();
3180 traversal_order.sort_by_key(|ix| self.next_frame.deferred_draws[*ix].priority);
3181
3182 for deferred_draw_ix in traversal_order {
3183 let (element, parent_node, current_view, absolute_offset, prepaint_range) = {
3184 let deferred_draw = &mut self.next_frame.deferred_draws[deferred_draw_ix];
3185 self.element_id_stack
3186 .clone_from(&deferred_draw.element_id_stack);
3187 self.text_style_stack
3188 .clone_from(&deferred_draw.text_style_stack);
3189 (
3190 deferred_draw.element.take(),
3191 deferred_draw.parent_node,
3192 deferred_draw.current_view,
3193 deferred_draw.absolute_offset,
3194 deferred_draw.prepaint_range.clone(),
3195 )
3196 };
3197 self.next_frame.dispatch_tree.set_active_node(parent_node);
3198
3199 let prepaint_start = self.prepaint_index();
3200 if let Some(mut element) = element {
3201 self.with_rendered_view(current_view, |window| {
3202 window.with_absolute_element_offset(absolute_offset, |window| {
3203 element.prepaint(window, cx)
3204 });
3205 });
3206 self.next_frame.deferred_draws[deferred_draw_ix].element = Some(element);
3207 } else {
3208 self.reuse_prepaint(prepaint_range);
3209 }
3210 let prepaint_end = self.prepaint_index();
3211 self.next_frame.deferred_draws[deferred_draw_ix].prepaint_range =
3212 prepaint_start..prepaint_end;
3213 }
3214
3215 self.element_id_stack.clear();
3216 self.text_style_stack.clear();
3217 round_start = round_end;
3218 }
3219 }
3220
3221 fn paint_deferred_draws(&mut self, deferred_draw_indices: &[usize], cx: &mut App) {
3222 assert_eq!(self.element_id_stack.len(), 0);
3223
3224 let mut deferred_draws = mem::take(&mut self.next_frame.deferred_draws);
3225 for deferred_draw_ix in deferred_draw_indices {
3226 let mut deferred_draw = &mut deferred_draws[*deferred_draw_ix];
3227 self.element_id_stack
3228 .clone_from(&deferred_draw.element_id_stack);
3229 self.next_frame
3230 .dispatch_tree
3231 .set_active_node(deferred_draw.parent_node);
3232
3233 let paint_start = self.paint_index();
3234 if let Some(element) = deferred_draw.element.as_mut() {
3235 self.with_rendered_view(deferred_draw.current_view, |window| {
3236 element.paint(window, cx);
3237 })
3238 } else {
3239 self.reuse_paint(deferred_draw.paint_range.clone());
3240 }
3241 let paint_end = self.paint_index();
3242 deferred_draw.paint_range = paint_start..paint_end;
3243 }
3244 self.next_frame.deferred_draws = deferred_draws;
3245 self.element_id_stack.clear();
3246 }
3247
3248 pub(crate) fn prepaint_index(&self) -> PrepaintStateIndex {
3249 PrepaintStateIndex {
3250 hitboxes_index: self.next_frame.hitboxes.len(),
3251 tooltips_index: self.next_frame.tooltip_requests.len(),
3252 deferred_draws_index: self.next_frame.deferred_draws.len(),
3253 dispatch_tree_index: self.next_frame.dispatch_tree.len(),
3254 accessed_element_states_index: self.next_frame.accessed_element_states.len(),
3255 line_layout_index: self.text_system.layout_index(),
3256 }
3257 }
3258
3259 pub(crate) fn reuse_prepaint(&mut self, range: Range<PrepaintStateIndex>) {
3260 self.next_frame.hitboxes.extend(
3261 self.rendered_frame.hitboxes[range.start.hitboxes_index..range.end.hitboxes_index]
3262 .iter()
3263 .cloned(),
3264 );
3265 self.next_frame.tooltip_requests.extend(
3266 self.rendered_frame.tooltip_requests
3267 [range.start.tooltips_index..range.end.tooltips_index]
3268 .iter_mut()
3269 .map(|request| request.take()),
3270 );
3271 self.next_frame.accessed_element_states.extend(
3272 self.rendered_frame.accessed_element_states[range.start.accessed_element_states_index
3273 ..range.end.accessed_element_states_index]
3274 .iter()
3275 .map(|(id, type_id)| (GlobalElementId(id.0.clone()), *type_id)),
3276 );
3277 self.text_system
3278 .reuse_layouts(range.start.line_layout_index..range.end.line_layout_index);
3279
3280 let reused_subtree = self.next_frame.dispatch_tree.reuse_subtree(
3281 range.start.dispatch_tree_index..range.end.dispatch_tree_index,
3282 &mut self.rendered_frame.dispatch_tree,
3283 self.focus,
3284 );
3285
3286 if reused_subtree.contains_focus() {
3287 self.next_frame.focus = self.focus;
3288 }
3289
3290 self.next_frame.deferred_draws.extend(
3291 self.rendered_frame.deferred_draws
3292 [range.start.deferred_draws_index..range.end.deferred_draws_index]
3293 .iter()
3294 .map(|deferred_draw| DeferredDraw {
3295 current_view: deferred_draw.current_view,
3296 parent_node: reused_subtree.refresh_node_id(deferred_draw.parent_node),
3297 element_id_stack: deferred_draw.element_id_stack.clone(),
3298 text_style_stack: deferred_draw.text_style_stack.clone(),
3299 priority: deferred_draw.priority,
3300 element: None,
3301 absolute_offset: deferred_draw.absolute_offset,
3302 prepaint_range: deferred_draw.prepaint_range.clone(),
3303 paint_range: deferred_draw.paint_range.clone(),
3304 }),
3305 );
3306 }
3307
3308 pub(crate) fn paint_index(&self) -> PaintIndex {
3309 PaintIndex {
3310 scene_index: self.next_frame.scene.len(),
3311 #[cfg(any(test, feature = "test-support"))]
3312 debug_bounds_index: self.next_frame.debug_bounds_records.len(),
3313 mouse_listeners_index: self.next_frame.mouse_listeners.len(),
3314 input_handlers_index: self.next_frame.input_handlers.len(),
3315 cursor_styles_index: self.next_frame.cursor_styles.len(),
3316 accessed_element_states_index: self.next_frame.accessed_element_states.len(),
3317 tab_handle_index: self.next_frame.tab_stops.paint_index(),
3318 line_layout_index: self.text_system.layout_index(),
3319 }
3320 }
3321
3322 pub(crate) fn reuse_paint(&mut self, range: Range<PaintIndex>) {
3323 #[cfg(any(test, feature = "test-support"))]
3325 for (selector, bounds) in &self.rendered_frame.debug_bounds_records
3326 [range.start.debug_bounds_index..range.end.debug_bounds_index]
3327 {
3328 self.next_frame
3329 .record_debug_bounds(selector.clone(), *bounds);
3330 }
3331 self.next_frame.cursor_styles.extend(
3332 self.rendered_frame.cursor_styles
3333 [range.start.cursor_styles_index..range.end.cursor_styles_index]
3334 .iter()
3335 .cloned(),
3336 );
3337 self.next_frame.input_handlers.extend(
3338 self.rendered_frame.input_handlers
3339 [range.start.input_handlers_index..range.end.input_handlers_index]
3340 .iter_mut()
3341 .map(|handler| handler.take()),
3342 );
3343 self.next_frame.mouse_listeners.extend(
3344 self.rendered_frame.mouse_listeners
3345 [range.start.mouse_listeners_index..range.end.mouse_listeners_index]
3346 .iter_mut()
3347 .map(|listener| listener.take()),
3348 );
3349 self.next_frame.accessed_element_states.extend(
3350 self.rendered_frame.accessed_element_states[range.start.accessed_element_states_index
3351 ..range.end.accessed_element_states_index]
3352 .iter()
3353 .map(|(id, type_id)| (GlobalElementId(id.0.clone()), *type_id)),
3354 );
3355 self.next_frame.tab_stops.replay(
3356 &self.rendered_frame.tab_stops.insertion_history
3357 [range.start.tab_handle_index..range.end.tab_handle_index],
3358 );
3359
3360 self.text_system
3361 .reuse_layouts(range.start.line_layout_index..range.end.line_layout_index);
3362 self.next_frame.scene.replay(
3363 range.start.scene_index..range.end.scene_index,
3364 &self.rendered_frame.scene,
3365 );
3366 }
3367
3368 pub fn with_text_style<F, R>(&mut self, style: Option<TextStyleRefinement>, f: F) -> R
3372 where
3373 F: FnOnce(&mut Self) -> R,
3374 {
3375 self.invalidator.debug_assert_paint_or_prepaint();
3376 if let Some(style) = style {
3377 self.text_style_stack.push(style);
3378 let result = f(self);
3379 self.text_style_stack.pop();
3380 result
3381 } else {
3382 f(self)
3383 }
3384 }
3385
3386 pub fn set_cursor_style(&mut self, style: CursorStyle, hitbox: &Hitbox) {
3389 self.invalidator.debug_assert_paint();
3390 self.next_frame.cursor_styles.push(CursorStyleRequest {
3391 hitbox_id: Some(hitbox.id),
3392 style,
3393 });
3394 }
3395
3396 pub fn set_window_cursor_style(&mut self, style: CursorStyle) {
3401 self.invalidator.debug_assert_paint();
3402 self.next_frame.cursor_styles.push(CursorStyleRequest {
3403 hitbox_id: None,
3404 style,
3405 })
3406 }
3407
3408 pub fn set_tooltip(&mut self, tooltip: AnyTooltip) -> TooltipId {
3411 self.invalidator.debug_assert_prepaint();
3412 let id = TooltipId(post_inc(&mut self.next_tooltip_id.0));
3413 self.next_frame
3414 .tooltip_requests
3415 .push(Some(TooltipRequest { id, tooltip }));
3416 id
3417 }
3418
3419 pub fn with_content_mask<R>(
3422 &mut self,
3423 mask: Option<ContentMask<Pixels>>,
3424 f: impl FnOnce(&mut Self) -> R,
3425 ) -> R {
3426 self.invalidator.debug_assert_paint_or_prepaint();
3427 if let Some(mask) = mask {
3428 let mask = mask.intersect(&self.content_mask());
3429 self.content_mask_stack.push(mask);
3430 let result = f(self);
3431 self.content_mask_stack.pop();
3432 result
3433 } else {
3434 f(self)
3435 }
3436 }
3437
3438 pub fn with_element_offset<R>(
3441 &mut self,
3442 offset: Point<Pixels>,
3443 f: impl FnOnce(&mut Self) -> R,
3444 ) -> R {
3445 self.invalidator.debug_assert_prepaint();
3446
3447 if offset.is_zero() {
3448 return f(self);
3449 };
3450
3451 let abs_offset = self.element_offset() + offset;
3452 self.with_absolute_element_offset(abs_offset, f)
3453 }
3454
3455 pub fn with_absolute_element_offset<R>(
3459 &mut self,
3460 offset: Point<Pixels>,
3461 f: impl FnOnce(&mut Self) -> R,
3462 ) -> R {
3463 self.invalidator.debug_assert_prepaint();
3464 self.element_offset_stack.push(offset);
3465 let result = f(self);
3466 self.element_offset_stack.pop();
3467 result
3468 }
3469
3470 pub(crate) fn with_element_opacity<R>(
3471 &mut self,
3472 opacity: Option<f32>,
3473 f: impl FnOnce(&mut Self) -> R,
3474 ) -> R {
3475 self.invalidator.debug_assert_paint_or_prepaint();
3476
3477 let Some(opacity) = opacity else {
3478 return f(self);
3479 };
3480
3481 let previous_opacity = self.element_opacity;
3482 self.element_opacity = previous_opacity * opacity;
3483 let result = f(self);
3484 self.element_opacity = previous_opacity;
3485 result
3486 }
3487
3488 pub fn transact<T, U>(&mut self, f: impl FnOnce(&mut Self) -> Result<T, U>) -> Result<T, U> {
3494 self.invalidator.debug_assert_prepaint();
3495 let index = self.prepaint_index();
3496 let result = f(self);
3497 if result.is_err() {
3498 self.next_frame.hitboxes.truncate(index.hitboxes_index);
3499 self.next_frame
3500 .tooltip_requests
3501 .truncate(index.tooltips_index);
3502 self.next_frame
3503 .deferred_draws
3504 .truncate(index.deferred_draws_index);
3505 self.next_frame
3506 .dispatch_tree
3507 .truncate(index.dispatch_tree_index);
3508 self.next_frame
3509 .accessed_element_states
3510 .truncate(index.accessed_element_states_index);
3511 self.text_system.truncate_layouts(index.line_layout_index);
3512 }
3513 result
3514 }
3515
3516 pub fn request_autoscroll(&mut self, bounds: Bounds<Pixels>) {
3522 self.invalidator.debug_assert_prepaint();
3523 self.requested_autoscroll = Some(bounds);
3524 }
3525
3526 pub fn take_autoscroll(&mut self) -> Option<Bounds<Pixels>> {
3529 self.invalidator.debug_assert_prepaint();
3530 self.requested_autoscroll.take()
3531 }
3532
3533 pub fn use_asset<A: Asset>(&mut self, source: &A::Source, cx: &mut App) -> Option<A::Output> {
3539 cx.asset_entry::<A>(source).use_by(self.current_view())
3540 }
3541
3542 pub fn get_asset<A: Asset>(&mut self, source: &A::Source, cx: &mut App) -> Option<A::Output> {
3548 cx.fetch_asset::<A>(source)
3549 }
3550 pub fn element_offset(&self) -> Point<Pixels> {
3553 self.invalidator.debug_assert_prepaint();
3554 self.element_offset_stack
3555 .last()
3556 .copied()
3557 .unwrap_or_default()
3558 }
3559
3560 #[inline]
3563 pub(crate) fn element_opacity(&self) -> f32 {
3564 self.invalidator.debug_assert_paint_or_prepaint();
3565 self.element_opacity
3566 }
3567
3568 pub fn content_mask(&self) -> ContentMask<Pixels> {
3570 self.invalidator.debug_assert_paint_or_prepaint();
3571 self.content_mask_stack
3572 .last()
3573 .cloned()
3574 .unwrap_or_else(|| ContentMask {
3575 bounds: Bounds {
3576 origin: Point::default(),
3577 size: self.viewport_size,
3578 },
3579 })
3580 }
3581
3582 pub fn with_element_namespace<R>(
3585 &mut self,
3586 element_id: impl Into<ElementId>,
3587 f: impl FnOnce(&mut Self) -> R,
3588 ) -> R {
3589 self.element_id_stack.push(element_id.into());
3590 let result = f(self);
3591 self.element_id_stack.pop();
3592 result
3593 }
3594
3595 pub fn use_keyed_state<S: 'static>(
3597 &mut self,
3598 key: impl Into<ElementId>,
3599 cx: &mut App,
3600 init: impl FnOnce(&mut Self, &mut Context<S>) -> S,
3601 ) -> Entity<S> {
3602 let current_view = self.current_view();
3603 self.with_global_id(key.into(), |global_id, window| {
3604 window.with_element_state(global_id, |state: Option<Entity<S>>, window| {
3605 if let Some(state) = state {
3606 (state.clone(), state)
3607 } else {
3608 let new_state = cx.new(|cx| init(window, cx));
3609 cx.observe(&new_state, move |_, cx| {
3610 cx.notify(current_view);
3611 })
3612 .detach();
3613 (new_state.clone(), new_state)
3614 }
3615 })
3616 })
3617 }
3618
3619 pub fn with_id<R>(&mut self, id: impl Into<ElementId>, f: impl FnOnce(&mut Self) -> R) -> R {
3621 self.with_global_id(id.into(), |_, window| f(window))
3622 }
3623
3624 #[track_caller]
3630 pub fn use_state<S: 'static>(
3631 &mut self,
3632 cx: &mut App,
3633 init: impl FnOnce(&mut Self, &mut Context<S>) -> S,
3634 ) -> Entity<S> {
3635 self.use_keyed_state(
3636 ElementId::CodeLocation(*core::panic::Location::caller()),
3637 cx,
3638 init,
3639 )
3640 }
3641
3642 pub fn with_element_state<S, R>(
3647 &mut self,
3648 global_id: &GlobalElementId,
3649 f: impl FnOnce(Option<S>, &mut Self) -> (R, S),
3650 ) -> R
3651 where
3652 S: 'static,
3653 {
3654 self.invalidator.debug_assert_paint_or_prepaint();
3655
3656 let key = (GlobalElementId(global_id.0.clone()), TypeId::of::<S>());
3657 self.next_frame
3658 .accessed_element_states
3659 .push((GlobalElementId(key.0.clone()), TypeId::of::<S>()));
3660
3661 if let Some(any) = self
3662 .next_frame
3663 .element_states
3664 .remove(&key)
3665 .or_else(|| self.rendered_frame.element_states.remove(&key))
3666 {
3667 let ElementStateBox {
3668 inner,
3669 #[cfg(debug_assertions)]
3670 type_name,
3671 } = any;
3672 let mut state_box = inner
3674 .downcast::<Option<S>>()
3675 .map_err(|_| {
3676 #[cfg(debug_assertions)]
3677 {
3678 anyhow::anyhow!(
3679 "invalid element state type for id, requested {:?}, actual: {:?}",
3680 std::any::type_name::<S>(),
3681 type_name
3682 )
3683 }
3684
3685 #[cfg(not(debug_assertions))]
3686 {
3687 anyhow::anyhow!(
3688 "invalid element state type for id, requested {:?}",
3689 std::any::type_name::<S>(),
3690 )
3691 }
3692 })
3693 .unwrap();
3694
3695 let state = state_box.take().expect(
3696 "reentrant call to with_element_state for the same state type and element id",
3697 );
3698 let (result, state) = f(Some(state), self);
3699 state_box.replace(state);
3700 self.next_frame.element_states.insert(
3701 key,
3702 ElementStateBox {
3703 inner: state_box,
3704 #[cfg(debug_assertions)]
3705 type_name,
3706 },
3707 );
3708 result
3709 } else {
3710 let (result, state) = f(None, self);
3711 self.next_frame.element_states.insert(
3712 key,
3713 ElementStateBox {
3714 inner: Box::new(Some(state)),
3715 #[cfg(debug_assertions)]
3716 type_name: std::any::type_name::<S>(),
3717 },
3718 );
3719 result
3720 }
3721 }
3722
3723 pub fn with_optional_element_state<S, R>(
3730 &mut self,
3731 global_id: Option<&GlobalElementId>,
3732 f: impl FnOnce(Option<Option<S>>, &mut Self) -> (R, Option<S>),
3733 ) -> R
3734 where
3735 S: 'static,
3736 {
3737 self.invalidator.debug_assert_paint_or_prepaint();
3738
3739 if let Some(global_id) = global_id {
3740 self.with_element_state(global_id, |state, cx| {
3741 let (result, state) = f(Some(state), cx);
3742 let state =
3743 state.expect("you must return some state when you pass some element id");
3744 (result, state)
3745 })
3746 } else {
3747 let (result, state) = f(None, self);
3748 debug_assert!(
3749 state.is_none(),
3750 "you must not return an element state when passing None for the global id"
3751 );
3752 result
3753 }
3754 }
3755
3756 #[inline]
3758 pub fn with_tab_group<R>(&mut self, index: Option<isize>, f: impl FnOnce(&mut Self) -> R) -> R {
3759 if let Some(index) = index {
3760 self.next_frame.tab_stops.begin_group(index);
3761 let result = f(self);
3762 self.next_frame.tab_stops.end_group();
3763 result
3764 } else {
3765 f(self)
3766 }
3767 }
3768
3769 pub fn defer_draw(
3775 &mut self,
3776 element: AnyElement,
3777 absolute_offset: Point<Pixels>,
3778 priority: usize,
3779 ) {
3780 self.invalidator.debug_assert_prepaint();
3781 let parent_node = self.next_frame.dispatch_tree.active_node_id().unwrap();
3782 self.next_frame.deferred_draws.push(DeferredDraw {
3783 current_view: self.current_view(),
3784 parent_node,
3785 element_id_stack: self.element_id_stack.clone(),
3786 text_style_stack: self.text_style_stack.clone(),
3787 priority,
3788 element: Some(element),
3789 absolute_offset,
3790 prepaint_range: PrepaintStateIndex::default()..PrepaintStateIndex::default(),
3791 paint_range: PaintIndex::default()..PaintIndex::default(),
3792 });
3793 }
3794
3795 pub fn paint_layer<R>(&mut self, bounds: Bounds<Pixels>, f: impl FnOnce(&mut Self) -> R) -> R {
3801 self.invalidator.debug_assert_paint();
3802
3803 let content_mask = self.content_mask();
3804 let clipped_bounds = bounds.intersect(&content_mask.bounds);
3805 if !clipped_bounds.is_empty() {
3806 self.next_frame
3807 .scene
3808 .push_layer(self.cover_bounds(clipped_bounds));
3809 }
3810
3811 let result = f(self);
3812
3813 if !clipped_bounds.is_empty() {
3814 self.next_frame.scene.pop_layer();
3815 }
3816
3817 result
3818 }
3819
3820 pub fn paint_shadows(
3824 &mut self,
3825 bounds: Bounds<Pixels>,
3826 corner_radii: Corners<Pixels>,
3827 shadows: &[BoxShadow],
3828 ) {
3829 self.invalidator.debug_assert_paint();
3830
3831 let scale_factor = self.scale_factor();
3832 let content_mask = self.snapped_content_mask();
3833 let opacity = self.element_opacity();
3834 for shadow in shadows {
3835 let shadow_bounds = if shadow.inset {
3836 bounds.contract(shadow.spread_radius)
3837 } else {
3838 (bounds + shadow.offset).dilate(shadow.spread_radius)
3839 };
3840 self.next_frame.scene.insert_primitive(Shadow {
3841 order: 0,
3842 blur_radius: shadow.blur_radius.scale(scale_factor),
3843 bounds: if shadow.inset {
3844 self.snap_bounds(shadow_bounds)
3845 } else {
3846 self.cover_bounds(shadow_bounds)
3847 },
3848 content_mask: if shadow.inset {
3849 ContentMask {
3850 bounds: self.snap_bounds(bounds),
3851 }
3852 } else {
3853 content_mask
3854 },
3855 corner_radii: corner_radii.scale(scale_factor),
3856 color: shadow.color.opacity(opacity),
3857 inset: if shadow.inset { 1 } else { 0 },
3858 _pad_end: 0,
3859 });
3860 }
3861 }
3862
3863 pub fn paint_quad(&mut self, quad: PaintQuad) {
3873 self.invalidator.debug_assert_paint();
3874
3875 let opacity = self.element_opacity();
3876 let snapped_bounds = self.snap_bounds(quad.bounds);
3877 let snapped_border_widths = self.snap_border_widths(quad.border_widths);
3878 let quad = Quad {
3879 order: 0,
3880 bounds: snapped_bounds,
3881 content_mask: self.snapped_content_mask(),
3882 background: quad.background.opacity(opacity),
3883 border_color: quad.border_color.opacity(opacity),
3884 corner_radii: quad.corner_radii.scale(self.scale_factor()),
3885 border_widths: snapped_border_widths,
3886 border_style: quad.border_style,
3887 continuous_corners: if quad.continuous_corners { 1 } else { 0 },
3888 _pad_before_transform: 0,
3889 transform: quad.transform,
3890 blend_mode: quad.blend_mode as u32,
3891 _pad_end: 0,
3892 };
3893
3894 if !quad.background.is_transparent() {
3895 self.next_frame.scene.insert_primitive(quad);
3896 return;
3897 }
3898
3899 let Some(strips) =
3900 border_only_quad_strips(quad.bounds, quad.border_widths, quad.corner_radii)
3901 else {
3902 self.next_frame.scene.insert_primitive(quad);
3903 return;
3904 };
3905
3906 for strip in strips {
3907 let mask_bounds = quad.content_mask.bounds.intersect(&strip);
3908 if !mask_bounds.is_empty() {
3909 self.next_frame.scene.insert_primitive(Quad {
3910 content_mask: ContentMask {
3911 bounds: mask_bounds,
3912 },
3913 ..quad
3914 });
3915 }
3916 }
3917 }
3918
3919 pub fn paint_path(&mut self, mut path: Path<Pixels>, color: impl Into<Background>) {
3923 self.invalidator.debug_assert_paint();
3924
3925 let scale_factor = self.scale_factor();
3926 let content_mask = self.content_mask();
3927 let opacity = self.element_opacity();
3928 path.content_mask = content_mask;
3929 let color: Background = color.into();
3930 path.color = color.opacity(opacity);
3931 self.next_frame
3932 .scene
3933 .insert_primitive(path.scale(scale_factor));
3934 }
3935
3936 pub fn paint_underline(
3940 &mut self,
3941 origin: Point<Pixels>,
3942 width: Pixels,
3943 style: &UnderlineStyle,
3944 ) {
3945 self.invalidator.debug_assert_paint();
3946
3947 let scale_factor = self.scale_factor();
3948 let thickness = self.snap_stroke(style.thickness);
3949 let height = if style.wavy {
3950 ScaledPixels(thickness.0 * 3.)
3951 } else {
3952 thickness
3953 };
3954 let bounds = Bounds {
3955 origin: origin.map(|c| ScaledPixels(round_to_device_pixel(c.0, scale_factor))),
3956 size: size(self.snap_stroke(width), height),
3957 };
3958 let element_opacity = self.element_opacity();
3959
3960 self.next_frame.scene.insert_primitive(Underline {
3961 order: 0,
3962 pad: 0,
3963 bounds,
3964 content_mask: self.snapped_content_mask(),
3965 color: style.color.unwrap_or_default().opacity(element_opacity),
3966 thickness,
3967 wavy: style.wavy.into(),
3968 });
3969 }
3970
3971 pub fn paint_strikethrough(
3975 &mut self,
3976 origin: Point<Pixels>,
3977 width: Pixels,
3978 style: &StrikethroughStyle,
3979 ) {
3980 self.invalidator.debug_assert_paint();
3981
3982 let scale_factor = self.scale_factor();
3983 let height = style.thickness;
3984 let bounds = Bounds {
3985 origin: origin.map(|c| ScaledPixels(round_to_device_pixel(c.0, scale_factor))),
3986 size: size(self.snap_stroke(width), self.snap_stroke(height)),
3987 };
3988 let opacity = self.element_opacity();
3989
3990 self.next_frame.scene.insert_primitive(Underline {
3991 order: 0,
3992 pad: 0,
3993 bounds,
3994 content_mask: self.snapped_content_mask(),
3995 thickness: self.snap_stroke(style.thickness),
3996 color: style.color.unwrap_or_default().opacity(opacity),
3997 wavy: false.into(),
3998 });
3999 }
4000
4001 pub fn paint_glyph(
4010 &mut self,
4011 origin: Point<Pixels>,
4012 font_id: FontId,
4013 glyph_id: GlyphId,
4014 font_size: Pixels,
4015 color: Hsla,
4016 ) -> Result<()> {
4017 self.invalidator.debug_assert_paint();
4018
4019 let element_opacity = self.element_opacity();
4020 let scale_factor = self.scale_factor();
4021 let glyph_origin = origin.scale(scale_factor);
4022
4023 let quantized_origin = Point::new(
4024 round_half_toward_zero(glyph_origin.x.0 * SUBPIXEL_VARIANTS_X as f32)
4025 / SUBPIXEL_VARIANTS_X as f32,
4026 round_half_toward_zero(glyph_origin.y.0 * SUBPIXEL_VARIANTS_Y as f32)
4027 / SUBPIXEL_VARIANTS_Y as f32,
4028 );
4029 let subpixel_variant = Point::new(
4030 (quantized_origin.x.fract() * SUBPIXEL_VARIANTS_X as f32) as u8,
4031 (quantized_origin.y.fract() * SUBPIXEL_VARIANTS_Y as f32) as u8,
4032 );
4033 let integer_origin = quantized_origin.map(|c| ScaledPixels(c.trunc()));
4034 let dilation = self.text_system().glyph_dilation_for_color(color);
4035 let params = RenderGlyphParams {
4036 font_id,
4037 glyph_id,
4038 font_size,
4039 subpixel_variant,
4040 scale_factor,
4041 is_emoji: false,
4042 dilation,
4043 };
4044
4045 let raster_bounds = self.text_system().raster_bounds(¶ms)?;
4046 if !raster_bounds.is_zero() {
4047 let tile = self
4048 .sprite_atlas
4049 .get_or_insert_with(¶ms.clone().into(), &mut || {
4050 let (size, bytes) = self.text_system().rasterize_glyph(¶ms)?;
4051 Ok(Some((size, Cow::Owned(bytes))))
4052 })?
4053 .expect("Callback above only errors or returns Some");
4054 let bounds = Bounds {
4055 origin: integer_origin + raster_bounds.origin.map(Into::into),
4056 size: tile.bounds.size.map(Into::into),
4057 };
4058 let content_mask = self.snapped_content_mask();
4059 self.next_frame.scene.insert_primitive(MonochromeSprite {
4060 order: 0,
4061 pad: 0,
4062 bounds,
4063 content_mask,
4064 color: color.opacity(element_opacity),
4065 tile,
4066 transformation: TransformationMatrix::unit(),
4067 });
4068 }
4069 Ok(())
4070 }
4071
4072 pub fn paint_emoji(
4081 &mut self,
4082 origin: Point<Pixels>,
4083 font_id: FontId,
4084 glyph_id: GlyphId,
4085 font_size: Pixels,
4086 ) -> Result<()> {
4087 self.invalidator.debug_assert_paint();
4088
4089 let scale_factor = self.scale_factor();
4090 let glyph_origin = origin.scale(scale_factor);
4091 let integer_origin = glyph_origin.map(|c| ScaledPixels(round_half_toward_zero(c.0)));
4092 let params = RenderGlyphParams {
4093 font_id,
4094 glyph_id,
4095 font_size,
4096 subpixel_variant: Default::default(),
4097 scale_factor,
4098 is_emoji: true,
4099 dilation: 0, };
4101
4102 let raster_bounds = self.text_system().raster_bounds(¶ms)?;
4103 if !raster_bounds.is_zero() {
4104 let tile = self
4105 .sprite_atlas
4106 .get_or_insert_with(¶ms.clone().into(), &mut || {
4107 let (size, bytes) = self.text_system().rasterize_glyph(¶ms)?;
4108 Ok(Some((size, Cow::Owned(bytes))))
4109 })?
4110 .expect("Callback above only errors or returns Some");
4111
4112 let bounds = Bounds {
4113 origin: integer_origin + raster_bounds.origin.map(Into::into),
4114 size: tile.bounds.size.map(Into::into),
4115 };
4116 let content_mask = self.snapped_content_mask();
4117 let opacity = self.element_opacity();
4118
4119 self.next_frame.scene.insert_primitive(PolychromeSprite {
4120 order: 0,
4121 pad: 0,
4122 grayscale: false.into(),
4123 bounds,
4124 corner_radii: Default::default(),
4125 content_mask,
4126 tile,
4127 opacity,
4128 });
4129 }
4130 Ok(())
4131 }
4132
4133 pub fn paint_svg(
4137 &mut self,
4138 bounds: Bounds<Pixels>,
4139 path: SharedString,
4140 transformation: TransformationMatrix,
4141 color: Hsla,
4142 cx: &App,
4143 ) -> Result<()> {
4144 self.paint_svg_from(bounds, path, None, transformation, color, cx)
4145 }
4146
4147 pub(crate) fn paint_svg_from(
4149 &mut self,
4150 bounds: Bounds<Pixels>,
4151 path: SharedString,
4152 data: Option<&[u8]>,
4153 transformation: TransformationMatrix,
4154 color: Hsla,
4155 cx: &App,
4156 ) -> Result<()> {
4157 self.invalidator.debug_assert_paint();
4158
4159 let element_opacity = self.element_opacity();
4160 let bounds = self.snap_bounds(bounds);
4161 let params = RenderSvgParams {
4162 path,
4163 size: bounds.size.map(|pixels| {
4164 DevicePixels::from((pixels.0 * SMOOTH_SVG_SCALE_FACTOR).ceil() as i32)
4165 }),
4166 };
4167
4168 let Some(tile) =
4169 self.sprite_atlas
4170 .get_or_insert_with(¶ms.clone().into(), &mut || {
4171 let Some((size, bytes)) = cx.svg_renderer.render(¶ms, data)? else {
4172 return Ok(None);
4173 };
4174 Ok(Some((size, Cow::Owned(bytes))))
4175 })?
4176 else {
4177 return Ok(());
4178 };
4179 let content_mask = self.snapped_content_mask();
4180 let svg_bounds = Bounds {
4181 origin: bounds.center()
4182 - Point::new(
4183 ScaledPixels(tile.bounds.size.width.0 as f32 / SMOOTH_SVG_SCALE_FACTOR / 2.),
4184 ScaledPixels(tile.bounds.size.height.0 as f32 / SMOOTH_SVG_SCALE_FACTOR / 2.),
4185 ),
4186 size: tile
4187 .bounds
4188 .size
4189 .map(|value| ScaledPixels(value.0 as f32 / SMOOTH_SVG_SCALE_FACTOR)),
4190 };
4191 let final_bounds = svg_bounds
4192 .map_origin(|origin| ScaledPixels(round_half_toward_zero(origin.0)))
4193 .map_size(|size| size.ceil());
4194
4195 self.next_frame.scene.insert_primitive(MonochromeSprite {
4196 order: 0,
4197 pad: 0,
4198 bounds: final_bounds,
4199 content_mask,
4200 color: color.opacity(element_opacity),
4201 tile,
4202 transformation,
4203 });
4204
4205 Ok(())
4206 }
4207
4208 pub fn paint_image(
4213 &mut self,
4214 bounds: Bounds<Pixels>,
4215 image_bounds: Bounds<Pixels>,
4216 corner_radii: Corners<Pixels>,
4217 data: Arc<RenderImage>,
4218 frame_index: usize,
4219 grayscale: bool,
4220 ) -> Result<()> {
4221 self.invalidator.debug_assert_paint();
4222
4223 let visible_bounds = bounds.intersect(&image_bounds);
4224 if visible_bounds.size.width <= Pixels::ZERO || visible_bounds.size.height <= Pixels::ZERO {
4225 return Ok(());
4226 }
4227 if image_bounds.size.width <= Pixels::ZERO || image_bounds.size.height <= Pixels::ZERO {
4228 return Ok(());
4229 }
4230
4231 let params = RenderImageParams {
4232 image_id: data.id,
4233 frame_index,
4234 };
4235 let Some(bytes) = data.as_bytes(frame_index) else {
4236 return Ok(());
4237 };
4238 let image_size = data.size(frame_index);
4239
4240 let tile = self
4241 .sprite_atlas
4242 .get_or_insert_with(¶ms.into(), &mut || {
4243 Ok(Some((image_size, Cow::Borrowed(bytes))))
4244 })?
4245 .expect("Callback above only returns Some");
4246
4247 let visible_bounds_snapped = self.snap_bounds(visible_bounds);
4248 let sub_tile = if visible_bounds == image_bounds {
4249 tile
4250 } else {
4251 let x_offset_ratio =
4252 (visible_bounds.origin.x - image_bounds.origin.x) / image_bounds.size.width;
4253 let y_offset_ratio =
4254 (visible_bounds.origin.y - image_bounds.origin.y) / image_bounds.size.height;
4255 let width_ratio = visible_bounds.size.width / image_bounds.size.width;
4256 let height_ratio = visible_bounds.size.height / image_bounds.size.height;
4257
4258 let tile_origin_x = tile.bounds.origin.x.0;
4259 let tile_origin_y = tile.bounds.origin.y.0;
4260 let tile_width = tile.bounds.size.width.0;
4261 let tile_height = tile.bounds.size.height.0;
4262
4263 let sub_origin_x = tile_origin_x + (x_offset_ratio * tile_width as f32).round() as i32;
4264 let sub_origin_y = tile_origin_y + (y_offset_ratio * tile_height as f32).round() as i32;
4265 let sub_width = (width_ratio * tile_width as f32).round() as i32;
4266 let sub_height = (height_ratio * tile_height as f32).round() as i32;
4267
4268 let max_x = tile_origin_x + tile_width;
4269 let max_y = tile_origin_y + tile_height;
4270 let clamped_origin_x = sub_origin_x.clamp(tile_origin_x, max_x);
4271 let clamped_origin_y = sub_origin_y.clamp(tile_origin_y, max_y);
4272 let clamped_width = sub_width.min(max_x - clamped_origin_x).max(0);
4273 let clamped_height = sub_height.min(max_y - clamped_origin_y).max(0);
4274
4275 AtlasTile {
4276 bounds: Bounds {
4277 origin: point(
4278 DevicePixels(clamped_origin_x),
4279 DevicePixels(clamped_origin_y),
4280 ),
4281 size: size(DevicePixels(clamped_width), DevicePixels(clamped_height)),
4282 },
4283 ..tile
4284 }
4285 };
4286
4287 let content_mask = self.snapped_content_mask();
4288 let corner_radii = corner_radii
4289 .clamp_radii_for_quad_size(visible_bounds.size)
4290 .scale(self.scale_factor());
4291 let opacity = self.element_opacity();
4292
4293 self.next_frame.scene.insert_primitive(PolychromeSprite {
4294 order: 0,
4295 pad: 0,
4296 grayscale: grayscale.into(),
4297 bounds: visible_bounds_snapped,
4298 content_mask,
4299 corner_radii,
4300 tile: sub_tile,
4301 opacity,
4302 });
4303 Ok(())
4304 }
4305
4306 #[cfg(target_os = "macos")]
4310 pub fn paint_surface(&mut self, bounds: Bounds<Pixels>, image_buffer: CVPixelBuffer) {
4311 use crate::PaintSurface;
4312
4313 self.invalidator.debug_assert_paint();
4314
4315 let bounds = self.snap_bounds(bounds);
4316 let content_mask = self.snapped_content_mask();
4317 self.next_frame.scene.insert_primitive(PaintSurface {
4318 order: 0,
4319 bounds,
4320 content_mask,
4321 image_buffer,
4322 });
4323 }
4324
4325 pub fn drop_image(&mut self, data: Arc<RenderImage>) -> Result<()> {
4327 for frame_index in 0..data.frame_count() {
4328 let params = RenderImageParams {
4329 image_id: data.id,
4330 frame_index,
4331 };
4332
4333 self.sprite_atlas.remove(¶ms.clone().into());
4334 }
4335
4336 Ok(())
4337 }
4338
4339 #[must_use]
4345 pub fn request_layout(
4346 &mut self,
4347 style: Style,
4348 children: impl IntoIterator<Item = LayoutId>,
4349 cx: &mut App,
4350 ) -> LayoutId {
4351 self.invalidator.debug_assert_prepaint();
4352
4353 cx.layout_id_buffer.clear();
4354 cx.layout_id_buffer.extend(children);
4355 let rem_size = self.rem_size();
4356 let scale_factor = self.scale_factor();
4357
4358 self.layout_engine.as_mut().unwrap().request_layout(
4359 style,
4360 rem_size,
4361 scale_factor,
4362 &cx.layout_id_buffer,
4363 )
4364 }
4365
4366 pub fn request_measured_layout<
4375 F: FnMut(Size<Option<Pixels>>, Size<AvailableSpace>, &mut Window, &mut App) -> Size<Pixels>
4376 + 'static,
4377 >(
4378 &mut self,
4379 style: Style,
4380 measure: F,
4381 ) -> LayoutId {
4382 self.invalidator.debug_assert_prepaint();
4383
4384 let rem_size = self.rem_size();
4385 let scale_factor = self.scale_factor();
4386 self.layout_engine
4387 .as_mut()
4388 .unwrap()
4389 .request_measured_layout(style, rem_size, scale_factor, measure)
4390 }
4391
4392 pub fn compute_layout(
4398 &mut self,
4399 layout_id: LayoutId,
4400 available_space: Size<AvailableSpace>,
4401 cx: &mut App,
4402 ) {
4403 self.invalidator.debug_assert_prepaint();
4404
4405 let mut layout_engine = self.layout_engine.take().unwrap();
4406 layout_engine.compute_layout(layout_id, available_space, self, cx);
4407 self.layout_engine = Some(layout_engine);
4408 }
4409
4410 pub fn layout_bounds(&mut self, layout_id: LayoutId) -> Bounds<Pixels> {
4415 self.invalidator.debug_assert_prepaint();
4416
4417 let scale_factor = self.scale_factor();
4418 let mut bounds = self
4419 .layout_engine
4420 .as_mut()
4421 .unwrap()
4422 .layout_bounds(layout_id, scale_factor)
4423 .map(Into::into);
4424 bounds.origin += self.pixel_snap_point(self.element_offset());
4425 bounds
4426 }
4427
4428 pub fn insert_hitbox(&mut self, bounds: Bounds<Pixels>, behavior: HitboxBehavior) -> Hitbox {
4434 self.invalidator.debug_assert_prepaint();
4435
4436 let content_mask = self.content_mask();
4437 let mut id = self.next_hitbox_id;
4438 self.next_hitbox_id = self.next_hitbox_id.next();
4439 let hitbox = Hitbox {
4440 id,
4441 bounds,
4442 content_mask,
4443 behavior,
4444 };
4445 self.next_frame.hitboxes.push(hitbox.clone());
4446 hitbox
4447 }
4448
4449 pub fn insert_window_control_hitbox(&mut self, area: WindowControlArea, hitbox: Hitbox) {
4453 self.invalidator.debug_assert_paint();
4454 self.next_frame.window_control_hitboxes.push((area, hitbox));
4455 }
4456
4457 pub fn set_key_context(&mut self, context: KeyContext) {
4462 self.invalidator.debug_assert_paint();
4463 self.next_frame.dispatch_tree.set_key_context(context);
4464 }
4465
4466 pub fn set_focus_handle(&mut self, focus_handle: &FocusHandle, _: &App) {
4471 self.invalidator.debug_assert_prepaint();
4472 if focus_handle.is_focused(self) {
4473 self.next_frame.focus = Some(focus_handle.id);
4474 }
4475 self.next_frame.dispatch_tree.set_focus_id(focus_handle.id);
4476 }
4477
4478 pub fn set_view_id(&mut self, view_id: EntityId) {
4484 self.invalidator.debug_assert_prepaint();
4485 self.next_frame.dispatch_tree.set_view_id(view_id);
4486 }
4487
4488 pub fn current_view(&self) -> EntityId {
4490 self.invalidator.debug_assert_paint_or_prepaint();
4491 self.rendered_entity_stack.last().copied().unwrap()
4492 }
4493
4494 pub(crate) fn with_rendered_view<R>(
4495 &mut self,
4496 id: EntityId,
4497 f: impl FnOnce(&mut Self) -> R,
4498 ) -> R {
4499 self.rendered_entity_stack.push(id);
4500 let result = f(self);
4501 self.rendered_entity_stack.pop();
4502 result
4503 }
4504
4505 pub fn with_image_cache<F, R>(&mut self, image_cache: Option<AnyImageCache>, f: F) -> R
4507 where
4508 F: FnOnce(&mut Self) -> R,
4509 {
4510 if let Some(image_cache) = image_cache {
4511 self.image_cache_stack.push(image_cache);
4512 let result = f(self);
4513 self.image_cache_stack.pop();
4514 result
4515 } else {
4516 f(self)
4517 }
4518 }
4519
4520 pub fn handle_input(
4529 &mut self,
4530 focus_handle: &FocusHandle,
4531 input_handler: impl InputHandler,
4532 cx: &App,
4533 ) {
4534 self.invalidator.debug_assert_paint();
4535
4536 if focus_handle.is_focused(self) {
4537 let cx = self.to_async(cx);
4538 self.next_frame
4539 .input_handlers
4540 .push(Some(PlatformInputHandler::new(cx, Box::new(input_handler))));
4541 }
4542 }
4543
4544 pub fn on_mouse_event<Event: MouseEvent>(
4550 &mut self,
4551 mut handler: impl FnMut(&Event, DispatchPhase, &mut Window, &mut App) + 'static,
4552 ) {
4553 self.invalidator.debug_assert_paint();
4554
4555 self.next_frame.mouse_listeners.push(Some(Box::new(
4556 move |event: &dyn Any, phase: DispatchPhase, window: &mut Window, cx: &mut App| {
4557 if let Some(event) = event.downcast_ref() {
4558 handler(event, phase, window, cx)
4559 }
4560 },
4561 )));
4562 }
4563
4564 pub fn on_key_event<Event: KeyEvent>(
4573 &mut self,
4574 listener: impl Fn(&Event, DispatchPhase, &mut Window, &mut App) + 'static,
4575 ) {
4576 self.invalidator.debug_assert_paint();
4577
4578 self.next_frame.dispatch_tree.on_key_event(Rc::new(
4579 move |event: &dyn Any, phase, window: &mut Window, cx: &mut App| {
4580 if let Some(event) = event.downcast_ref::<Event>() {
4581 listener(event, phase, window, cx)
4582 }
4583 },
4584 ));
4585 }
4586
4587 pub fn on_modifiers_changed(
4594 &mut self,
4595 listener: impl Fn(&ModifiersChangedEvent, &mut Window, &mut App) + 'static,
4596 ) {
4597 self.invalidator.debug_assert_paint();
4598
4599 self.next_frame.dispatch_tree.on_modifiers_changed(Rc::new(
4600 move |event: &ModifiersChangedEvent, window: &mut Window, cx: &mut App| {
4601 listener(event, window, cx)
4602 },
4603 ));
4604 }
4605
4606 pub fn on_focus_in(
4610 &mut self,
4611 handle: &FocusHandle,
4612 cx: &mut App,
4613 mut listener: impl FnMut(&mut Window, &mut App) + 'static,
4614 ) -> Subscription {
4615 let focus_id = handle.id;
4616 let (subscription, activate) =
4617 self.new_focus_listener(Box::new(move |event, window, cx| {
4618 if event.is_focus_in(focus_id) {
4619 listener(window, cx);
4620 }
4621 true
4622 }));
4623 cx.defer(move |_| activate());
4624 subscription
4625 }
4626
4627 pub fn on_focus_out(
4630 &mut self,
4631 handle: &FocusHandle,
4632 cx: &mut App,
4633 mut listener: impl FnMut(FocusOutEvent, &mut Window, &mut App) + 'static,
4634 ) -> Subscription {
4635 let focus_id = handle.id;
4636 let (subscription, activate) =
4637 self.new_focus_listener(Box::new(move |event, window, cx| {
4638 if let Some(blurred_id) = event.previous_focus_path.last().copied()
4639 && event.is_focus_out(focus_id)
4640 {
4641 let event = FocusOutEvent {
4642 blurred: WeakFocusHandle {
4643 id: blurred_id,
4644 handles: Arc::downgrade(&cx.focus_handles),
4645 },
4646 };
4647 listener(event, window, cx)
4648 }
4649 true
4650 }));
4651 cx.defer(move |_| activate());
4652 subscription
4653 }
4654
4655 fn reset_cursor_style(&self, cx: &mut App) {
4656 if self.is_window_hovered() {
4658 let style = self
4659 .rendered_frame
4660 .cursor_style(self)
4661 .unwrap_or(CursorStyle::Arrow);
4662 self.platform_window.set_cursor_style(style);
4668 cx.platform.set_cursor_style(style);
4669 }
4670 }
4671
4672 pub fn dispatch_keystroke(&mut self, keystroke: Keystroke, cx: &mut App) -> bool {
4675 let keystroke = keystroke.with_simulated_ime();
4676 let result = self.dispatch_event(
4677 PlatformInput::KeyDown(KeyDownEvent {
4678 keystroke: keystroke.clone(),
4679 is_held: false,
4680 prefer_character_input: false,
4681 }),
4682 cx,
4683 );
4684 if !result.propagate {
4685 return true;
4686 }
4687
4688 if let Some(input) = keystroke.key_char
4689 && let Some(mut input_handler) = self.platform_window.take_input_handler()
4690 {
4691 input_handler.dispatch_input(&input, self, cx);
4692 self.platform_window.set_input_handler(input_handler);
4693 return true;
4694 }
4695
4696 false
4697 }
4698
4699 pub fn keystroke_text_for(&self, action: &dyn Action) -> String {
4702 self.highest_precedence_binding_for_action(action)
4703 .map(|binding| {
4704 binding
4705 .keystrokes()
4706 .iter()
4707 .map(ToString::to_string)
4708 .collect::<Vec<_>>()
4709 .join(" ")
4710 })
4711 .unwrap_or_else(|| action.name().to_string())
4712 }
4713
4714 #[profiling::function]
4716 pub fn dispatch_event(&mut self, event: PlatformInput, cx: &mut App) -> DispatchEventResult {
4717 #[cfg(feature = "input-latency-histogram")]
4718 let dispatch_time = Instant::now();
4719 let update_count_before = self.invalidator.update_count();
4720
4721 cx.propagate_event = true;
4723 self.default_prevented = false;
4725
4726 let event = match event {
4727 PlatformInput::MouseMove(mouse_move) => {
4730 self.mouse_position = mouse_move.position;
4731 self.modifiers = mouse_move.modifiers;
4732 PlatformInput::MouseMove(mouse_move)
4733 }
4734 PlatformInput::MouseDown(mouse_down) => {
4735 self.mouse_position = mouse_down.position;
4736 self.modifiers = mouse_down.modifiers;
4737 PlatformInput::MouseDown(mouse_down)
4738 }
4739 PlatformInput::MouseUp(mouse_up) => {
4740 self.mouse_position = mouse_up.position;
4741 self.modifiers = mouse_up.modifiers;
4742 PlatformInput::MouseUp(mouse_up)
4743 }
4744 PlatformInput::MouseExited(mouse_exited) => {
4745 self.modifiers = mouse_exited.modifiers;
4746 PlatformInput::MouseExited(mouse_exited)
4747 }
4748 PlatformInput::ModifiersChanged(modifiers_changed) => {
4749 self.modifiers = modifiers_changed.modifiers;
4750 self.capslock = modifiers_changed.capslock;
4751 PlatformInput::ModifiersChanged(modifiers_changed)
4752 }
4753 PlatformInput::ScrollWheel(scroll_wheel) => {
4754 self.mouse_position = scroll_wheel.position;
4755 self.modifiers = scroll_wheel.modifiers;
4756 PlatformInput::ScrollWheel(scroll_wheel)
4757 }
4758 PlatformInput::Pinch(pinch) => {
4759 self.mouse_position = pinch.position;
4760 self.modifiers = pinch.modifiers;
4761 PlatformInput::Pinch(pinch)
4762 }
4763 PlatformInput::FileDrop(file_drop) => match file_drop {
4766 FileDropEvent::Entered { position, paths } => {
4767 self.mouse_position = position;
4768 if cx.active_drag.is_none() {
4769 cx.active_drag = Some(AnyDrag {
4770 value: Arc::new(paths.clone()),
4771 view: cx.new(|_| paths).into(),
4772 cursor_offset: position,
4773 cursor_style: None,
4774 });
4775 }
4776 PlatformInput::MouseMove(MouseMoveEvent {
4777 position,
4778 pressed_button: Some(MouseButton::Left),
4779 modifiers: Modifiers::default(),
4780 })
4781 }
4782 FileDropEvent::Pending { position } => {
4783 self.mouse_position = position;
4784 PlatformInput::MouseMove(MouseMoveEvent {
4785 position,
4786 pressed_button: Some(MouseButton::Left),
4787 modifiers: Modifiers::default(),
4788 })
4789 }
4790 FileDropEvent::Submit { position } => {
4791 cx.activate(true);
4792 self.mouse_position = position;
4793 PlatformInput::MouseUp(MouseUpEvent {
4794 button: MouseButton::Left,
4795 position,
4796 modifiers: Modifiers::default(),
4797 click_count: 1,
4798 })
4799 }
4800 FileDropEvent::Exited => {
4801 cx.active_drag.take();
4802 PlatformInput::FileDrop(FileDropEvent::Exited)
4803 }
4804 },
4805 PlatformInput::KeyDown(_) | PlatformInput::KeyUp(_) => event,
4806 };
4807
4808 if let Some(any_mouse_event) = event.mouse_event() {
4809 self.dispatch_mouse_event(any_mouse_event, cx);
4810 } else if let Some(any_key_event) = event.keyboard_event() {
4811 self.dispatch_key_event(any_key_event, cx);
4812 }
4813
4814 if self.invalidator.update_count() > update_count_before {
4815 self.input_rate_tracker.borrow_mut().record_input();
4816 #[cfg(feature = "input-latency-histogram")]
4817 if self.invalidator.not_drawing() {
4818 self.input_latency_tracker.record_input(dispatch_time);
4819 } else {
4820 self.input_latency_tracker.record_mid_draw_input();
4821 }
4822 }
4823
4824 DispatchEventResult {
4825 propagate: cx.propagate_event,
4826 default_prevented: self.default_prevented,
4827 }
4828 }
4829
4830 fn dispatch_mouse_event(&mut self, event: &dyn Any, cx: &mut App) {
4831 self.last_input_was_keyboard.set(false);
4832
4833 let hit_test = self.rendered_frame.hit_test(self.mouse_position());
4834 if hit_test != self.mouse_hit_test {
4835 self.mouse_hit_test = hit_test;
4836 self.reset_cursor_style(cx);
4837 }
4838
4839 #[cfg(any(feature = "inspector", debug_assertions))]
4840 if self.is_inspector_picking(cx) {
4841 self.handle_inspector_mouse_event(event, cx);
4842 return;
4844 }
4845
4846 let mut mouse_listeners = mem::take(&mut self.rendered_frame.mouse_listeners);
4847
4848 for listener in &mut mouse_listeners {
4851 let listener = listener.as_mut().unwrap();
4852 listener(event, DispatchPhase::Capture, self, cx);
4853 if !cx.propagate_event {
4854 break;
4855 }
4856 }
4857
4858 if cx.propagate_event {
4860 for listener in mouse_listeners.iter_mut().rev() {
4861 let listener = listener.as_mut().unwrap();
4862 listener(event, DispatchPhase::Bubble, self, cx);
4863 if !cx.propagate_event {
4864 break;
4865 }
4866 }
4867 }
4868
4869 self.rendered_frame.mouse_listeners = mouse_listeners;
4870
4871 if cx.has_active_drag() {
4872 if event.is::<MouseMoveEvent>() {
4873 self.refresh();
4876 } else if event.is::<MouseUpEvent>() {
4877 cx.active_drag = None;
4880 self.refresh();
4881 }
4882 }
4883
4884 if event.is::<MouseUpEvent>() && self.captured_hitbox.is_some() {
4885 self.captured_hitbox = None;
4886 }
4887 }
4888
4889 fn dispatch_key_event(&mut self, event: &dyn Any, cx: &mut App) {
4890 self.last_input_was_keyboard.set(true);
4891
4892 if self.invalidator.is_dirty() {
4893 self.draw(cx).clear();
4894 }
4895
4896 let node_id = self.focus_node_id_in_rendered_frame(self.focus);
4897 let dispatch_path = self.rendered_frame.dispatch_tree.dispatch_path(node_id);
4898
4899 let mut keystroke: Option<Keystroke> = None;
4900
4901 if let Some(event) = event.downcast_ref::<ModifiersChangedEvent>() {
4902 if event.modifiers.number_of_modifiers() == 0
4903 && self.pending_modifier.modifiers.number_of_modifiers() == 1
4904 && !self.pending_modifier.saw_other_input
4905 {
4906 let key = match self.pending_modifier.modifiers {
4907 modifiers if modifiers.shift => Some("shift"),
4908 modifiers if modifiers.control => Some("control"),
4909 modifiers if modifiers.alt => Some("alt"),
4910 modifiers if modifiers.platform => Some("platform"),
4911 modifiers if modifiers.function => Some("function"),
4912 _ => None,
4913 };
4914 if let Some(key) = key {
4915 keystroke = Some(Keystroke {
4916 key: key.to_string(),
4917 key_char: None,
4918 modifiers: Modifiers::default(),
4919 });
4920 }
4921 }
4922
4923 if self.pending_modifier.modifiers.number_of_modifiers() == 0
4924 && event.modifiers.number_of_modifiers() == 1
4925 {
4926 self.pending_modifier.saw_other_input = false
4927 } else if event.modifiers.number_of_modifiers() > 1 {
4928 self.pending_modifier.saw_other_input = true
4929 }
4930 self.pending_modifier.modifiers = event.modifiers
4931 } else if let Some(key_down_event) = event.downcast_ref::<KeyDownEvent>() {
4932 self.pending_modifier.saw_other_input = true;
4933 keystroke = Some(key_down_event.keystroke.clone());
4934 }
4935
4936 let Some(keystroke) = keystroke else {
4937 self.finish_dispatch_key_event(
4938 event,
4939 None,
4940 InputPreference::KeyBindings,
4941 dispatch_path,
4942 self.context_stack(),
4943 cx,
4944 );
4945 return;
4946 };
4947
4948 let input_preference = self.input_preference(event, cx);
4949
4950 cx.propagate_event = true;
4951 self.dispatch_keystroke_interceptors(
4952 &keystroke,
4953 input_preference,
4954 self.context_stack(),
4955 cx,
4956 );
4957 if !cx.propagate_event {
4958 self.finish_dispatch_key_event(
4959 event,
4960 Some(&keystroke),
4961 input_preference,
4962 dispatch_path,
4963 self.context_stack(),
4964 cx,
4965 );
4966 return;
4967 }
4968
4969 let mut currently_pending = self.pending_input.take().unwrap_or_default();
4970 if currently_pending.focus.is_some() && currently_pending.focus != self.focus {
4971 currently_pending = PendingInput::default();
4972 }
4973
4974 let match_result = self.rendered_frame.dispatch_tree.dispatch_key(
4975 currently_pending.keystrokes,
4976 keystroke.clone(),
4977 &dispatch_path,
4978 );
4979
4980 if !match_result.to_replay.is_empty() {
4981 self.replay_pending_input(match_result.to_replay, cx);
4982 cx.propagate_event = true;
4983 }
4984
4985 if !match_result.pending.is_empty() {
4986 let previous_timeout = currently_pending.timeout.take();
4987 currently_pending.keystrokes = match_result.pending;
4988 currently_pending.focus = self.focus;
4989
4990 currently_pending.timeout = match previous_timeout {
4994 Some(mut timeout) if timeout.is_paused() => {
4995 timeout.reset_duration(PENDING_INPUT_TIMEOUT);
4996 Some(timeout)
4997 }
4998 previous_timeout => {
4999 drop(previous_timeout);
5000 Some(self.new_pending_input_timeout(PENDING_INPUT_TIMEOUT, cx))
5001 }
5002 };
5003 self.pending_input = Some(currently_pending);
5004 self.pending_input_changed(cx);
5005 cx.propagate_event = false;
5006 return;
5007 }
5008
5009 let input_preference = self.input_preference(event, cx);
5011 if input_preference == InputPreference::KeyBindings {
5012 for binding in match_result.bindings {
5013 self.dispatch_action_on_node(node_id, binding.action.as_ref(), cx);
5014 if !cx.propagate_event {
5015 self.dispatch_keystroke_observers(
5016 &keystroke,
5017 input_preference,
5018 Some(binding.action.as_ref()),
5019 match_result.context_stack,
5020 cx,
5021 );
5022 self.pending_input_changed(cx);
5023 return;
5024 }
5025 }
5026 }
5027
5028 self.finish_dispatch_key_event(
5029 event,
5030 Some(&keystroke),
5031 input_preference,
5032 dispatch_path,
5033 match_result.context_stack,
5034 cx,
5035 );
5036 self.pending_input_changed(cx);
5037 }
5038
5039 fn input_preference(&mut self, event: &dyn Any, cx: &mut App) -> InputPreference {
5042 let prefer_character_input = event
5043 .downcast_ref::<KeyDownEvent>()
5044 .is_some_and(|key_down_event| key_down_event.prefer_character_input);
5045 if !prefer_character_input {
5046 return InputPreference::KeyBindings;
5047 }
5048 let Some(mut input_handler) = self.platform_window.take_input_handler() else {
5049 return InputPreference::KeyBindings;
5050 };
5051 let accepts_text_input = input_handler.accepts_text_input(self, cx);
5052 self.platform_window.set_input_handler(input_handler);
5053 if accepts_text_input {
5054 InputPreference::CharacterInput
5055 } else {
5056 InputPreference::KeyBindings
5057 }
5058 }
5059
5060 fn new_pending_input_timeout(&self, duration: Duration, cx: &App) -> PendingInputTimeout {
5061 let (started_at, task) = self.start_pending_input_timeout(duration, cx);
5062 PendingInputTimeout {
5063 duration,
5064 remaining: duration,
5065 state: PendingInputTimeoutState::Running { started_at, task },
5066 }
5067 }
5068
5069 fn start_pending_input_timeout(&self, remaining: Duration, cx: &App) -> (Instant, Task<()>) {
5070 let started_at = cx.background_executor().now();
5071 let task = self.spawn(cx, async move |cx| {
5072 cx.background_executor.timer(remaining).await;
5073 cx.update(move |window, cx| {
5074 let Some(currently_pending) = window
5075 .pending_input
5076 .take()
5077 .filter(|pending| pending.focus == window.focus)
5078 else {
5079 return;
5080 };
5081
5082 let node_id = window.focus_node_id_in_rendered_frame(window.focus);
5083 let dispatch_path = window.rendered_frame.dispatch_tree.dispatch_path(node_id);
5084
5085 let to_replay = window
5086 .rendered_frame
5087 .dispatch_tree
5088 .flush_dispatch(currently_pending.keystrokes, &dispatch_path);
5089
5090 window.pending_input_changed(cx);
5091 window.replay_pending_input(to_replay, cx)
5092 })
5093 .log_err();
5094 });
5095 (started_at, task)
5096 }
5097
5098 fn finish_dispatch_key_event(
5099 &mut self,
5100 event: &dyn Any,
5101 recognized_keystroke: Option<&Keystroke>,
5102 input_preference: InputPreference,
5103 dispatch_path: SmallVec<[DispatchNodeId; 32]>,
5104 context_stack: Vec<KeyContext>,
5105 cx: &mut App,
5106 ) {
5107 self.dispatch_key_down_up_event(event, &dispatch_path, cx);
5108 if !cx.propagate_event {
5109 return;
5110 }
5111
5112 self.dispatch_modifiers_changed_event(event, &dispatch_path, cx);
5113 if !cx.propagate_event {
5114 return;
5115 }
5116
5117 if let Some(keystroke) = recognized_keystroke {
5118 self.dispatch_keystroke_observers(keystroke, input_preference, None, context_stack, cx);
5119 }
5120 }
5121
5122 fn pending_input_changed(&mut self, cx: &mut App) {
5123 self.pending_input_observers
5124 .clone()
5125 .retain(&(), |callback| callback(self, cx));
5126 }
5127
5128 fn dispatch_key_down_up_event(
5129 &mut self,
5130 event: &dyn Any,
5131 dispatch_path: &SmallVec<[DispatchNodeId; 32]>,
5132 cx: &mut App,
5133 ) {
5134 for node_id in dispatch_path {
5136 let node = self.rendered_frame.dispatch_tree.node(*node_id);
5137
5138 for key_listener in node.key_listeners.clone() {
5139 key_listener(event, DispatchPhase::Capture, self, cx);
5140 if !cx.propagate_event {
5141 return;
5142 }
5143 }
5144 }
5145
5146 for node_id in dispatch_path.iter().rev() {
5148 let node = self.rendered_frame.dispatch_tree.node(*node_id);
5150 for key_listener in node.key_listeners.clone() {
5151 key_listener(event, DispatchPhase::Bubble, self, cx);
5152 if !cx.propagate_event {
5153 return;
5154 }
5155 }
5156 }
5157 }
5158
5159 fn dispatch_modifiers_changed_event(
5160 &mut self,
5161 event: &dyn Any,
5162 dispatch_path: &SmallVec<[DispatchNodeId; 32]>,
5163 cx: &mut App,
5164 ) {
5165 let Some(event) = event.downcast_ref::<ModifiersChangedEvent>() else {
5166 return;
5167 };
5168 for node_id in dispatch_path.iter().rev() {
5169 let node = self.rendered_frame.dispatch_tree.node(*node_id);
5170 for listener in node.modifiers_changed_listeners.clone() {
5171 listener(event, self, cx);
5172 if !cx.propagate_event {
5173 return;
5174 }
5175 }
5176 }
5177 }
5178
5179 pub fn has_pending_keystrokes(&self) -> bool {
5181 self.pending_input().is_some()
5182 }
5183
5184 #[cfg(test)]
5185 pub(crate) fn pending_input_is_none(&self) -> bool {
5186 self.pending_input.is_none()
5187 }
5188
5189 fn defer_pending_input_changed(&self, cx: &mut App) {
5190 self.defer(cx, |window, cx| {
5193 window.pending_input_changed(cx);
5194 });
5195 }
5196
5197 pub(crate) fn clear_pending_keystrokes(&mut self, cx: &mut App) {
5198 if self.pending_input.take().is_some() {
5199 self.defer_pending_input_changed(cx);
5200 }
5201 }
5202
5203 pub fn pending_input(&self) -> Option<PendingInputStatus<'_>> {
5206 self.pending_input
5207 .as_ref()
5208 .filter(|pending_input| pending_input.focus == self.focus)
5209 .map(|pending_input| PendingInputStatus {
5210 keystrokes: pending_input.keystrokes.as_slice(),
5211 timeout: pending_input
5212 .timeout
5213 .as_ref()
5214 .map(PendingInputTimeout::status),
5215 })
5216 }
5217
5218 pub fn set_pending_input_timeout_paused<T: 'static>(
5223 &mut self,
5224 owner: &Entity<T>,
5225 paused: bool,
5226 cx: &mut App,
5227 ) -> bool {
5228 let owner_id = owner.entity_id();
5229 if !paused {
5230 return self.resume_pending_input_timeout(owner_id, cx);
5231 }
5232
5233 let timeout = self
5234 .pending_input
5235 .as_ref()
5236 .filter(|pending_input| pending_input.focus == self.focus)
5237 .and_then(|pending_input| pending_input.timeout.as_ref());
5238 let Some(timeout) = timeout else {
5239 return false;
5240 };
5241 if timeout.is_paused() {
5242 return false;
5243 }
5244
5245 let release_subscription = self.observe_release(owner, cx, move |_, window, cx| {
5246 window.resume_pending_input_timeout(owner_id, cx);
5247 });
5248 let now = cx.background_executor().now();
5249 let changed = self
5250 .pending_input
5251 .as_mut()
5252 .filter(|pending_input| pending_input.focus == self.focus)
5253 .and_then(|pending_input| pending_input.timeout.as_mut())
5254 .is_some_and(|timeout| {
5255 timeout.pause(
5256 PendingInputTimeoutPause {
5257 owner_id,
5258 _release_subscription: release_subscription,
5259 },
5260 now,
5261 )
5262 });
5263
5264 if changed {
5265 self.defer_pending_input_changed(cx);
5266 }
5267 changed
5268 }
5269
5270 fn resume_pending_input_timeout(&mut self, owner_id: EntityId, cx: &mut App) -> bool {
5271 let Some(remaining) = self
5272 .pending_input
5273 .as_ref()
5274 .filter(|pending_input| pending_input.focus == self.focus)
5275 .and_then(|pending_input| pending_input.timeout.as_ref())
5276 .filter(|timeout| timeout.pause_owner_id() == Some(owner_id))
5277 .map(|timeout| timeout.remaining)
5278 else {
5279 return false;
5280 };
5281
5282 let (started_at, task) = self.start_pending_input_timeout(remaining, cx);
5283 let changed = self
5284 .pending_input
5285 .as_mut()
5286 .filter(|pending_input| pending_input.focus == self.focus)
5287 .and_then(|pending_input| pending_input.timeout.as_mut())
5288 .is_some_and(|timeout| timeout.resume(owner_id, started_at, task));
5289
5290 if changed {
5291 self.defer_pending_input_changed(cx);
5292 }
5293 changed
5294 }
5295
5296 pub fn pending_input_keystrokes(&self) -> Option<&[Keystroke]> {
5298 self.pending_input()
5299 .map(|pending_input| pending_input.keystrokes())
5300 }
5301
5302 fn replay_pending_input(&mut self, replays: SmallVec<[Replay; 1]>, cx: &mut App) {
5303 let node_id = self.focus_node_id_in_rendered_frame(self.focus);
5304 let dispatch_path = self.rendered_frame.dispatch_tree.dispatch_path(node_id);
5305
5306 'replay: for replay in replays {
5307 let event = KeyDownEvent {
5308 keystroke: replay.keystroke.clone(),
5309 is_held: false,
5310 prefer_character_input: true,
5311 };
5312
5313 cx.propagate_event = true;
5314 for binding in replay.bindings {
5315 self.dispatch_action_on_node(node_id, binding.action.as_ref(), cx);
5316 if !cx.propagate_event {
5317 self.dispatch_keystroke_observers(
5318 &replay.keystroke,
5319 InputPreference::KeyBindings,
5320 Some(binding.action.as_ref()),
5321 Vec::default(),
5322 cx,
5323 );
5324 continue 'replay;
5325 }
5326 }
5327
5328 self.dispatch_key_down_up_event(&event, &dispatch_path, cx);
5329 if !cx.propagate_event {
5330 continue 'replay;
5331 }
5332 if let Some(input) = replay.keystroke.key_char.as_ref().cloned()
5333 && let Some(mut input_handler) = self.platform_window.take_input_handler()
5334 {
5335 input_handler.dispatch_input(&input, self, cx);
5336 self.platform_window.set_input_handler(input_handler)
5337 }
5338 }
5339 }
5340
5341 fn focus_node_id_in_rendered_frame(&self, focus_id: Option<FocusId>) -> DispatchNodeId {
5342 focus_id
5343 .and_then(|focus_id| {
5344 self.rendered_frame
5345 .dispatch_tree
5346 .focusable_node_id(focus_id)
5347 })
5348 .unwrap_or_else(|| self.rendered_frame.dispatch_tree.root_node_id())
5349 }
5350
5351 fn dispatch_action_on_node(
5352 &mut self,
5353 node_id: DispatchNodeId,
5354 action: &dyn Action,
5355 cx: &mut App,
5356 ) {
5357 let dispatch_path = self.rendered_frame.dispatch_tree.dispatch_path(node_id);
5358
5359 cx.propagate_event = true;
5361 if let Some(mut global_listeners) = cx
5362 .global_action_listeners
5363 .remove(&action.as_any().type_id())
5364 {
5365 for listener in &global_listeners {
5366 listener(action.as_any(), DispatchPhase::Capture, cx);
5367 if !cx.propagate_event {
5368 break;
5369 }
5370 }
5371
5372 global_listeners.extend(
5373 cx.global_action_listeners
5374 .remove(&action.as_any().type_id())
5375 .unwrap_or_default(),
5376 );
5377
5378 cx.global_action_listeners
5379 .insert(action.as_any().type_id(), global_listeners);
5380 }
5381
5382 if !cx.propagate_event {
5383 return;
5384 }
5385
5386 for node_id in &dispatch_path {
5388 let node = self.rendered_frame.dispatch_tree.node(*node_id);
5389 for DispatchActionListener {
5390 action_type,
5391 listener,
5392 } in node.action_listeners.clone()
5393 {
5394 let any_action = action.as_any();
5395 if action_type == any_action.type_id() {
5396 listener(any_action, DispatchPhase::Capture, self, cx);
5397
5398 if !cx.propagate_event {
5399 return;
5400 }
5401 }
5402 }
5403 }
5404
5405 for node_id in dispatch_path.iter().rev() {
5407 let node = self.rendered_frame.dispatch_tree.node(*node_id);
5408 for DispatchActionListener {
5409 action_type,
5410 listener,
5411 } in node.action_listeners.clone()
5412 {
5413 let any_action = action.as_any();
5414 if action_type == any_action.type_id() {
5415 cx.propagate_event = false; listener(any_action, DispatchPhase::Bubble, self, cx);
5417
5418 if !cx.propagate_event {
5419 return;
5420 }
5421 }
5422 }
5423 }
5424
5425 if let Some(mut global_listeners) = cx
5427 .global_action_listeners
5428 .remove(&action.as_any().type_id())
5429 {
5430 for listener in global_listeners.iter().rev() {
5431 cx.propagate_event = false; listener(action.as_any(), DispatchPhase::Bubble, cx);
5434 if !cx.propagate_event {
5435 break;
5436 }
5437 }
5438
5439 global_listeners.extend(
5440 cx.global_action_listeners
5441 .remove(&action.as_any().type_id())
5442 .unwrap_or_default(),
5443 );
5444
5445 cx.global_action_listeners
5446 .insert(action.as_any().type_id(), global_listeners);
5447 }
5448 }
5449
5450 pub fn observe_global<G: Global>(
5453 &mut self,
5454 cx: &mut App,
5455 f: impl Fn(&mut Window, &mut App) + 'static,
5456 ) -> Subscription {
5457 let window_handle = self.handle;
5458 let (subscription, activate) = cx.global_observers.insert(
5459 TypeId::of::<G>(),
5460 Box::new(move |cx| {
5461 window_handle
5462 .update(cx, |_, window, cx| f(window, cx))
5463 .is_ok()
5464 }),
5465 );
5466 cx.defer(move |_| activate());
5467 subscription
5468 }
5469
5470 pub fn activate_window(&self) {
5472 self.platform_window.activate();
5473 }
5474
5475 pub fn request_attention(&self) {
5477 self.platform_window.request_attention();
5478 }
5479
5480 pub fn minimize_window(&self) {
5482 self.platform_window.minimize();
5483 }
5484
5485 pub fn show_window(&self) {
5487 self.platform_window.show();
5488 }
5489
5490 pub fn hide_window(&self) {
5492 self.platform_window.hide();
5493 }
5494
5495 pub fn is_window_visible(&self) -> bool {
5497 self.platform_window.is_visible()
5498 }
5499
5500 pub fn set_mouse_passthrough(&self, passthrough: bool) {
5502 self.platform_window.set_mouse_passthrough(passthrough);
5503 }
5504
5505 pub fn set_input_region(&self, region: Option<&[Bounds<Pixels>]>) {
5512 self.platform_window.set_input_region(region);
5513 }
5514
5515 pub fn toggle_fullscreen(&self) {
5517 self.platform_window.toggle_fullscreen();
5518 }
5519
5520 pub fn toggle_simple_fullscreen(&self) {
5525 self.platform_window.toggle_simple_fullscreen();
5526 }
5527
5528 pub fn set_progress_bar(&self, state: ProgressBarState) {
5530 self.platform_window.set_progress_bar(state);
5531 }
5532
5533 pub fn window_state(&self) -> WindowState {
5535 let bounds = self.platform_window.window_bounds();
5536 let display_id = self.platform_window.display().map(|d| d.id());
5537 let fullscreen = self.platform_window.is_fullscreen();
5538 WindowState {
5539 bounds,
5540 display_id,
5541 fullscreen,
5542 }
5543 }
5544
5545 pub fn restore_window_state(&self, state: &WindowState) {
5551 let is_fullscreen = self.platform_window.is_fullscreen();
5552 if state.fullscreen != is_fullscreen {
5553 self.platform_window.toggle_fullscreen();
5554 }
5555 }
5556
5557 pub fn invalidate_character_coordinates(&self) {
5559 self.on_next_frame(|window, cx| {
5560 if let Some(mut input_handler) = window.platform_window.take_input_handler() {
5561 if let Some(bounds) = input_handler.selected_bounds(window, cx) {
5562 window.platform_window.update_ime_position(bounds);
5563 }
5564 window.platform_window.set_input_handler(input_handler);
5565 }
5566 });
5567 }
5568
5569 pub fn prompt<T>(
5573 &mut self,
5574 level: PromptLevel,
5575 message: &str,
5576 detail: Option<&str>,
5577 answers: &[T],
5578 cx: &mut App,
5579 ) -> oneshot::Receiver<usize>
5580 where
5581 T: Clone + Into<PromptButton>,
5582 {
5583 let prompt_builder = cx.prompt_builder.take();
5584 let Some(prompt_builder) = prompt_builder else {
5585 unreachable!("Re-entrant window prompting is not supported by GPUI");
5586 };
5587
5588 let answers = answers
5589 .iter()
5590 .map(|answer| answer.clone().into())
5591 .collect::<Vec<_>>();
5592
5593 let receiver = match &prompt_builder {
5594 PromptBuilder::Default => self
5595 .platform_window
5596 .prompt(level, message, detail, &answers)
5597 .unwrap_or_else(|| {
5598 self.build_custom_prompt(&prompt_builder, level, message, detail, &answers, cx)
5599 }),
5600 PromptBuilder::Custom(_) => {
5601 self.build_custom_prompt(&prompt_builder, level, message, detail, &answers, cx)
5602 }
5603 };
5604
5605 cx.prompt_builder = Some(prompt_builder);
5606
5607 receiver
5608 }
5609
5610 fn build_custom_prompt(
5611 &mut self,
5612 prompt_builder: &PromptBuilder,
5613 level: PromptLevel,
5614 message: &str,
5615 detail: Option<&str>,
5616 answers: &[PromptButton],
5617 cx: &mut App,
5618 ) -> oneshot::Receiver<usize> {
5619 let (sender, receiver) = oneshot::channel();
5620 let handle = PromptHandle::new(sender);
5621 let handle = (prompt_builder)(level, message, detail, answers, handle, self, cx);
5622 self.prompt = Some(handle);
5623 receiver
5624 }
5625
5626 pub fn has_active_prompt(&self) -> bool {
5630 self.prompt.is_some()
5631 }
5632
5633 pub fn context_stack(&self) -> Vec<KeyContext> {
5635 let node_id = self.focus_node_id_in_rendered_frame(self.focus);
5636 let dispatch_tree = &self.rendered_frame.dispatch_tree;
5637 dispatch_tree
5638 .dispatch_path(node_id)
5639 .iter()
5640 .filter_map(move |&node_id| dispatch_tree.node(node_id).context.clone())
5641 .collect()
5642 }
5643
5644 pub fn available_actions(&self, cx: &App) -> Vec<Box<dyn Action>> {
5646 let node_id = self.focus_node_id_in_rendered_frame(self.focus);
5647 let mut actions = self.rendered_frame.dispatch_tree.available_actions(node_id);
5648 for action_type in cx.global_action_listeners.keys() {
5649 if let Err(ix) = actions.binary_search_by_key(action_type, |a| a.as_any().type_id()) {
5650 let action = cx.actions.build_action_type(action_type).ok();
5651 if let Some(action) = action {
5652 actions.insert(ix, action);
5653 }
5654 }
5655 }
5656 actions
5657 }
5658
5659 pub fn bindings_for_action(&self, action: &dyn Action) -> Vec<KeyBinding> {
5662 self.rendered_frame
5663 .dispatch_tree
5664 .bindings_for_action(action, &self.rendered_frame.dispatch_tree.context_stack)
5665 }
5666
5667 pub fn highest_precedence_binding_for_action(&self, action: &dyn Action) -> Option<KeyBinding> {
5670 self.rendered_frame
5671 .dispatch_tree
5672 .highest_precedence_binding_for_action(
5673 action,
5674 &self.rendered_frame.dispatch_tree.context_stack,
5675 )
5676 }
5677
5678 pub fn bindings_for_action_in_context(
5680 &self,
5681 action: &dyn Action,
5682 context: KeyContext,
5683 ) -> Vec<KeyBinding> {
5684 let dispatch_tree = &self.rendered_frame.dispatch_tree;
5685 dispatch_tree.bindings_for_action(action, &[context])
5686 }
5687
5688 pub fn highest_precedence_binding_for_action_in_context(
5691 &self,
5692 action: &dyn Action,
5693 context: KeyContext,
5694 ) -> Option<KeyBinding> {
5695 let dispatch_tree = &self.rendered_frame.dispatch_tree;
5696 dispatch_tree.highest_precedence_binding_for_action(action, &[context])
5697 }
5698
5699 pub fn bindings_for_action_in(
5703 &self,
5704 action: &dyn Action,
5705 focus_handle: &FocusHandle,
5706 ) -> Vec<KeyBinding> {
5707 let dispatch_tree = &self.rendered_frame.dispatch_tree;
5708 let Some(context_stack) = self.context_stack_for_focus_handle(focus_handle) else {
5709 return vec![];
5710 };
5711 dispatch_tree.bindings_for_action(action, &context_stack)
5712 }
5713
5714 pub fn highest_precedence_binding_for_action_in(
5718 &self,
5719 action: &dyn Action,
5720 focus_handle: &FocusHandle,
5721 ) -> Option<KeyBinding> {
5722 let dispatch_tree = &self.rendered_frame.dispatch_tree;
5723 let context_stack = self.context_stack_for_focus_handle(focus_handle)?;
5724 dispatch_tree.highest_precedence_binding_for_action(action, &context_stack)
5725 }
5726
5727 fn context_stack_for_focus_handle(
5728 &self,
5729 focus_handle: &FocusHandle,
5730 ) -> Option<Vec<KeyContext>> {
5731 let dispatch_tree = &self.rendered_frame.dispatch_tree;
5732 let node_id = dispatch_tree.focusable_node_id(focus_handle.id)?;
5733 let context_stack: Vec<_> = dispatch_tree
5734 .dispatch_path(node_id)
5735 .into_iter()
5736 .filter_map(|node_id| dispatch_tree.node(node_id).context.clone())
5737 .collect();
5738 Some(context_stack)
5739 }
5740
5741 pub fn listener_for<V: Render, E>(
5743 &self,
5744 view: &Entity<V>,
5745 f: impl Fn(&mut V, &E, &mut Window, &mut Context<V>) + 'static,
5746 ) -> impl Fn(&E, &mut Window, &mut App) + 'static {
5747 let view = view.downgrade();
5748 move |e: &E, window: &mut Window, cx: &mut App| {
5749 view.update(cx, |view, cx| f(view, e, window, cx)).ok();
5750 }
5751 }
5752
5753 pub fn handler_for<V: Render, Callback: Fn(&mut V, &mut Window, &mut Context<V>) + 'static>(
5755 &self,
5756 view: &Entity<V>,
5757 f: Callback,
5758 ) -> impl Fn(&mut Window, &mut App) + use<V, Callback> {
5759 let view = view.downgrade();
5760 move |window: &mut Window, cx: &mut App| {
5761 view.update(cx, |view, cx| f(view, window, cx)).ok();
5762 }
5763 }
5764
5765 pub fn on_window_should_close(
5768 &self,
5769 cx: &App,
5770 f: impl Fn(&mut Window, &mut App) -> bool + 'static,
5771 ) {
5772 let mut cx = self.to_async(cx);
5773 self.platform_window.on_should_close(Box::new(move || {
5774 cx.update(|window, cx| f(window, cx)).unwrap_or(true)
5775 }))
5776 }
5777
5778 pub fn on_action(
5785 &mut self,
5786 action_type: TypeId,
5787 listener: impl Fn(&dyn Any, DispatchPhase, &mut Window, &mut App) + 'static,
5788 ) {
5789 self.next_frame
5790 .dispatch_tree
5791 .on_action(action_type, Rc::new(listener));
5792 }
5793
5794 pub fn on_action_when(
5801 &mut self,
5802 condition: bool,
5803 action_type: TypeId,
5804 listener: impl Fn(&dyn Any, DispatchPhase, &mut Window, &mut App) + 'static,
5805 ) {
5806 if condition {
5807 self.next_frame
5808 .dispatch_tree
5809 .on_action(action_type, Rc::new(listener));
5810 }
5811 }
5812
5813 pub fn gpu_specs(&self) -> Option<GpuSpecs> {
5816 self.platform_window.gpu_specs()
5817 }
5818
5819 pub fn titlebar_double_click(&self) {
5822 self.platform_window.titlebar_double_click();
5823 }
5824
5825 pub fn window_title(&self) -> String {
5828 self.platform_window.get_title()
5829 }
5830
5831 pub fn tabbed_windows(&self) -> Option<Vec<SystemWindowTab>> {
5834 self.platform_window.tabbed_windows()
5835 }
5836
5837 pub fn tab_bar_visible(&self) -> bool {
5840 self.platform_window.tab_bar_visible()
5841 }
5842
5843 pub fn merge_all_windows(&self) {
5846 self.platform_window.merge_all_windows()
5847 }
5848
5849 pub fn move_tab_to_new_window(&self) {
5852 self.platform_window.move_tab_to_new_window()
5853 }
5854
5855 pub fn toggle_window_tab_overview(&self) {
5858 self.platform_window.toggle_window_tab_overview()
5859 }
5860
5861 pub fn set_tabbing_identifier(&self, tabbing_identifier: Option<String>) {
5864 self.platform_window
5865 .set_tabbing_identifier(tabbing_identifier)
5866 }
5867
5868 pub fn play_system_bell(&self) {
5870 self.platform_window.play_system_bell()
5871 }
5872
5873 pub fn is_a11y_enabled(&self) -> bool {
5880 self.a11y.is_enabled()
5881 }
5882
5883 pub fn debug_a11y_tree_json(&self) -> Option<String> {
5887 self.a11y.debug_tree_json()
5888 }
5889
5890 pub fn on_a11y_action(
5894 &mut self,
5895 node_id: accesskit::NodeId,
5896 action: accesskit::Action,
5897 listener: impl FnMut(Option<&accesskit::ActionData>, &mut Window, &mut App) + 'static,
5898 ) {
5899 self.a11y
5900 .action_listeners
5901 .entry(node_id)
5902 .or_default()
5903 .push((action, Box::new(listener)));
5904 }
5905
5906 #[cfg(not(target_family = "wasm"))]
5907 pub(crate) fn handle_a11y_action(&mut self, request: accesskit::ActionRequest, cx: &mut App) {
5908 if let Some(mut listeners) = self.a11y.action_listeners.remove(&request.target_node) {
5909 let action_data = request.data.as_ref();
5910 let mut matched = false;
5911 for (action, listener) in &mut listeners {
5912 if *action == request.action {
5913 listener(action_data, self, cx);
5914 matched = true;
5915 }
5916 }
5917 self.a11y
5918 .action_listeners
5919 .insert(request.target_node, listeners);
5920 if matched {
5921 return;
5922 }
5923 }
5924
5925 match request.action {
5926 accesskit::Action::Click => {
5927 if let Some(bounds) = self.a11y.node_bounds.get(&request.target_node).copied() {
5928 let center = bounds.center();
5929 self.dispatch_event(
5930 PlatformInput::MouseDown(crate::MouseDownEvent {
5931 button: MouseButton::Left,
5932 position: center,
5933 modifiers: Modifiers::default(),
5934 click_count: 1,
5935 first_mouse: false,
5936 }),
5937 cx,
5938 );
5939 self.dispatch_event(
5940 PlatformInput::MouseUp(MouseUpEvent {
5941 button: MouseButton::Left,
5942 position: center,
5943 modifiers: Modifiers::default(),
5944 click_count: 1,
5945 }),
5946 cx,
5947 );
5948 }
5949 }
5950 accesskit::Action::Focus => {
5951 if let Some(focus_id) = self.a11y.focus_ids.get(&request.target_node).copied()
5952 && let Some(handle) = FocusHandle::for_id(focus_id, &cx.focus_handles)
5953 {
5954 self.focus(&handle);
5955 }
5956 }
5957 accesskit::Action::Blur => self.blur(cx),
5958 _ => {
5959 log::debug!(
5960 "Unhandled a11y action: {:?} on {:?}",
5961 request.action,
5962 request.target_node
5963 );
5964 }
5965 }
5966 }
5967
5968 #[cfg(any(feature = "inspector", debug_assertions))]
5970 pub fn toggle_inspector(&mut self, cx: &mut App) {
5971 self.inspector = match self.inspector {
5972 None => Some(cx.new(|_| Inspector::new())),
5973 Some(_) => None,
5974 };
5975 self.refresh();
5976 }
5977
5978 pub fn is_inspector_picking(&self, _cx: &App) -> bool {
5980 #[cfg(any(feature = "inspector", debug_assertions))]
5981 {
5982 if let Some(inspector) = &self.inspector {
5983 return inspector.read(_cx).is_picking();
5984 }
5985 }
5986 false
5987 }
5988
5989 #[cfg(any(feature = "inspector", debug_assertions))]
5991 pub fn with_inspector_state<T: 'static, R>(
5992 &mut self,
5993 _inspector_id: Option<&crate::InspectorElementId>,
5994 cx: &mut App,
5995 f: impl FnOnce(&mut Option<T>, &mut Self) -> R,
5996 ) -> R {
5997 if let Some(inspector_id) = _inspector_id
5998 && let Some(inspector) = &self.inspector
5999 {
6000 let inspector = inspector.clone();
6001 let active_element_id = inspector.read(cx).active_element_id();
6002 if Some(inspector_id) == active_element_id {
6003 return inspector.update(cx, |inspector, _cx| {
6004 inspector.with_active_element_state(self, f)
6005 });
6006 }
6007 }
6008 f(&mut None, self)
6009 }
6010
6011 #[cfg(any(feature = "inspector", debug_assertions))]
6012 pub(crate) fn build_inspector_element_id(
6013 &mut self,
6014 path: crate::InspectorElementPath,
6015 ) -> crate::InspectorElementId {
6016 self.invalidator.debug_assert_paint_or_prepaint();
6017 let path = Rc::new(path);
6018 let next_instance_id = self
6019 .next_frame
6020 .next_inspector_instance_ids
6021 .entry(path.clone())
6022 .or_insert(0);
6023 let instance_id = *next_instance_id;
6024 *next_instance_id += 1;
6025 crate::InspectorElementId { path, instance_id }
6026 }
6027
6028 #[cfg(any(feature = "inspector", debug_assertions))]
6029 fn prepaint_inspector(&mut self, inspector_width: Pixels, cx: &mut App) -> Option<AnyElement> {
6030 if let Some(inspector) = self.inspector.take() {
6031 let mut inspector_element = AnyView::from(inspector.clone()).into_any_element();
6032 inspector_element.prepaint_as_root(
6033 point(self.viewport_size.width - inspector_width, px(0.0)),
6034 size(inspector_width, self.viewport_size.height).into(),
6035 self,
6036 cx,
6037 );
6038 self.inspector = Some(inspector);
6039 Some(inspector_element)
6040 } else {
6041 None
6042 }
6043 }
6044
6045 #[cfg(any(feature = "inspector", debug_assertions))]
6046 fn paint_inspector(&mut self, mut inspector_element: Option<AnyElement>, cx: &mut App) {
6047 if let Some(mut inspector_element) = inspector_element {
6048 inspector_element.paint(self, cx);
6049 };
6050 }
6051
6052 #[cfg(any(feature = "inspector", debug_assertions))]
6055 pub fn insert_inspector_hitbox(
6056 &mut self,
6057 hitbox_id: HitboxId,
6058 inspector_id: Option<&crate::InspectorElementId>,
6059 cx: &App,
6060 ) {
6061 self.invalidator.debug_assert_paint_or_prepaint();
6062 if !self.is_inspector_picking(cx) {
6063 return;
6064 }
6065 if let Some(inspector_id) = inspector_id {
6066 self.next_frame
6067 .inspector_hitboxes
6068 .insert(hitbox_id, inspector_id.clone());
6069 }
6070 }
6071
6072 #[cfg(any(feature = "inspector", debug_assertions))]
6073 fn paint_inspector_hitbox(&mut self, cx: &App) {
6074 if let Some(inspector) = self.inspector.as_ref() {
6075 let inspector = inspector.read(cx);
6076 if let Some((hitbox_id, _)) = self.hovered_inspector_hitbox(inspector, &self.next_frame)
6077 && let Some(hitbox) = self
6078 .next_frame
6079 .hitboxes
6080 .iter()
6081 .find(|hitbox| hitbox.id == hitbox_id)
6082 {
6083 self.paint_quad(crate::fill(hitbox.bounds, crate::rgba(0x61afef4d)));
6084 }
6085 }
6086 }
6087
6088 #[cfg(any(feature = "inspector", debug_assertions))]
6089 fn handle_inspector_mouse_event(&mut self, event: &dyn Any, cx: &mut App) {
6090 let Some(inspector) = self.inspector.clone() else {
6091 return;
6092 };
6093 if event.downcast_ref::<MouseMoveEvent>().is_some() {
6094 inspector.update(cx, |inspector, _cx| {
6095 if let Some((_, inspector_id)) =
6096 self.hovered_inspector_hitbox(inspector, &self.rendered_frame)
6097 {
6098 inspector.hover(inspector_id, self);
6099 }
6100 });
6101 } else if event.downcast_ref::<crate::MouseDownEvent>().is_some() {
6102 inspector.update(cx, |inspector, _cx| {
6103 if let Some((_, inspector_id)) =
6104 self.hovered_inspector_hitbox(inspector, &self.rendered_frame)
6105 {
6106 inspector.select(inspector_id, self);
6107 }
6108 });
6109 } else if let Some(event) = event.downcast_ref::<crate::ScrollEvent>() {
6110 const SCROLL_LINES: f32 = 3.0;
6112 const SCROLL_PIXELS_PER_LAYER: f32 = 36.0;
6113 let delta_y = event
6114 .delta
6115 .pixel_delta(px(SCROLL_PIXELS_PER_LAYER / SCROLL_LINES))
6116 .y;
6117 if let Some(inspector) = self.inspector.clone() {
6118 inspector.update(cx, |inspector, _cx| {
6119 if let Some(depth) = inspector.pick_depth.as_mut() {
6120 *depth += f32::from(delta_y) / SCROLL_PIXELS_PER_LAYER;
6121 let max_depth = self.mouse_hit_test.ids.len() as f32 - 0.5;
6122 if *depth < 0.0 {
6123 *depth = 0.0;
6124 } else if *depth > max_depth {
6125 *depth = max_depth;
6126 }
6127 if let Some((_, inspector_id)) =
6128 self.hovered_inspector_hitbox(inspector, &self.rendered_frame)
6129 {
6130 inspector.set_active_element_id(inspector_id, self);
6131 }
6132 }
6133 });
6134 }
6135 }
6136 }
6137
6138 #[cfg(any(feature = "inspector", debug_assertions))]
6139 fn hovered_inspector_hitbox(
6140 &self,
6141 inspector: &Inspector,
6142 frame: &Frame,
6143 ) -> Option<(HitboxId, crate::InspectorElementId)> {
6144 if let Some(pick_depth) = inspector.pick_depth {
6145 let depth = (pick_depth as i64).try_into().unwrap_or(0);
6146 let max_skipped = self.mouse_hit_test.ids.len().saturating_sub(1);
6147 let skip_count = (depth as usize).min(max_skipped);
6148 for hitbox_id in self.mouse_hit_test.ids.iter().skip(skip_count) {
6149 if let Some(inspector_id) = frame.inspector_hitboxes.get(hitbox_id) {
6150 return Some((*hitbox_id, inspector_id.clone()));
6151 }
6152 }
6153 }
6154 None
6155 }
6156
6157 #[cfg(any(test, feature = "test-support"))]
6160 pub fn set_modifiers(&mut self, modifiers: Modifiers) {
6161 self.modifiers = modifiers;
6162 }
6163}
6164
6165slotmap::new_key_type! {
6167 pub struct WindowId;
6169}
6170
6171impl WindowId {
6172 pub fn as_u64(&self) -> u64 {
6174 self.0.as_ffi()
6175 }
6176}
6177
6178impl From<u64> for WindowId {
6179 fn from(value: u64) -> Self {
6180 WindowId(slotmap::KeyData::from_ffi(value))
6181 }
6182}
6183
6184#[derive(Deref, DerefMut)]
6187pub struct WindowHandle<V> {
6188 #[deref]
6189 #[deref_mut]
6190 pub(crate) any_handle: AnyWindowHandle,
6191 state_type: PhantomData<V>,
6192}
6193
6194impl<V> Debug for WindowHandle<V> {
6195 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
6196 f.debug_struct("WindowHandle")
6197 .field("any_handle", &self.any_handle.id.as_u64())
6198 .finish()
6199 }
6200}
6201
6202impl<V: 'static + Render> WindowHandle<V> {
6203 pub fn new(id: WindowId) -> Self {
6206 WindowHandle {
6207 any_handle: AnyWindowHandle {
6208 id,
6209 state_type: TypeId::of::<V>(),
6210 },
6211 state_type: PhantomData,
6212 }
6213 }
6214
6215 #[cfg(any(test, feature = "test-support"))]
6219 pub fn root<C>(&self, cx: &mut C) -> Result<Entity<V>>
6220 where
6221 C: AppContext,
6222 {
6223 crate::Flatten::flatten(cx.update_window(self.any_handle, |root_view, _, _| {
6224 root_view
6225 .downcast::<V>()
6226 .map_err(|_| anyhow!("the type of the window's root view has changed"))
6227 }))
6228 }
6229
6230 pub fn update<C, R>(
6234 &self,
6235 cx: &mut C,
6236 update: impl FnOnce(&mut V, &mut Window, &mut Context<V>) -> R,
6237 ) -> Result<R>
6238 where
6239 C: AppContext,
6240 {
6241 cx.update_window(self.any_handle, |root_view, window, cx| {
6242 let view = root_view
6243 .downcast::<V>()
6244 .map_err(|_| anyhow!("the type of the window's root view has changed"))?;
6245
6246 Ok(view.update(cx, |view, cx| update(view, window, cx)))
6247 })?
6248 }
6249
6250 pub fn read<'a>(&self, cx: &'a App) -> Result<&'a V> {
6254 let x = cx
6255 .windows
6256 .get(self.id)
6257 .and_then(|window| {
6258 window
6259 .as_ref()
6260 .and_then(|window| window.root.clone())
6261 .map(|root_view| root_view.downcast::<V>())
6262 })
6263 .context("window not found")?
6264 .map_err(|_| anyhow!("the type of the window's root view has changed"))?;
6265
6266 Ok(x.read(cx))
6267 }
6268
6269 pub fn read_with<C, R>(&self, cx: &C, read_with: impl FnOnce(&V, &App) -> R) -> Result<R>
6273 where
6274 C: AppContext,
6275 {
6276 cx.read_window(self, |root_view, cx| read_with(root_view.read(cx), cx))
6277 }
6278
6279 pub fn entity<C>(&self, cx: &C) -> Result<Entity<V>>
6283 where
6284 C: AppContext,
6285 {
6286 cx.read_window(self, |root_view, _cx| root_view)
6287 }
6288
6289 pub fn is_active(&self, cx: &mut App) -> Option<bool> {
6294 cx.update_window(self.any_handle, |_, window, _| window.is_window_active())
6295 .ok()
6296 }
6297}
6298
6299impl<V> Copy for WindowHandle<V> {}
6300
6301impl<V> Clone for WindowHandle<V> {
6302 fn clone(&self) -> Self {
6303 *self
6304 }
6305}
6306
6307impl<V> PartialEq for WindowHandle<V> {
6308 fn eq(&self, other: &Self) -> bool {
6309 self.any_handle == other.any_handle
6310 }
6311}
6312
6313impl<V> Eq for WindowHandle<V> {}
6314
6315impl<V> Hash for WindowHandle<V> {
6316 fn hash<H: Hasher>(&self, state: &mut H) {
6317 self.any_handle.hash(state);
6318 }
6319}
6320
6321impl<V: 'static> From<WindowHandle<V>> for AnyWindowHandle {
6322 fn from(val: WindowHandle<V>) -> Self {
6323 val.any_handle
6324 }
6325}
6326
6327unsafe impl<V> Send for WindowHandle<V> {}
6328unsafe impl<V> Sync for WindowHandle<V> {}
6329
6330#[derive(Copy, Clone, PartialEq, Eq, Hash)]
6332pub struct AnyWindowHandle {
6333 pub(crate) id: WindowId,
6334 state_type: TypeId,
6335}
6336
6337impl AnyWindowHandle {
6338 pub fn window_id(&self) -> WindowId {
6340 self.id
6341 }
6342
6343 #[cfg(any(test, feature = "test-support"))]
6345 pub fn for_test(id: WindowId) -> Self {
6346 Self {
6347 id,
6348 state_type: TypeId::of::<()>(),
6349 }
6350 }
6351
6352 pub fn downcast<T: 'static>(&self) -> Option<WindowHandle<T>> {
6355 if TypeId::of::<T>() == self.state_type {
6356 Some(WindowHandle {
6357 any_handle: *self,
6358 state_type: PhantomData,
6359 })
6360 } else {
6361 None
6362 }
6363 }
6364
6365 pub fn update<C, R>(
6369 self,
6370 cx: &mut C,
6371 update: impl FnOnce(AnyView, &mut Window, &mut App) -> R,
6372 ) -> Result<R>
6373 where
6374 C: AppContext,
6375 {
6376 cx.update_window(self, update)
6377 }
6378
6379 pub fn read<T, C, R>(self, cx: &C, read: impl FnOnce(Entity<T>, &App) -> R) -> Result<R>
6383 where
6384 C: AppContext,
6385 T: 'static,
6386 {
6387 let view = self
6388 .downcast::<T>()
6389 .context("the type of the window's root view has changed")?;
6390
6391 cx.read_window(&view, read)
6392 }
6393}
6394
6395impl HasWindowHandle for Window {
6396 fn window_handle(&self) -> Result<raw_window_handle::WindowHandle<'_>, HandleError> {
6397 self.platform_window.window_handle()
6398 }
6399}
6400
6401impl HasDisplayHandle for Window {
6402 fn display_handle(
6403 &self,
6404 ) -> std::result::Result<raw_window_handle::DisplayHandle<'_>, HandleError> {
6405 self.platform_window.display_handle()
6406 }
6407}
6408
6409#[derive(Clone, Debug, Eq, PartialEq, Hash)]
6414pub enum ElementId {
6415 View(EntityId),
6417 Integer(u64),
6419 Name(SharedString),
6421 Uuid(Uuid),
6423 FocusHandle(FocusId),
6425 NamedInteger(SharedString, u64),
6427 Path(Arc<std::path::Path>),
6429 CodeLocation(core::panic::Location<'static>),
6431 NamedChild(Box<ElementId>, SharedString),
6433 OpaqueId([u8; 20]),
6435}
6436
6437impl ElementId {
6438 pub fn named_usize(name: impl Into<SharedString>, integer: usize) -> ElementId {
6440 Self::NamedInteger(name.into(), integer as u64)
6441 }
6442}
6443
6444impl Display for ElementId {
6445 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
6446 match self {
6447 ElementId::View(entity_id) => write!(f, "view-{}", entity_id)?,
6448 ElementId::Integer(ix) => write!(f, "{}", ix)?,
6449 ElementId::Name(name) => write!(f, "{}", name)?,
6450 ElementId::FocusHandle(_) => write!(f, "FocusHandle")?,
6451 ElementId::NamedInteger(s, i) => write!(f, "{}-{}", s, i)?,
6452 ElementId::Uuid(uuid) => write!(f, "{}", uuid)?,
6453 ElementId::Path(path) => write!(f, "{}", path.display())?,
6454 ElementId::CodeLocation(location) => write!(f, "{}", location)?,
6455 ElementId::NamedChild(id, name) => write!(f, "{}-{}", id, name)?,
6456 ElementId::OpaqueId(opaque_id) => write!(f, "{:x?}", opaque_id)?,
6457 }
6458
6459 Ok(())
6460 }
6461}
6462
6463impl TryInto<SharedString> for ElementId {
6464 type Error = anyhow::Error;
6465
6466 fn try_into(self) -> anyhow::Result<SharedString> {
6467 if let ElementId::Name(name) = self {
6468 Ok(name)
6469 } else {
6470 anyhow::bail!("element id is not string")
6471 }
6472 }
6473}
6474
6475impl From<u64> for ElementId {
6476 fn from(id: u64) -> Self {
6477 ElementId::Integer(id)
6478 }
6479}
6480
6481impl From<usize> for ElementId {
6482 fn from(id: usize) -> Self {
6483 ElementId::Integer(id as u64)
6484 }
6485}
6486
6487impl From<i32> for ElementId {
6488 fn from(id: i32) -> Self {
6489 Self::Integer(id as u64)
6490 }
6491}
6492
6493impl From<SharedString> for ElementId {
6494 fn from(name: SharedString) -> Self {
6495 ElementId::Name(name)
6496 }
6497}
6498
6499impl From<String> for ElementId {
6500 fn from(name: String) -> Self {
6501 ElementId::Name(name.into())
6502 }
6503}
6504
6505impl From<Arc<str>> for ElementId {
6506 fn from(name: Arc<str>) -> Self {
6507 ElementId::Name(name.into())
6508 }
6509}
6510
6511impl From<Arc<std::path::Path>> for ElementId {
6512 fn from(path: Arc<std::path::Path>) -> Self {
6513 ElementId::Path(path)
6514 }
6515}
6516
6517impl From<&'static str> for ElementId {
6518 fn from(name: &'static str) -> Self {
6519 ElementId::Name(SharedString::new_static(name))
6520 }
6521}
6522
6523impl<'a> From<&'a FocusHandle> for ElementId {
6524 fn from(handle: &'a FocusHandle) -> Self {
6525 ElementId::FocusHandle(handle.id)
6526 }
6527}
6528
6529impl From<(&'static str, EntityId)> for ElementId {
6530 fn from((name, id): (&'static str, EntityId)) -> Self {
6531 ElementId::NamedInteger(SharedString::new_static(name), id.as_u64())
6532 }
6533}
6534
6535impl From<(&'static str, usize)> for ElementId {
6536 fn from((name, id): (&'static str, usize)) -> Self {
6537 ElementId::NamedInteger(SharedString::new_static(name), id as u64)
6538 }
6539}
6540
6541impl From<(SharedString, usize)> for ElementId {
6542 fn from((name, id): (SharedString, usize)) -> Self {
6543 ElementId::NamedInteger(name, id as u64)
6544 }
6545}
6546
6547impl From<(&'static str, u64)> for ElementId {
6548 fn from((name, id): (&'static str, u64)) -> Self {
6549 ElementId::NamedInteger(SharedString::new_static(name), id)
6550 }
6551}
6552
6553impl From<Uuid> for ElementId {
6554 fn from(value: Uuid) -> Self {
6555 Self::Uuid(value)
6556 }
6557}
6558
6559impl From<(&'static str, u32)> for ElementId {
6560 fn from((name, id): (&'static str, u32)) -> Self {
6561 ElementId::NamedInteger(SharedString::new_static(name), id.into())
6562 }
6563}
6564
6565impl<T: Into<SharedString>> From<(ElementId, T)> for ElementId {
6566 fn from((id, name): (ElementId, T)) -> Self {
6567 ElementId::NamedChild(Box::new(id), name.into())
6568 }
6569}
6570
6571impl From<&'static core::panic::Location<'static>> for ElementId {
6572 fn from(location: &'static core::panic::Location<'static>) -> Self {
6573 ElementId::CodeLocation(*location)
6574 }
6575}
6576
6577impl From<[u8; 20]> for ElementId {
6578 fn from(opaque_id: [u8; 20]) -> Self {
6579 ElementId::OpaqueId(opaque_id)
6580 }
6581}
6582
6583#[derive(Clone)]
6586pub struct PaintQuad {
6587 pub bounds: Bounds<Pixels>,
6589 pub corner_radii: Corners<Pixels>,
6591 pub background: Background,
6593 pub border_widths: Edges<Pixels>,
6595 pub border_color: Hsla,
6597 pub border_style: BorderStyle,
6599 pub continuous_corners: bool,
6601 pub transform: TransformationMatrix,
6603 pub blend_mode: BlendMode,
6605}
6606
6607impl PaintQuad {
6608 pub fn corner_radii(self, corner_radii: impl Into<Corners<Pixels>>) -> Self {
6610 PaintQuad {
6611 corner_radii: corner_radii.into(),
6612 ..self
6613 }
6614 }
6615
6616 pub fn border_widths(self, border_widths: impl Into<Edges<Pixels>>) -> Self {
6618 PaintQuad {
6619 border_widths: border_widths.into(),
6620 ..self
6621 }
6622 }
6623
6624 pub fn border_color(self, border_color: impl Into<Hsla>) -> Self {
6626 PaintQuad {
6627 border_color: border_color.into(),
6628 ..self
6629 }
6630 }
6631
6632 pub fn background(self, background: impl Into<Background>) -> Self {
6634 PaintQuad {
6635 background: background.into(),
6636 ..self
6637 }
6638 }
6639}
6640
6641pub fn quad(
6643 bounds: Bounds<Pixels>,
6644 corner_radii: impl Into<Corners<Pixels>>,
6645 background: impl Into<Background>,
6646 border_widths: impl Into<Edges<Pixels>>,
6647 border_color: impl Into<Hsla>,
6648 border_style: BorderStyle,
6649) -> PaintQuad {
6650 PaintQuad {
6651 bounds,
6652 corner_radii: corner_radii.into(),
6653 background: background.into(),
6654 border_widths: border_widths.into(),
6655 border_color: border_color.into(),
6656 border_style,
6657 continuous_corners: false,
6658 transform: TransformationMatrix::unit(),
6659 blend_mode: BlendMode::Normal,
6660 }
6661}
6662
6663pub fn fill(bounds: impl Into<Bounds<Pixels>>, background: impl Into<Background>) -> PaintQuad {
6665 PaintQuad {
6666 bounds: bounds.into(),
6667 corner_radii: (0.).into(),
6668 background: background.into(),
6669 border_widths: (0.).into(),
6670 border_color: transparent_black(),
6671 border_style: BorderStyle::default(),
6672 continuous_corners: false,
6673 transform: TransformationMatrix::unit(),
6674 blend_mode: BlendMode::Normal,
6675 }
6676}
6677
6678pub fn outline(
6680 bounds: impl Into<Bounds<Pixels>>,
6681 border_color: impl Into<Hsla>,
6682 border_style: BorderStyle,
6683) -> PaintQuad {
6684 PaintQuad {
6685 bounds: bounds.into(),
6686 corner_radii: (0.).into(),
6687 background: transparent_black().into(),
6688 border_widths: (1.).into(),
6689 border_color: border_color.into(),
6690 border_style,
6691 continuous_corners: false,
6692 transform: TransformationMatrix::unit(),
6693 blend_mode: BlendMode::Normal,
6694 }
6695}
6696
6697#[cfg(test)]
6698mod tests {
6699 use super::*;
6700 use crate::{
6701 ContentMask, Context, Entity, ExternalPaths, HitboxBehavior, InputEvent as _,
6702 MouseMoveEvent, QuitMode, Render, StyleRefinement, TestAppContext, ThermalState,
6703 WindowOptions, bounds, canvas, div, hsla, point, px, size,
6704 };
6705 use std::{
6706 cell::{Cell, RefCell},
6707 path::PathBuf,
6708 rc::Rc,
6709 };
6710
6711 #[test]
6712 fn high_rate_input_avoids_inactive_window_throttling() {
6713 let default_inactive = Some(super::THIRTY_FPS_INTERVAL);
6714 assert_eq!(
6715 minimum_frame_interval(
6716 true,
6717 true,
6718 default_inactive,
6719 ThermalState::Nominal,
6720 crate::PowerMode::Unknown,
6721 ),
6722 default_inactive
6723 );
6724 assert_eq!(
6725 minimum_frame_interval(
6726 true,
6727 false,
6728 default_inactive,
6729 ThermalState::Nominal,
6730 crate::PowerMode::Unknown,
6731 ),
6732 None
6733 );
6734 assert_eq!(
6735 minimum_frame_interval(
6736 true,
6737 false,
6738 default_inactive,
6739 ThermalState::Serious,
6740 crate::PowerMode::Unknown,
6741 ),
6742 Some(super::SIXTY_FPS_INTERVAL),
6743 "thermal pressure still caps high-rate input"
6744 );
6745 }
6746
6747 #[test]
6748 fn inactive_frame_interval_is_configurable() {
6749 let custom = Some(Duration::from_millis(16));
6750 assert_eq!(
6751 minimum_frame_interval(
6752 true,
6753 true,
6754 custom,
6755 ThermalState::Nominal,
6756 crate::PowerMode::Unknown,
6757 ),
6758 custom
6759 );
6760 assert_eq!(
6761 minimum_frame_interval(
6762 true,
6763 true,
6764 None,
6765 ThermalState::Nominal,
6766 crate::PowerMode::Unknown,
6767 ),
6768 None,
6769 "None disables inactive-window throttling"
6770 );
6771 }
6772
6773 #[test]
6774 fn frame_throttle_tracks_display_refreshes() {
6775 let start = super::Instant::now();
6776 for (elapsed, interval) in [
6777 (Duration::from_micros(16_666), super::SIXTY_FPS_INTERVAL),
6778 (Duration::from_micros(33_332), super::THIRTY_FPS_INTERVAL),
6779 ] {
6780 let mut pacer = super::FramePacer::default();
6781 assert!(!pacer.should_defer(start, Some(interval)));
6782 assert!(pacer.should_defer(start + elapsed / 2, Some(interval)));
6783 assert!(!pacer.should_defer(start + elapsed, Some(interval)));
6784 }
6785 }
6786
6787 #[test]
6788 fn frame_throttle_preserves_cadence_without_catching_up_after_stalls() {
6789 let start = super::Instant::now();
6790 let interval = super::THIRTY_FPS_INTERVAL;
6791 let mut pacer = super::FramePacer::default();
6792 assert!(!pacer.should_defer(start, Some(interval)));
6793 let delayed_frame = start + interval + Duration::from_millis(5);
6794 assert!(!pacer.should_defer(delayed_frame, Some(interval)));
6795 assert!(pacer.should_defer(start + interval + interval / 2, Some(interval)));
6796 assert!(!pacer.should_defer(start + interval * 2, Some(interval)));
6797
6798 let after_stall = start + interval * 4 - Duration::from_millis(1);
6800 assert!(!pacer.should_defer(after_stall, Some(interval)));
6801 assert!(pacer.should_defer(after_stall + interval / 2, Some(interval)));
6802 assert!(!pacer.should_defer(after_stall + interval, Some(interval)));
6803 let mandatory_frame = after_stall + interval + Duration::from_millis(2);
6805 assert!(!pacer.should_defer(mandatory_frame, None));
6806 assert!(pacer.should_defer(mandatory_frame + interval / 2, Some(interval)));
6807 }
6808
6809 #[test]
6810 fn power_modes_preserve_frame_limits() {
6811 for (power_mode, active_interval, thermal_interval) in [
6812 (
6813 crate::PowerMode::LowPower,
6814 Some(super::THIRTY_FPS_INTERVAL),
6815 super::THIRTY_FPS_INTERVAL,
6816 ),
6817 (crate::PowerMode::Unknown, None, super::SIXTY_FPS_INTERVAL),
6818 (crate::PowerMode::Balanced, None, super::SIXTY_FPS_INTERVAL),
6819 (crate::PowerMode::HighPower, None, super::SIXTY_FPS_INTERVAL),
6820 ] {
6821 assert_eq!(
6822 super::minimum_frame_interval(true, false, None, ThermalState::Nominal, power_mode),
6823 active_interval,
6824 );
6825 assert_eq!(
6826 super::minimum_frame_interval(true, false, None, ThermalState::Serious, power_mode),
6827 Some(thermal_interval),
6828 );
6829 let inactive_interval = Duration::from_millis(100);
6830 assert_eq!(
6831 super::minimum_frame_interval(
6832 true,
6833 true,
6834 Some(inactive_interval),
6835 ThermalState::Nominal,
6836 power_mode,
6837 ),
6838 Some(inactive_interval),
6839 );
6840 }
6841 }
6842
6843 #[test]
6844 fn thermal_and_low_power_caps_raise_short_inactive_intervals() {
6845 let short = Some(Duration::from_millis(10));
6846 let long = Some(Duration::from_millis(100));
6847 assert_eq!(
6848 super::minimum_frame_interval(
6849 true,
6850 true,
6851 short,
6852 ThermalState::Serious,
6853 crate::PowerMode::Unknown,
6854 ),
6855 Some(super::SIXTY_FPS_INTERVAL),
6856 );
6857 assert_eq!(
6858 super::minimum_frame_interval(
6859 true,
6860 true,
6861 None,
6862 ThermalState::Critical,
6863 crate::PowerMode::Unknown,
6864 ),
6865 Some(super::SIXTY_FPS_INTERVAL),
6866 "a missing inactive interval does not disable the thermal cap"
6867 );
6868 assert_eq!(
6869 super::minimum_frame_interval(
6870 true,
6871 true,
6872 short,
6873 ThermalState::Nominal,
6874 crate::PowerMode::LowPower,
6875 ),
6876 Some(super::THIRTY_FPS_INTERVAL),
6877 );
6878 assert_eq!(
6879 super::minimum_frame_interval(
6880 true,
6881 true,
6882 short,
6883 ThermalState::Serious,
6884 crate::PowerMode::LowPower,
6885 ),
6886 Some(super::THIRTY_FPS_INTERVAL),
6887 "low power is the longer of the two caps"
6888 );
6889 assert_eq!(
6890 super::minimum_frame_interval(
6891 true,
6892 true,
6893 long,
6894 ThermalState::Critical,
6895 crate::PowerMode::LowPower,
6896 ),
6897 long,
6898 );
6899 assert_eq!(
6900 super::minimum_frame_interval(
6901 true,
6902 false,
6903 None,
6904 ThermalState::Nominal,
6905 crate::PowerMode::Unknown,
6906 ),
6907 None,
6908 "unknown power mode does not enable the low-power cap"
6909 );
6910 }
6911
6912 #[test]
6913 fn hovered_at_ignores_pointer_capture() {
6914 let mut cx = TestAppContext::single();
6915 let window = cx.add_window(|_, _| EmptyView);
6916 let window: AnyWindowHandle = window.into();
6917
6918 cx.update_window(window, |_, window, _| {
6919 let bounds = bounds(point(px(0.), px(0.)), size(px(10.), px(10.)));
6920 let hitbox = Hitbox {
6921 id: HitboxId(1),
6922 bounds,
6923 content_mask: ContentMask { bounds },
6924 behavior: HitboxBehavior::Normal,
6925 };
6926 window.rendered_frame.hitboxes.push(hitbox.clone());
6927 window.capture_pointer(hitbox.id);
6928
6929 assert!(hitbox.is_hovered(window));
6930 assert!(hitbox.is_hovered_at(point(px(5.), px(5.)), window));
6931 assert!(!hitbox.is_hovered_at(point(px(20.), px(20.)), window));
6932 })
6933 .unwrap();
6934 }
6935
6936 #[test]
6937 fn hovered_at_respects_content_masks_and_occlusion() {
6938 let mut cx = TestAppContext::single();
6939 let window = cx.add_window(|_, _| EmptyView);
6940 let window: AnyWindowHandle = window.into();
6941
6942 cx.update_window(window, |_, window, _| {
6943 let target_bounds = bounds(point(px(0.), px(0.)), size(px(20.), px(20.)));
6944 let target = Hitbox {
6945 id: HitboxId(1),
6946 bounds: target_bounds,
6947 content_mask: ContentMask {
6948 bounds: bounds(point(px(0.), px(0.)), size(px(10.), px(20.))),
6949 },
6950 behavior: HitboxBehavior::Normal,
6951 };
6952 let blocker = Hitbox {
6953 id: HitboxId(2),
6954 bounds: target_bounds,
6955 content_mask: ContentMask {
6956 bounds: target_bounds,
6957 },
6958 behavior: HitboxBehavior::BlockMouse,
6959 };
6960 window.rendered_frame.hitboxes.push(target.clone());
6961 assert!(target.is_hovered_at(point(px(5.), px(5.)), window));
6962 assert!(!target.is_hovered_at(point(px(15.), px(5.)), window));
6963
6964 window.rendered_frame.hitboxes.push(blocker.clone());
6965
6966 assert!(!target.is_hovered_at(point(px(5.), px(5.)), window));
6967 assert!(blocker.is_hovered_at(point(px(15.), px(5.)), window));
6968 })
6969 .unwrap();
6970 }
6971
6972 #[test]
6973 fn hovered_at_ignores_keyboard_input_modality() {
6974 let mut cx = TestAppContext::single();
6975 let window = cx.add_window(|_, _| EmptyView);
6976 let window: AnyWindowHandle = window.into();
6977
6978 cx.update_window(window, |_, window, _| {
6979 let bounds = bounds(point(px(0.), px(0.)), size(px(10.), px(10.)));
6980 let hitbox = Hitbox {
6981 id: HitboxId(1),
6982 bounds,
6983 content_mask: ContentMask { bounds },
6984 behavior: HitboxBehavior::Normal,
6985 };
6986 window.rendered_frame.hitboxes.push(hitbox.clone());
6987 window.last_input_was_keyboard.set(true);
6988
6989 assert!(!hitbox.is_hovered(window));
6990 assert!(hitbox.is_hovered_at(point(px(5.), px(5.)), window));
6991 })
6992 .unwrap();
6993 }
6994
6995 #[test]
6999 fn draw_in_progress_tracks_element_arena_scope() {
7000 assert!(!draw_in_progress());
7001
7002 let scope = ElementArenaScope::enter();
7003 assert!(draw_in_progress());
7004
7005 let nested = ElementArenaScope::enter();
7006 assert!(draw_in_progress());
7007 drop(nested);
7008 assert!(draw_in_progress(), "outer draw is still in progress");
7009
7010 drop(scope);
7011 assert!(!draw_in_progress());
7012 }
7013
7014 struct EmptyView;
7015
7016 impl Render for EmptyView {
7017 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
7018 div()
7019 }
7020 }
7021
7022 struct FileDropExitView(Rc<Cell<usize>>);
7023
7024 impl Render for FileDropExitView {
7025 fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
7026 div().size_full().on_file_drop_exit({
7027 let observed_file_drop_exit = self.0.clone();
7028 move |_, _, _| observed_file_drop_exit.set(observed_file_drop_exit.get() + 1)
7029 })
7030 }
7031 }
7032
7033 #[test]
7037 fn file_drop_exit_is_window_local() {
7038 let mut cx = TestAppContext::single();
7039 let first_destination_exit_count = Rc::new(Cell::new(0));
7040 let first_destination: AnyWindowHandle = cx
7041 .add_window({
7042 let first_destination_exit_count = first_destination_exit_count.clone();
7043 move |_, _| FileDropExitView(first_destination_exit_count)
7044 })
7045 .into();
7046 let second_destination_exit_count = Rc::new(Cell::new(0));
7047 let second_destination: AnyWindowHandle = cx
7048 .add_window({
7049 let second_destination_exit_count = second_destination_exit_count.clone();
7050 move |_, _| FileDropExitView(second_destination_exit_count)
7051 })
7052 .into();
7053 let reentry_position = point(px(30.), px(30.));
7054 let external_paths =
7055 || ExternalPaths([PathBuf::from("/tmp/dropped.txt")].into_iter().collect());
7056
7057 let update_result = cx.update_window(first_destination, |_, window, cx| {
7058 window.draw(cx).clear();
7059 window.dispatch_event(
7060 FileDropEvent::Entered {
7061 position: reentry_position,
7062 paths: external_paths(),
7063 }
7064 .to_platform_input(),
7065 cx,
7066 );
7067 window.dispatch_event(FileDropEvent::Exited.to_platform_input(), cx);
7068 assert!(cx.active_drag.is_none());
7069 assert_eq!(first_destination_exit_count.get(), 1);
7070 assert_eq!(second_destination_exit_count.get(), 0);
7071 });
7072 assert!(
7073 update_result.is_ok(),
7074 "failed to handle drag in first destination window: {update_result:?}"
7075 );
7076
7077 let update_result = cx.update_window(second_destination, |_, window, cx| {
7078 window.draw(cx).clear();
7079 window.dispatch_event(
7080 PlatformInput::KeyDown(KeyDownEvent {
7081 keystroke: Keystroke::parse("down").expect("valid keystroke"),
7082 is_held: false,
7083 prefer_character_input: false,
7084 }),
7085 cx,
7086 );
7087 window.dispatch_event(
7088 FileDropEvent::Entered {
7089 position: reentry_position,
7090 paths: external_paths(),
7091 }
7092 .to_platform_input(),
7093 cx,
7094 );
7095 assert!(
7096 cx.active_drag
7097 .as_ref()
7098 .is_some_and(|drag| drag.value.downcast_ref::<ExternalPaths>().is_some())
7099 );
7100 assert_eq!(first_destination_exit_count.get(), 1);
7101 assert_eq!(second_destination_exit_count.get(), 0);
7102
7103 window.dispatch_event(FileDropEvent::Exited.to_platform_input(), cx);
7104 assert!(cx.active_drag.is_none());
7105 assert_eq!(first_destination_exit_count.get(), 1);
7106 assert_eq!(second_destination_exit_count.get(), 1);
7107 });
7108 assert!(
7109 update_result.is_ok(),
7110 "failed to handle drag in second destination window: {update_result:?}"
7111 );
7112 }
7113
7114 #[test]
7115 fn open_window_propagates_platform_map_error() {
7116 let cx = TestAppContext::single();
7117 cx.test_platform()
7118 .fail_next_window_map("test window mapping failed");
7119
7120 let result =
7121 cx.update(|cx| cx.open_window(WindowOptions::default(), |_, cx| cx.new(|_| EmptyView)));
7122
7123 let error = match result {
7124 Ok(_) => panic!("window mapping unexpectedly succeeded"),
7125 Err(error) => error,
7126 };
7127 assert_eq!(error.to_string(), "test window mapping failed");
7128 assert!(cx.read(|cx| cx.windows().is_empty()));
7129 }
7130
7131 struct OpensWindowOnPaint {
7132 opened: Rc<Cell<bool>>,
7133 }
7134
7135 impl Render for OpensWindowOnPaint {
7136 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
7137 let opened = self.opened.clone();
7138 div()
7139 .size_full()
7140 .child(canvas(
7141 |_, _, _| {},
7142 move |_, _, _window, cx| {
7143 if !opened.replace(true) {
7144 cx.open_window(WindowOptions::default(), |_, cx| cx.new(|_| EmptyView))
7145 .unwrap();
7146 }
7147 },
7148 ))
7149 .child(div().child("after"))
7150 }
7151 }
7152
7153 #[test]
7157 fn opening_a_window_during_draw_keeps_outer_elements_alive() {
7158 let mut cx = TestAppContext::single();
7159 let opened = Rc::new(Cell::new(false));
7160 let window = cx.add_window({
7161 let opened = opened.clone();
7162 move |_, _| OpensWindowOnPaint { opened }
7163 });
7164
7165 assert!(opened.get());
7166 assert_eq!(cx.windows().len(), 2);
7167
7168 cx.update_window(window.into(), |_, window, cx| window.draw(cx).clear())
7169 .unwrap();
7170 }
7171
7172 struct FocusLostRestoreView {
7173 parent: FocusHandle,
7174 child: FocusHandle,
7175 show_child: bool,
7176 observed_restore: Option<FocusHandle>,
7177 _subscription: Subscription,
7178 }
7179
7180 impl FocusLostRestoreView {
7181 fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
7182 Self {
7183 parent: cx.focus_handle(),
7184 child: cx.focus_handle(),
7185 show_child: true,
7186 observed_restore: None,
7187 _subscription: cx.on_focus_lost(window, |this, window, cx| {
7188 this.observed_restore = window.focus_lost_restore_target(cx);
7189 }),
7190 }
7191 }
7192 }
7193
7194 impl Render for FocusLostRestoreView {
7195 fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
7196 div()
7197 .id("parent")
7198 .track_focus(&self.parent)
7199 .when(self.show_child, |parent| {
7200 parent.child(div().id("child").track_focus(&self.child))
7201 })
7202 }
7203 }
7204
7205 #[test]
7208 fn focus_lost_restore_target_is_nearest_surviving_ancestor() {
7209 let mut cx = TestAppContext::single();
7210 let window = cx.add_window(FocusLostRestoreView::new);
7211
7212 window
7213 .update(&mut cx, |view, window, _| {
7214 window.focus(&view.child);
7215 })
7216 .unwrap();
7217
7218 cx.update_window(window.into(), |_, window, cx| {
7219 window.draw(cx).clear();
7220 assert!(
7221 window.focus_lost_restore_target(cx).is_none(),
7222 "restore target is only set while focus-lost listeners run"
7223 );
7224 })
7225 .unwrap();
7226
7227 window
7228 .update(&mut cx, |view, window, _| {
7229 assert!(view.child.is_focused(window));
7230 view.show_child = false;
7231 })
7232 .unwrap();
7233
7234 cx.update_window(window.into(), |_, window, cx| {
7235 window.draw(cx).clear();
7236 assert!(
7237 window.focus_lost_restore_target(cx).is_none(),
7238 "restore target must be cleared after focus-lost listeners return"
7239 );
7240 })
7241 .unwrap();
7242
7243 window
7244 .update(&mut cx, |view, _, _| {
7245 assert_eq!(
7246 view.observed_restore.as_ref(),
7247 Some(&view.parent),
7248 "restore target should be the parent that remained in the tree"
7249 );
7250 })
7251 .unwrap();
7252 }
7253
7254 #[gpui::test]
7255 fn test_native_close_defers_app_access(cx: &mut TestAppContext) {
7256 let window = cx.add_window(|_, _| EmptyView);
7257 let platform_window = cx.test_window(window.into());
7258 {
7259 let app = cx.app.borrow_mut();
7260 platform_window.simulate_close();
7261 assert!(app.windows.contains_key(window.window_id()));
7262 }
7263 cx.run_until_parked();
7264 assert!(!cx.app.borrow().windows.contains_key(window.window_id()));
7265 }
7266
7267 #[gpui::test]
7268 fn test_window_reports_no_raw_handle_instead_of_panicking(cx: &mut TestAppContext) {
7269 use raw_window_handle::{HandleError, HasDisplayHandle as _, HasWindowHandle as _};
7270
7271 let window = cx.add_window(|_, _| EmptyView);
7272 window
7273 .update(cx, |_, window, _| {
7274 assert!(matches!(
7275 window.window_handle(),
7276 Err(HandleError::NotSupported)
7277 ));
7278 assert!(matches!(
7279 window.display_handle(),
7280 Err(HandleError::NotSupported)
7281 ));
7282 })
7283 .unwrap();
7284 }
7285
7286 #[gpui::test]
7290 fn test_window_visibility(cx: &mut TestAppContext) {
7291 let window = cx.add_window(|_, _| EmptyView);
7292 let observed = Rc::new(RefCell::new(Vec::new()));
7293 let _subscription = window
7294 .update(cx, {
7295 let observed = observed.clone();
7296 move |_, window, _| {
7297 assert_eq!(window.visibility(), WindowVisibility::Visible);
7298 assert!(window.is_visible());
7299 window.observe_window_visibility(move |visibility, window, _| {
7300 assert_eq!(window.visibility(), visibility);
7301 observed.borrow_mut().push(visibility);
7302 })
7303 }
7304 })
7305 .unwrap();
7306 let test_window = cx.test_window(window.into());
7307 window
7311 .update(cx, |_, window, _| {
7312 window.invalidator.set_dirty(false);
7313 window.needs_present.set(false);
7314 })
7315 .unwrap();
7316 let frame_wake_count = test_window.frame_wake_count();
7317
7318 test_window.simulate_visibility_change(WindowVisibility::Hidden);
7319 assert_eq!(*observed.borrow(), [WindowVisibility::Hidden]);
7320 window
7321 .update(cx, |_, window, _| assert!(!window.is_visible()))
7322 .unwrap();
7323
7324 test_window.simulate_visibility_change(WindowVisibility::Hidden);
7326 assert_eq!(observed.borrow().len(), 1);
7327
7328 test_window.simulate_visibility_change(WindowVisibility::Visible);
7329 assert_eq!(
7330 *observed.borrow(),
7331 [WindowVisibility::Hidden, WindowVisibility::Visible]
7332 );
7333 window
7334 .update(cx, |_, window, _| assert!(window.is_visible()))
7335 .unwrap();
7336 assert_eq!(test_window.frame_wake_count(), frame_wake_count);
7337 }
7338
7339 #[gpui::test]
7340 fn test_appearance_change_runs_after_app_update(cx: &mut TestAppContext) {
7341 let window = cx.add_window(|_, _| EmptyView);
7342 let observed_appearance = Rc::new(Cell::new(None));
7343 let _subscription = window
7344 .update(cx, {
7345 let observed_appearance = observed_appearance.clone();
7346 move |_, window, _| {
7347 window.observe_window_appearance(move |window, _| {
7348 observed_appearance.set(Some(window.appearance()));
7349 })
7350 }
7351 })
7352 .unwrap();
7353 let test_window = cx.test_window(window.into());
7354
7355 cx.update(|_| {
7356 test_window.simulate_appearance_change(WindowAppearance::Dark);
7357 assert_eq!(observed_appearance.get(), None);
7358 });
7359 cx.run_until_parked();
7360
7361 assert_eq!(observed_appearance.get(), Some(WindowAppearance::Dark));
7362 }
7363
7364 #[test]
7365 fn test_scale_factor_change_preserves_bounds_and_survives_resize() {
7366 let mut cx = TestAppContext::single();
7367 let window = cx.add_window(|_, _| EmptyView);
7368 let handle: AnyWindowHandle = window.into();
7369 let window_state = |cx: &mut TestAppContext| {
7370 cx.update_window(handle, |_, window, _| {
7371 (
7372 window.scale_factor(),
7373 window.bounds(),
7374 window.viewport_size(),
7375 )
7376 })
7377 .unwrap()
7378 };
7379
7380 let (scale_factor, mut expected_bounds, _) = window_state(&mut cx);
7381 assert_eq!(scale_factor, 2.0);
7382
7383 for (scale_factor, resized_size) in [
7384 (1.0, size(px(800.), px(600.))),
7385 (1.25, size(px(640.), px(480.))),
7386 (2.0, size(px(1024.), px(768.))),
7387 ] {
7388 cx.simulate_window_scale_factor_change(handle, scale_factor);
7389 assert_eq!(
7390 window_state(&mut cx),
7391 (scale_factor, expected_bounds, expected_bounds.size)
7392 );
7393
7394 cx.simulate_window_resize(handle, resized_size);
7395 expected_bounds.size = resized_size;
7396 assert_eq!(
7397 window_state(&mut cx),
7398 (scale_factor, expected_bounds, resized_size)
7399 );
7400 }
7401 }
7402
7403 struct RootView {
7404 explicit_size: bool,
7405 child_bounds: Rc<Cell<Bounds<Pixels>>>,
7406 }
7407
7408 impl Render for RootView {
7409 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
7410 let child_bounds = self.child_bounds.clone();
7411 let mut root = div().flex().flex_col().child(
7412 canvas(
7413 move |bounds, _, _| child_bounds.set(bounds),
7414 |_, _, _, _| {},
7415 )
7416 .size_full(),
7417 );
7418 if self.explicit_size {
7419 root = root.w(px(300.)).h(px(200.));
7420 }
7421 root
7422 }
7423 }
7424
7425 #[test]
7426 fn auto_sized_window_root_fills_the_window() {
7427 let mut cx = TestAppContext::single();
7428 let child_bounds = Rc::new(Cell::new(Bounds::default()));
7429 let window = cx.add_window({
7430 let child_bounds = child_bounds.clone();
7431 move |_, _| RootView {
7432 explicit_size: false,
7433 child_bounds,
7434 }
7435 });
7436
7437 let viewport_size = cx
7438 .update_window(window.into(), |_, window, cx| {
7439 window.draw(cx).clear();
7440 window.viewport_size()
7441 })
7442 .unwrap();
7443
7444 assert_eq!(child_bounds.get().size, viewport_size);
7445 }
7446
7447 #[test]
7448 fn explicitly_sized_window_root_keeps_its_size() {
7449 let mut cx = TestAppContext::single();
7450 let child_bounds = Rc::new(Cell::new(Bounds::default()));
7451 let window = cx.add_window({
7452 let child_bounds = child_bounds.clone();
7453 move |_, _| RootView {
7454 explicit_size: true,
7455 child_bounds,
7456 }
7457 });
7458
7459 cx.update_window(window.into(), |_, window, cx| {
7460 window.draw(cx).clear();
7461 })
7462 .unwrap();
7463
7464 assert_eq!(child_bounds.get().size, size(px(300.), px(200.)));
7465 }
7466
7467 fn scaled(value: f32) -> ScaledPixels {
7468 ScaledPixels(value)
7469 }
7470
7471 #[test]
7472 fn border_only_quad_strips_cover_asymmetric_borders_and_corners() {
7473 let bounds = Bounds::new(
7474 point(scaled(0.), scaled(0.)),
7475 size(scaled(100.), scaled(80.)),
7476 );
7477 let widths = Edges {
7478 top: scaled(6.),
7479 right: scaled(4.),
7480 bottom: scaled(8.),
7481 left: scaled(2.),
7482 };
7483 let radii = Corners {
7484 top_left: scaled(10.),
7485 top_right: scaled(12.),
7486 bottom_right: scaled(16.),
7487 bottom_left: scaled(14.),
7488 };
7489
7490 let strips = border_only_quad_strips(bounds, widths, radii).unwrap();
7491 assert_eq!(
7492 strips,
7493 [
7494 Bounds::from_corners(
7495 point(scaled(0.), scaled(0.)),
7496 point(scaled(100.), scaled(13.)),
7497 ),
7498 Bounds::from_corners(
7499 point(scaled(0.), scaled(63.)),
7500 point(scaled(100.), scaled(80.)),
7501 ),
7502 Bounds::from_corners(
7503 point(scaled(0.), scaled(13.)),
7504 point(scaled(3.), scaled(63.)),
7505 ),
7506 Bounds::from_corners(
7507 point(scaled(95.), scaled(13.)),
7508 point(scaled(100.), scaled(63.)),
7509 ),
7510 ]
7511 );
7512 }
7513
7514 #[test]
7515 fn border_only_quad_keeps_one_primitive_when_interior_is_too_small() {
7516 let bounds = Bounds::new(
7517 point(scaled(0.), scaled(0.)),
7518 size(scaled(10.), scaled(10.)),
7519 );
7520 let widths = Edges {
7521 top: scaled(5.),
7522 right: scaled(5.),
7523 bottom: scaled(5.),
7524 left: scaled(5.),
7525 };
7526
7527 assert!(border_only_quad_strips(bounds, widths, Corners::default()).is_none());
7528 }
7529
7530 struct BorderOnlyQuadView;
7531
7532 impl Render for BorderOnlyQuadView {
7533 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
7534 canvas(
7535 |_, _, _| {},
7536 |bounds, _, window, _| {
7537 window.paint_quad(outline(bounds, hsla(0., 0., 1., 1.), BorderStyle::Solid));
7538 },
7539 )
7540 .size(px(100.))
7541 }
7542 }
7543
7544 #[test]
7545 fn border_only_quad_emits_four_clipped_primitives() {
7546 let mut cx = TestAppContext::single();
7547 let window = cx.add_window(|_, _| BorderOnlyQuadView);
7548
7549 let primitive_count = cx
7550 .update_window(window.into(), |_, window, cx| {
7551 window.draw(cx).clear();
7552 window.rendered_frame.scene.quads.len()
7553 })
7554 .unwrap();
7555
7556 assert_eq!(primitive_count, 4);
7557 }
7558
7559 #[test]
7560 fn resource_profile_gpu_budget_reaches_the_platform() {
7561 let cx = TestAppContext::single();
7562
7563 let budget = cx.test_platform().gpu_resource_budget.lock().clone();
7564 assert_eq!(budget.instance_buffer_initial_size, 2 * 1024 * 1024);
7565 assert_eq!(budget.instance_buffer_max_size, 256 * 1024 * 1024);
7566 }
7567
7568 #[test]
7569 fn window_attention_is_forwarded_to_the_platform_window() {
7570 let mut cx = TestAppContext::single();
7571 let window = cx.add_window(|_, _| BorderOnlyQuadView);
7572 let window = AnyWindowHandle::from(window);
7573
7574 cx.update_window(window, |_, window, _| window.request_attention())
7575 .unwrap();
7576
7577 assert_eq!(cx.test_window(window).0.lock().attention_requests, 1);
7578 }
7579
7580 #[test]
7581 fn quit_mode_explicit_keeps_app_alive_after_last_window_closed() {
7582 let mut cx = TestAppContext::single();
7583 cx.update(|cx| cx.set_quit_mode(QuitMode::Explicit));
7584 assert_eq!(
7585 *cx.test_platform().last_quit_mode.lock(),
7586 Some(QuitMode::Explicit)
7587 );
7588 let window = cx.add_window(|_, _| BorderOnlyQuadView);
7589 let window = AnyWindowHandle::from(window);
7590
7591 cx.update_window(window, |_, window, _| window.remove_window())
7592 .unwrap();
7593
7594 assert!(!*cx.test_platform().did_quit.lock());
7595 }
7596
7597 #[test]
7598 fn quit_mode_last_window_closed_quits_after_last_window_closed() {
7599 let mut cx = TestAppContext::single();
7600 cx.update(|cx| cx.set_quit_mode(QuitMode::LastWindowClosed));
7601 let window = cx.add_window(|_, _| BorderOnlyQuadView);
7602 let window = AnyWindowHandle::from(window);
7603
7604 cx.update_window(window, |_, window, _| window.remove_window())
7605 .unwrap();
7606
7607 assert!(*cx.test_platform().did_quit.lock());
7608 }
7609
7610 #[test]
7611 fn quit_mode_runtime_change_applies_to_the_next_window_close() {
7612 let mut cx = TestAppContext::single();
7613 cx.update(|cx| cx.set_quit_mode(QuitMode::Explicit));
7614 let window = AnyWindowHandle::from(cx.add_window(|_, _| BorderOnlyQuadView));
7615
7616 cx.update(|cx| cx.set_quit_mode(QuitMode::LastWindowClosed));
7617 assert_eq!(
7618 *cx.test_platform().last_quit_mode.lock(),
7619 Some(QuitMode::LastWindowClosed)
7620 );
7621 cx.update_window(window, |_, window, _| window.remove_window())
7622 .unwrap();
7623
7624 assert!(*cx.test_platform().did_quit.lock());
7625 }
7626
7627 #[test]
7628 fn quit_mode_last_window_closed_waits_for_every_window() {
7629 let mut cx = TestAppContext::single();
7630 cx.update(|cx| cx.set_quit_mode(QuitMode::LastWindowClosed));
7631 let first = AnyWindowHandle::from(cx.add_window(|_, _| BorderOnlyQuadView));
7632 let second = AnyWindowHandle::from(cx.add_window(|_, _| BorderOnlyQuadView));
7633
7634 cx.update_window(first, |_, window, _| window.remove_window())
7635 .unwrap();
7636 assert!(!*cx.test_platform().did_quit.lock());
7637
7638 cx.update_window(second, |_, window, _| window.remove_window())
7639 .unwrap();
7640 assert!(*cx.test_platform().did_quit.lock());
7641 }
7642
7643 #[test]
7644 fn quit_mode_default_follows_platform_convention() {
7645 let mut cx = TestAppContext::single();
7646 let window = cx.add_window(|_, _| BorderOnlyQuadView);
7648 let window = AnyWindowHandle::from(window);
7649
7650 cx.update_window(window, |_, window, _| window.remove_window())
7651 .unwrap();
7652
7653 let expected = cfg!(not(target_os = "macos"));
7656 assert_eq!(*cx.test_platform().did_quit.lock(), expected);
7657 }
7658
7659 #[gpui::test]
7660 fn cached_view_follows_inherited_opacity(cx: &mut TestAppContext) {
7661 struct Child {
7662 renders: usize,
7663 }
7664
7665 impl Render for Child {
7666 fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
7667 self.renders += 1;
7668 div().size_full().bg(crate::rgb(0xff0000))
7669 }
7670 }
7671
7672 struct Root {
7673 opacity: f32,
7674 width: Pixels,
7675 child: Entity<Child>,
7676 }
7677
7678 impl Render for Root {
7679 fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
7680 div()
7681 .w(self.width)
7682 .h(px(200.))
7683 .opacity(self.opacity)
7684 .hover(|style| style.opacity(1.))
7685 .child(
7686 AnyView::from(self.child.clone())
7687 .cached(StyleRefinement::default().size(px(100.))),
7688 )
7689 }
7690 }
7691
7692 fn update_and_draw(
7695 window: WindowHandle<Root>,
7696 child: &Entity<Child>,
7697 cx: &mut TestAppContext,
7698 update: impl FnOnce(&mut Root, &mut Window, &mut Context<Root>),
7699 ) -> (f32, usize) {
7700 window
7701 .update(cx, |root, window, cx| {
7702 update(root, window, cx);
7703 cx.notify();
7704 })
7705 .expect("update root");
7706 for _ in 0..3 {
7707 let (alpha, renders, requested_frames) = cx
7708 .update_window(window.into(), |_, window, cx| {
7709 window.draw(cx).clear();
7710 let quads = &window.rendered_frame.scene.quads;
7711 assert_eq!(quads.len(), 1);
7712 let alpha = quads.first().expect("child quad").background.solid.a;
7713 (
7714 alpha,
7715 child.read(cx).renders,
7716 simulate_next_frame(window, cx),
7717 )
7718 })
7719 .expect("draw window");
7720 if requested_frames == 0 {
7721 return (alpha, renders);
7722 }
7723 }
7724 panic!("cached child kept requesting frames");
7725 }
7726
7727 fn simulate_next_frame(window: &mut Window, cx: &mut App) -> usize {
7730 let callbacks = window.next_frame_callbacks.take();
7731 let count = callbacks.len();
7732 for callback in callbacks {
7733 callback(window, cx);
7734 }
7735 count
7736 }
7737
7738 fn simulate_mouse_move(window: &mut Window, position: Point<Pixels>, cx: &mut App) {
7739 let _ = window.dispatch_event(
7740 MouseMoveEvent {
7741 position,
7742 modifiers: window.modifiers(),
7743 pressed_button: None,
7744 }
7745 .to_platform_input(),
7746 cx,
7747 );
7748 }
7749
7750 let child = cx.new(|_| Child { renders: 0 });
7751 let window = cx.add_window(|_, _| Root {
7752 opacity: 1.,
7753 width: px(200.),
7754 child: child.clone(),
7755 });
7756 let outside = point(px(500.), px(500.));
7757 let inside = point(px(50.), px(50.));
7758 let beside = point(px(250.), px(50.));
7759
7760 let move_outside = |_: &mut Root, window: &mut Window, cx: &mut Context<Root>| {
7762 simulate_mouse_move(window, outside, cx)
7763 };
7764 assert_eq!(update_and_draw(window, &child, cx, move_outside), (1., 1));
7765 assert_eq!(update_and_draw(window, &child, cx, |_, _, _| {}), (1., 1));
7766 let fade = |root: &mut Root, _: &mut Window, _: &mut Context<Root>| root.opacity = 0.5;
7767 assert_eq!(update_and_draw(window, &child, cx, fade), (0.5, 2));
7768 assert_eq!(update_and_draw(window, &child, cx, |_, _, _| {}), (0.5, 2));
7769
7770 let move_inside = |_: &mut Root, window: &mut Window, cx: &mut Context<Root>| {
7772 simulate_mouse_move(window, inside, cx)
7773 };
7774 assert_eq!(update_and_draw(window, &child, cx, move_inside).0, 1.);
7775 let move_beside = |_: &mut Root, window: &mut Window, cx: &mut Context<Root>| {
7776 simulate_mouse_move(window, beside, cx)
7777 };
7778 assert_eq!(update_and_draw(window, &child, cx, move_beside).0, 0.5);
7779
7780 let widen = |root: &mut Root, _: &mut Window, _: &mut Context<Root>| root.width = px(300.);
7783 assert_eq!(update_and_draw(window, &child, cx, widen).0, 1.);
7784 }
7785}