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, ResizeEdge, SMOOTH_SVG_SCALE_FACTOR,
15 SUBPIXEL_VARIANTS_X, SUBPIXEL_VARIANTS_Y, ScaledPixels, Scene, Shadow, SharedString, Size,
16 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;
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
288pub(crate) type FocusMap = RwLock<SlotMap<FocusId, FocusRef>>;
289pub(crate) struct FocusRef {
290 pub(crate) ref_count: AtomicUsize,
291 pub(crate) tab_index: isize,
292 pub(crate) tab_stop: bool,
293}
294
295impl FocusId {
296 pub fn is_focused(&self, window: &Window) -> bool {
298 window.focus == Some(*self)
299 }
300
301 pub fn contains_focused(&self, window: &Window, cx: &App) -> bool {
304 window
305 .focused(cx)
306 .is_some_and(|focused| self.contains(focused.id, window))
307 }
308
309 pub fn within_focused(&self, window: &Window, cx: &App) -> bool {
312 let focused = window.focused(cx);
313 focused.is_some_and(|focused| focused.id.contains(*self, window))
314 }
315
316 pub(crate) fn contains(&self, other: Self, window: &Window) -> bool {
318 window
319 .rendered_frame
320 .dispatch_tree
321 .focus_contains(*self, other)
322 }
323}
324
325pub struct FocusHandle {
327 pub(crate) id: FocusId,
328 handles: Arc<FocusMap>,
329 pub tab_index: isize,
331 pub tab_stop: bool,
333}
334
335impl std::fmt::Debug for FocusHandle {
336 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
337 f.write_fmt(format_args!("FocusHandle({:?})", self.id))
338 }
339}
340
341impl FocusHandle {
342 pub(crate) fn new(handles: &Arc<FocusMap>) -> Self {
343 let id = handles.write().insert(FocusRef {
344 ref_count: AtomicUsize::new(1),
345 tab_index: 0,
346 tab_stop: false,
347 });
348
349 Self {
350 id,
351 tab_index: 0,
352 tab_stop: false,
353 handles: handles.clone(),
354 }
355 }
356
357 pub(crate) fn for_id(id: FocusId, handles: &Arc<FocusMap>) -> Option<Self> {
358 let lock = handles.read();
359 let focus = lock.get(id)?;
360 if atomic_incr_if_not_zero(&focus.ref_count) == 0 {
361 return None;
362 }
363 Some(Self {
364 id,
365 tab_index: focus.tab_index,
366 tab_stop: focus.tab_stop,
367 handles: handles.clone(),
368 })
369 }
370
371 pub fn tab_index(mut self, index: isize) -> Self {
373 self.tab_index = index;
374 if let Some(focus) = self.handles.write().get_mut(self.id) {
375 focus.tab_index = index;
376 }
377 self
378 }
379
380 pub fn tab_stop(mut self, tab_stop: bool) -> Self {
384 self.tab_stop = tab_stop;
385 if let Some(focus) = self.handles.write().get_mut(self.id) {
386 focus.tab_stop = tab_stop;
387 }
388 self
389 }
390
391 pub fn downgrade(&self) -> WeakFocusHandle {
393 WeakFocusHandle {
394 id: self.id,
395 handles: Arc::downgrade(&self.handles),
396 }
397 }
398
399 pub fn focus(&self, window: &mut Window) {
401 window.focus(self)
402 }
403
404 pub fn is_focused(&self, window: &Window) -> bool {
406 self.id.is_focused(window)
407 }
408
409 pub fn contains_focused(&self, window: &Window, cx: &App) -> bool {
412 self.id.contains_focused(window, cx)
413 }
414
415 pub fn within_focused(&self, window: &Window, cx: &mut App) -> bool {
418 self.id.within_focused(window, cx)
419 }
420
421 pub fn contains(&self, other: &Self, window: &Window) -> bool {
423 self.id.contains(other.id, window)
424 }
425
426 pub fn dispatch_action(&self, action: &dyn Action, window: &mut Window, cx: &mut App) {
428 if let Some(node_id) = window
429 .rendered_frame
430 .dispatch_tree
431 .focusable_node_id(self.id)
432 {
433 window.dispatch_action_on_node(node_id, action, cx)
434 }
435 }
436}
437
438impl Clone for FocusHandle {
439 fn clone(&self) -> Self {
440 Self::for_id(self.id, &self.handles).unwrap()
441 }
442}
443
444impl PartialEq for FocusHandle {
445 fn eq(&self, other: &Self) -> bool {
446 self.id == other.id
447 }
448}
449
450impl Eq for FocusHandle {}
451
452impl Drop for FocusHandle {
453 fn drop(&mut self) {
454 self.handles
455 .read()
456 .get(self.id)
457 .unwrap()
458 .ref_count
459 .fetch_sub(1, SeqCst);
460 }
461}
462
463#[derive(Clone, Debug)]
465pub struct WeakFocusHandle {
466 pub(crate) id: FocusId,
467 pub(crate) handles: Weak<FocusMap>,
468}
469
470impl WeakFocusHandle {
471 pub fn upgrade(&self) -> Option<FocusHandle> {
473 let handles = self.handles.upgrade()?;
474 FocusHandle::for_id(self.id, &handles)
475 }
476}
477
478impl PartialEq for WeakFocusHandle {
479 fn eq(&self, other: &WeakFocusHandle) -> bool {
480 self.id == other.id
481 }
482}
483
484impl Eq for WeakFocusHandle {}
485
486impl PartialEq<FocusHandle> for WeakFocusHandle {
487 fn eq(&self, other: &FocusHandle) -> bool {
488 self.id == other.id
489 }
490}
491
492impl PartialEq<WeakFocusHandle> for FocusHandle {
493 fn eq(&self, other: &WeakFocusHandle) -> bool {
494 self.id == other.id
495 }
496}
497
498pub trait Focusable: 'static {
501 fn focus_handle(&self, cx: &App) -> FocusHandle;
503}
504
505impl<V: Focusable> Focusable for Entity<V> {
506 fn focus_handle(&self, cx: &App) -> FocusHandle {
507 self.read(cx).focus_handle(cx)
508 }
509}
510
511pub trait ManagedView: Focusable + EventEmitter<DismissEvent> + Render {}
514
515impl<M: Focusable + EventEmitter<DismissEvent> + Render> ManagedView for M {}
516
517pub struct DismissEvent;
519
520type FrameCallback = Box<dyn FnOnce(&mut Window, &mut App)>;
521
522pub(crate) type AnyMouseListener =
523 Box<dyn FnMut(&dyn Any, DispatchPhase, &mut Window, &mut App) + 'static>;
524
525#[derive(Clone)]
526pub(crate) struct CursorStyleRequest {
527 pub(crate) hitbox_id: Option<HitboxId>,
528 pub(crate) style: CursorStyle,
529}
530
531#[derive(Default, Eq, PartialEq)]
532pub(crate) struct HitTest {
533 pub(crate) ids: SmallVec<[HitboxId; 8]>,
534 pub(crate) hover_hitbox_count: usize,
535}
536
537#[derive(Clone, Copy, Debug, Eq, PartialEq)]
539pub enum WindowControlArea {
540 Drag,
542 Close,
544 Max,
546 Min,
548}
549
550#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
552pub struct HitboxId(u64);
553
554impl HitboxId {
555 pub fn is_hovered(self, window: &Window) -> bool {
561 if window.captured_hitbox == Some(self) {
563 return true;
564 }
565 if window.last_input_was_keyboard() {
566 return false;
567 }
568 self.hit_test(window)
569 }
570
571 pub(crate) fn is_hovered_ignoring_last_input(self, window: &Window) -> bool {
576 if window.captured_hitbox == Some(self) {
578 return true;
579 }
580 self.hit_test(window)
581 }
582
583 fn hit_test(self, window: &Window) -> bool {
584 let hit_test = &window.mouse_hit_test;
585 for id in hit_test.ids.iter().take(hit_test.hover_hitbox_count) {
586 if self == *id {
587 return true;
588 }
589 }
590 false
591 }
592
593 pub fn should_handle_scroll(self, window: &Window) -> bool {
598 window.mouse_hit_test.ids.contains(&self)
599 }
600
601 fn next(mut self) -> HitboxId {
602 HitboxId(self.0.wrapping_add(1))
603 }
604}
605
606#[derive(Clone, Debug, Deref)]
609pub struct Hitbox {
610 pub id: HitboxId,
612 #[deref]
614 pub bounds: Bounds<Pixels>,
615 pub content_mask: ContentMask<Pixels>,
617 pub behavior: HitboxBehavior,
619}
620
621impl Hitbox {
622 pub fn is_hovered(&self, window: &Window) -> bool {
637 self.id.is_hovered(window)
638 }
639
640 pub fn is_hovered_at(&self, position: Point<Pixels>, window: &Window) -> bool {
649 let hit_test = window.rendered_frame.hit_test(position);
650 hit_test
651 .ids
652 .iter()
653 .take(hit_test.hover_hitbox_count)
654 .any(|id| self.id == *id)
655 }
656
657 pub fn should_handle_scroll(&self, window: &Window) -> bool {
664 self.id.should_handle_scroll(window)
665 }
666}
667
668#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
670pub enum HitboxBehavior {
671 #[default]
673 Normal,
674
675 BlockMouse,
697
698 BlockMouseExceptScroll,
725}
726
727#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
729pub struct TooltipId(usize);
730
731impl TooltipId {
732 pub fn is_hovered(&self, window: &Window) -> bool {
734 window
735 .tooltip_bounds
736 .as_ref()
737 .is_some_and(|tooltip_bounds| {
738 tooltip_bounds.id == *self
739 && tooltip_bounds.bounds.contains(&window.mouse_position())
740 })
741 }
742}
743
744pub(crate) struct TooltipBounds {
745 id: TooltipId,
746 bounds: Bounds<Pixels>,
747}
748
749#[derive(Clone)]
750pub(crate) struct TooltipRequest {
751 id: TooltipId,
752 tooltip: AnyTooltip,
753}
754
755pub(crate) struct DeferredDraw {
756 current_view: EntityId,
757 priority: usize,
758 parent_node: DispatchNodeId,
759 element_id_stack: SmallVec<[ElementId; 32]>,
760 text_style_stack: SmallVec<[TextStyleRefinement; 4]>,
761 element: Option<AnyElement>,
762 absolute_offset: Point<Pixels>,
763 prepaint_range: Range<PrepaintStateIndex>,
764 paint_range: Range<PaintIndex>,
765}
766
767pub(crate) struct Frame {
768 pub(crate) focus: Option<FocusId>,
769 pub(crate) window_active: bool,
770 pub(crate) element_states: FxHashMap<(GlobalElementId, TypeId), ElementStateBox>,
771 accessed_element_states: Vec<(GlobalElementId, TypeId)>,
772 pub(crate) mouse_listeners: Vec<Option<AnyMouseListener>>,
773 pub(crate) dispatch_tree: DispatchTree,
774 pub(crate) scene: Scene,
775 pub(crate) hitboxes: Vec<Hitbox>,
776 pub(crate) window_control_hitboxes: Vec<(WindowControlArea, Hitbox)>,
777 pub(crate) deferred_draws: Vec<DeferredDraw>,
778 pub(crate) input_handlers: Vec<Option<PlatformInputHandler>>,
779 pub(crate) tooltip_requests: Vec<Option<TooltipRequest>>,
780 pub(crate) cursor_styles: Vec<CursorStyleRequest>,
781 #[cfg(any(test, feature = "test-support"))]
782 pub(crate) debug_bounds: FxHashMap<String, Bounds<Pixels>>,
783 #[cfg(any(test, feature = "test-support"))]
784 debug_bounds_records: Vec<(String, Bounds<Pixels>)>,
785 #[cfg(any(feature = "inspector", debug_assertions))]
786 pub(crate) next_inspector_instance_ids: FxHashMap<Rc<crate::InspectorElementPath>, usize>,
787 #[cfg(any(feature = "inspector", debug_assertions))]
788 pub(crate) inspector_hitboxes: FxHashMap<HitboxId, crate::InspectorElementId>,
789 pub(crate) tab_stops: TabStopMap,
790}
791
792#[derive(Clone, Default)]
793pub(crate) struct PrepaintStateIndex {
794 hitboxes_index: usize,
795 tooltips_index: usize,
796 deferred_draws_index: usize,
797 dispatch_tree_index: usize,
798 accessed_element_states_index: usize,
799 line_layout_index: LineLayoutIndex,
800}
801
802#[derive(Clone, Default)]
803pub(crate) struct PaintIndex {
804 scene_index: usize,
805 #[cfg(any(test, feature = "test-support"))]
806 debug_bounds_index: usize,
807 mouse_listeners_index: usize,
808 input_handlers_index: usize,
809 cursor_styles_index: usize,
810 accessed_element_states_index: usize,
811 tab_handle_index: usize,
812 line_layout_index: LineLayoutIndex,
813}
814
815impl Frame {
816 #[cfg(any(test, feature = "test-support"))]
817 pub(crate) fn record_debug_bounds(&mut self, selector: String, bounds: Bounds<Pixels>) {
818 self.debug_bounds.insert(selector.clone(), bounds);
819 self.debug_bounds_records.push((selector, bounds));
820 }
821
822 pub(crate) fn new(dispatch_tree: DispatchTree) -> Self {
823 Frame {
824 focus: None,
825 window_active: false,
826 element_states: FxHashMap::default(),
827 accessed_element_states: Vec::new(),
828 mouse_listeners: Vec::new(),
829 dispatch_tree,
830 scene: Scene::default(),
831 hitboxes: Vec::new(),
832 window_control_hitboxes: Vec::new(),
833 deferred_draws: Vec::new(),
834 input_handlers: Vec::new(),
835 tooltip_requests: Vec::new(),
836 cursor_styles: Vec::new(),
837
838 #[cfg(any(test, feature = "test-support"))]
839 debug_bounds: FxHashMap::default(),
840 #[cfg(any(test, feature = "test-support"))]
841 debug_bounds_records: Vec::new(),
842
843 #[cfg(any(feature = "inspector", debug_assertions))]
844 next_inspector_instance_ids: FxHashMap::default(),
845
846 #[cfg(any(feature = "inspector", debug_assertions))]
847 inspector_hitboxes: FxHashMap::default(),
848 tab_stops: TabStopMap::default(),
849 }
850 }
851
852 pub(crate) fn clear(&mut self) {
853 self.element_states.clear();
854 self.accessed_element_states.clear();
855 self.mouse_listeners.clear();
856 self.dispatch_tree.clear();
857 self.scene.clear();
858 self.input_handlers.clear();
859 self.tooltip_requests.clear();
860 self.cursor_styles.clear();
861 self.hitboxes.clear();
862 self.window_control_hitboxes.clear();
863 self.deferred_draws.clear();
864 self.tab_stops.clear();
865 self.focus = None;
866
867 #[cfg(any(test, feature = "test-support"))]
868 {
869 self.debug_bounds.clear();
870 self.debug_bounds_records.clear();
871 }
872
873 #[cfg(any(feature = "inspector", debug_assertions))]
874 {
875 self.next_inspector_instance_ids.clear();
876 self.inspector_hitboxes.clear();
877 }
878 }
879
880 pub(crate) fn cursor_style(&self, window: &Window) -> Option<CursorStyle> {
881 self.cursor_styles
882 .iter()
883 .rev()
884 .fold_while(None, |style, request| match request.hitbox_id {
885 None => Done(Some(request.style)),
886 Some(hitbox_id) => Continue(style.or_else(|| {
887 hitbox_id
888 .is_hovered_ignoring_last_input(window)
889 .then_some(request.style)
890 })),
891 })
892 .into_inner()
893 }
894
895 pub(crate) fn hit_test(&self, position: Point<Pixels>) -> HitTest {
896 let mut set_hover_hitbox_count = false;
897 let mut hit_test = HitTest::default();
898 for hitbox in self.hitboxes.iter().rev() {
899 let bounds = hitbox.bounds.intersect(&hitbox.content_mask.bounds);
900 if bounds.contains(&position) {
901 hit_test.ids.push(hitbox.id);
902 if !set_hover_hitbox_count
903 && hitbox.behavior == HitboxBehavior::BlockMouseExceptScroll
904 {
905 hit_test.hover_hitbox_count = hit_test.ids.len();
906 set_hover_hitbox_count = true;
907 }
908 if hitbox.behavior == HitboxBehavior::BlockMouse {
909 break;
910 }
911 }
912 }
913 if !set_hover_hitbox_count {
914 hit_test.hover_hitbox_count = hit_test.ids.len();
915 }
916 hit_test
917 }
918
919 pub(crate) fn focus_path(&self) -> SmallVec<[FocusId; 8]> {
920 self.focus
921 .map(|focus_id| self.dispatch_tree.focus_path(focus_id))
922 .unwrap_or_default()
923 }
924
925 pub(crate) fn finish(&mut self, prev_frame: &mut Self) {
926 for element_state_key in &self.accessed_element_states {
927 if let Some((element_state_key, element_state)) =
928 prev_frame.element_states.remove_entry(element_state_key)
929 {
930 self.element_states.insert(element_state_key, element_state);
931 }
932 }
933
934 self.scene.finish();
935 }
936}
937
938#[derive(Clone, Debug)]
941pub(crate) struct InputRateTracker {
942 timestamps: Vec<Instant>,
943 window: Duration,
944 inputs_per_second: u32,
945 sustain_until: Instant,
946 sustain_duration: Duration,
947}
948
949impl Default for InputRateTracker {
950 fn default() -> Self {
951 Self {
952 timestamps: Vec::new(),
953 window: Duration::from_millis(100),
954 inputs_per_second: 60,
955 sustain_until: Instant::now(),
956 sustain_duration: Duration::from_secs(1),
957 }
958 }
959}
960
961impl InputRateTracker {
962 pub fn record_input(&mut self) {
963 let now = Instant::now();
964 self.timestamps.push(now);
965 self.timestamps
966 .retain(|&t| now.duration_since(t) <= self.window);
967 let min_events = self.inputs_per_second as u128 * self.window.as_millis() / 1000;
968 if self.timestamps.len() as u128 >= min_events {
969 self.sustain_until = now + self.sustain_duration;
970 }
971 }
972
973 pub fn is_high_rate(&self) -> bool {
974 Instant::now() < self.sustain_until
975 }
976}
977
978fn frame_throttle_interval(
979 force_render: bool,
980 require_presentation: bool,
981 has_next_frame_callbacks: bool,
982 is_active: bool,
983 has_high_rate_input: bool,
984 is_thermally_constrained: bool,
985 inactive_frame_interval: Option<Duration>,
986) -> Option<Duration> {
987 if require_presentation || (!force_render && !has_next_frame_callbacks) {
988 None
989 } else if !is_active && !has_high_rate_input {
990 inactive_frame_interval
991 } else if is_thermally_constrained {
992 Some(Duration::from_micros(16667))
993 } else {
994 None
995 }
996}
997
998#[cfg(feature = "input-latency-histogram")]
1000pub struct InputLatencySnapshot {
1001 pub latency_histogram: Histogram<u64>,
1003 pub events_per_frame_histogram: Histogram<u64>,
1005 pub mid_draw_events_dropped: u64,
1007}
1008
1009#[cfg(feature = "input-latency-histogram")]
1010struct InputLatencyTracker {
1011 first_input_at: Option<Instant>,
1012 pending_input_count: u64,
1013 latency_histogram: Histogram<u64>,
1014 events_per_frame_histogram: Histogram<u64>,
1015 mid_draw_events_dropped: u64,
1016}
1017
1018#[cfg(feature = "input-latency-histogram")]
1019impl InputLatencyTracker {
1020 fn new() -> Result<Self> {
1021 Ok(Self {
1022 first_input_at: None,
1023 pending_input_count: 0,
1024 latency_histogram: Histogram::new(3)
1025 .map_err(|error| anyhow!("failed to create input latency histogram: {error}"))?,
1026 events_per_frame_histogram: Histogram::new(3)
1027 .map_err(|error| anyhow!("failed to create events per frame histogram: {error}"))?,
1028 mid_draw_events_dropped: 0,
1029 })
1030 }
1031
1032 fn record_input(&mut self, dispatch_time: Instant) {
1033 self.first_input_at.get_or_insert(dispatch_time);
1034 self.pending_input_count += 1;
1035 }
1036
1037 fn record_mid_draw_input(&mut self) {
1038 self.mid_draw_events_dropped += 1;
1039 }
1040
1041 fn record_frame_presented(&mut self) {
1042 if let Some(first_input_at) = self.first_input_at.take() {
1043 self.latency_histogram
1044 .record(first_input_at.elapsed().as_nanos() as u64)
1045 .ok();
1046 }
1047
1048 if self.pending_input_count > 0 {
1049 self.events_per_frame_histogram
1050 .record(self.pending_input_count)
1051 .ok();
1052 self.pending_input_count = 0;
1053 }
1054 }
1055
1056 fn snapshot(&self) -> InputLatencySnapshot {
1057 InputLatencySnapshot {
1058 latency_histogram: self.latency_histogram.clone(),
1059 events_per_frame_histogram: self.events_per_frame_histogram.clone(),
1060 mid_draw_events_dropped: self.mid_draw_events_dropped,
1061 }
1062 }
1063}
1064
1065pub struct Window {
1067 pub(crate) handle: AnyWindowHandle,
1068 pub(crate) invalidator: WindowInvalidator,
1069 pub(crate) removed: bool,
1070 pub(crate) platform_window: Box<dyn PlatformWindow>,
1071 pub(crate) a11y: A11y,
1072 display_id: Option<DisplayId>,
1073 sprite_atlas: Arc<dyn PlatformAtlas>,
1074 text_system: Arc<WindowTextSystem>,
1075 rem_size: Pixels,
1076 rem_size_override_stack: SmallVec<[Pixels; 8]>,
1081 pub(crate) viewport_size: Size<Pixels>,
1082 layout_engine: Option<TaffyLayoutEngine>,
1083 pub(crate) root: Option<AnyView>,
1084 pub(crate) element_id_stack: SmallVec<[ElementId; 32]>,
1085 pub(crate) text_style_stack: SmallVec<[TextStyleRefinement; 4]>,
1086 pub(crate) rendered_entity_stack: SmallVec<[EntityId; 16]>,
1087 pub(crate) element_offset_stack: SmallVec<[Point<Pixels>; 16]>,
1088 pub(crate) element_opacity: f32,
1089 pub(crate) content_mask_stack: SmallVec<[ContentMask<Pixels>; 16]>,
1090 pub(crate) requested_autoscroll: Option<Bounds<Pixels>>,
1091 pub(crate) image_cache_stack: SmallVec<[AnyImageCache; 4]>,
1092 pub(crate) rendered_frame: Frame,
1093 pub(crate) next_frame: Frame,
1094 next_hitbox_id: HitboxId,
1095 pub(crate) next_tooltip_id: TooltipId,
1096 pub(crate) tooltip_bounds: Option<TooltipBounds>,
1097 pub(crate) next_frame_callbacks: Rc<RefCell<Vec<FrameCallback>>>,
1098 pub(crate) dirty_views: FxHashSet<EntityId>,
1099 focus_listeners: SubscriberSet<(), AnyWindowFocusListener>,
1100 pub(crate) focus_lost_listeners: SubscriberSet<(), AnyObserver>,
1101 focus_lost_path: SmallVec<[FocusId; 8]>,
1102 default_prevented: bool,
1103 mouse_position: Point<Pixels>,
1104 mouse_hit_test: HitTest,
1105 modifiers: Modifiers,
1106 capslock: Capslock,
1107 scale_factor: f32,
1108 pub(crate) bounds_observers: SubscriberSet<(), AnyObserver>,
1109 appearance: WindowAppearance,
1110 pub(crate) appearance_observers: SubscriberSet<(), AnyObserver>,
1111 active: Rc<Cell<bool>>,
1112 visibility: WindowVisibility,
1113 pub(crate) visibility_observers:
1114 SubscriberSet<(), Box<dyn FnMut(WindowVisibility, &mut Window, &mut App) -> bool>>,
1115 hovered: Rc<Cell<bool>>,
1116 pub(crate) needs_present: Rc<Cell<bool>>,
1117 pub(crate) input_rate_tracker: Rc<RefCell<InputRateTracker>>,
1118 #[cfg(feature = "input-latency-histogram")]
1119 input_latency_tracker: InputLatencyTracker,
1120 #[allow(dead_code)]
1121 pub(crate) last_frame_time: Rc<Cell<Option<Instant>>>,
1122 pub(crate) last_input_was_keyboard: Cell<bool>,
1123 pub(crate) refreshing: bool,
1124 pub(crate) activation_observers: SubscriberSet<(), AnyObserver>,
1125 pub(crate) focus: Option<FocusId>,
1126 focus_enabled: bool,
1127 pending_input: Option<PendingInput>,
1128 pending_modifier: ModifierState,
1129 pub(crate) pending_input_observers: SubscriberSet<(), AnyObserver>,
1130 prompt: Option<RenderablePromptHandle>,
1131 pub(crate) client_inset: Option<Pixels>,
1132 captured_hitbox: Option<HitboxId>,
1135 #[cfg(any(feature = "inspector", debug_assertions))]
1136 inspector: Option<Entity<Inspector>>,
1137}
1138
1139#[derive(Clone, Debug, Default)]
1140struct ModifierState {
1141 modifiers: Modifiers,
1142 saw_other_input: bool,
1143}
1144
1145#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1146pub(crate) enum DrawPhase {
1147 None,
1148 Prepaint,
1149 Paint,
1150 Focus,
1151}
1152
1153pub(crate) const PENDING_INPUT_TIMEOUT: Duration = Duration::from_secs(1);
1154
1155pub struct PendingInputStatus<'a> {
1157 keystrokes: &'a [Keystroke],
1158 timeout: Option<PendingInputTimeoutStatus>,
1159}
1160
1161impl<'a> PendingInputStatus<'a> {
1162 pub fn keystrokes(&self) -> &'a [Keystroke] {
1164 self.keystrokes
1165 }
1166
1167 pub fn timeout(&self) -> Option<PendingInputTimeoutStatus> {
1169 self.timeout
1170 }
1171}
1172
1173#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1175pub struct PendingInputTimeoutStatus {
1176 duration: Duration,
1177 remaining: Duration,
1178 started_at: Option<Instant>,
1179 paused: bool,
1180}
1181
1182impl PendingInputTimeoutStatus {
1183 pub fn duration(&self) -> Duration {
1185 self.duration
1186 }
1187
1188 pub fn remaining(&self, cx: &App) -> Duration {
1190 self.started_at
1191 .map(|started_at| {
1192 self.remaining
1193 .saturating_sub(cx.background_executor().now() - started_at)
1194 })
1195 .unwrap_or(self.remaining)
1196 }
1197
1198 pub fn is_paused(&self) -> bool {
1200 self.paused
1201 }
1202}
1203
1204#[derive(Debug)]
1205struct PendingInputTimeout {
1206 duration: Duration,
1207 remaining: Duration,
1208 state: PendingInputTimeoutState,
1209}
1210
1211#[derive(Debug)]
1212enum PendingInputTimeoutState {
1213 Running { started_at: Instant, task: Task<()> },
1214 Paused { pause: PendingInputTimeoutPause },
1215}
1216
1217struct PendingInputTimeoutPause {
1218 owner_id: EntityId,
1219 _release_subscription: Subscription,
1220}
1221
1222impl std::fmt::Debug for PendingInputTimeoutPause {
1223 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1224 f.debug_struct("PendingInputTimeoutPause")
1225 .field("owner_id", &self.owner_id)
1226 .finish_non_exhaustive()
1227 }
1228}
1229
1230impl PendingInputTimeout {
1231 fn is_paused(&self) -> bool {
1232 matches!(&self.state, PendingInputTimeoutState::Paused { .. })
1233 }
1234
1235 fn pause(&mut self, pause: PendingInputTimeoutPause, now: Instant) -> bool {
1236 match mem::replace(&mut self.state, PendingInputTimeoutState::Paused { pause }) {
1237 PendingInputTimeoutState::Running { started_at, task } => {
1238 self.remaining = self.remaining.saturating_sub(now - started_at);
1239 drop(task);
1240 true
1241 }
1242 previous_state @ PendingInputTimeoutState::Paused { .. } => {
1243 self.state = previous_state;
1244 false
1245 }
1246 }
1247 }
1248
1249 fn pause_owner_id(&self) -> Option<EntityId> {
1250 match &self.state {
1251 PendingInputTimeoutState::Running { .. } => None,
1252 PendingInputTimeoutState::Paused { pause } => Some(pause.owner_id),
1253 }
1254 }
1255
1256 fn resume(&mut self, owner_id: EntityId, started_at: Instant, task: Task<()>) -> bool {
1257 match mem::replace(
1258 &mut self.state,
1259 PendingInputTimeoutState::Running { started_at, task },
1260 ) {
1261 PendingInputTimeoutState::Paused { pause } if pause.owner_id == owner_id => true,
1262 previous_state => {
1263 self.state = previous_state;
1264 false
1265 }
1266 }
1267 }
1268
1269 fn reset_duration(&mut self, duration: Duration) {
1270 self.duration = duration;
1271 self.remaining = duration;
1272 }
1273
1274 fn status(&self) -> PendingInputTimeoutStatus {
1275 let (started_at, paused) = match &self.state {
1276 PendingInputTimeoutState::Running { started_at, .. } => (Some(*started_at), false),
1277 PendingInputTimeoutState::Paused { .. } => (None, true),
1278 };
1279 PendingInputTimeoutStatus {
1280 duration: self.duration,
1281 remaining: self.remaining,
1282 started_at,
1283 paused,
1284 }
1285 }
1286}
1287
1288#[derive(Default, Debug)]
1289struct PendingInput {
1290 keystrokes: SmallVec<[Keystroke; 1]>,
1291 focus: Option<FocusId>,
1292 timeout: Option<PendingInputTimeout>,
1293}
1294
1295pub(crate) struct ElementStateBox {
1296 pub(crate) inner: Box<dyn Any>,
1297 #[cfg(debug_assertions)]
1298 pub(crate) type_name: &'static str,
1299}
1300
1301fn default_bounds(display_id: Option<DisplayId>, cx: &mut App) -> Bounds<Pixels> {
1302 const DEFAULT_WINDOW_OFFSET: Point<Pixels> = point(px(0.), px(35.));
1303
1304 cx.active_window()
1308 .and_then(|w| w.update(cx, |_, window, _| window.bounds()).ok())
1309 .map(|mut bounds| {
1310 bounds.origin += DEFAULT_WINDOW_OFFSET;
1311 bounds
1312 })
1313 .unwrap_or_else(|| {
1314 let display = display_id
1315 .map(|id| cx.find_display(id))
1316 .unwrap_or_else(|| cx.primary_display());
1317
1318 display
1319 .map(|display| display.default_bounds())
1320 .unwrap_or_else(|| Bounds::new(point(px(0.), px(0.)), DEFAULT_WINDOW_SIZE))
1321 })
1322}
1323
1324fn border_only_quad_strips(
1325 outer_bounds: Bounds<ScaledPixels>,
1326 widths: Edges<ScaledPixels>,
1327 radii: Corners<ScaledPixels>,
1328) -> Option<[Bounds<ScaledPixels>; 4]> {
1329 let antialias_slack = point(ScaledPixels(1.0), ScaledPixels(1.0));
1330 let top_left_inset = point(
1331 widths.left,
1332 widths.top.max(radii.top_left).max(radii.top_right),
1333 ) + antialias_slack;
1334 let bottom_right_inset = point(
1335 widths.right,
1336 widths.bottom.max(radii.bottom_left).max(radii.bottom_right),
1337 ) + antialias_slack;
1338 let inner_bounds = Bounds::from_corners(
1339 outer_bounds.origin + top_left_inset,
1340 outer_bounds.bottom_right() - bottom_right_inset,
1341 );
1342 if inner_bounds.is_empty() {
1343 return None;
1344 }
1345
1346 Some([
1347 Bounds::from_corners(
1348 outer_bounds.origin,
1349 point(outer_bounds.right(), inner_bounds.top()),
1350 ),
1351 Bounds::from_corners(
1352 point(outer_bounds.left(), inner_bounds.bottom()),
1353 outer_bounds.bottom_right(),
1354 ),
1355 Bounds::from_corners(
1356 point(outer_bounds.left(), inner_bounds.top()),
1357 inner_bounds.bottom_left(),
1358 ),
1359 Bounds::from_corners(
1360 inner_bounds.top_right(),
1361 point(outer_bounds.right(), inner_bounds.bottom()),
1362 ),
1363 ])
1364}
1365
1366impl Window {
1367 pub(crate) fn new(
1368 handle: AnyWindowHandle,
1369 options: WindowOptions,
1370 cx: &mut App,
1371 ) -> Result<Self> {
1372 let WindowOptions {
1373 window_bounds,
1374 titlebar,
1375 focus,
1376 show,
1377 kind,
1378 is_movable,
1379 app_owns_titlebar_drag,
1380 inactive_frame_interval,
1381 is_resizable,
1382 is_minimizable,
1383 display_id,
1384 window_background,
1385 app_id,
1386 window_min_size,
1387 window_decorations,
1388 #[cfg_attr(not(target_os = "macos"), allow(unused_variables))]
1389 tabbing_identifier,
1390 mouse_passthrough,
1391 icon,
1392 } = options;
1393
1394 let bounds = window_bounds
1395 .map(|bounds| bounds.get_bounds())
1396 .unwrap_or_else(|| default_bounds(display_id, cx));
1397 let mut platform_window = cx.platform.open_window(
1398 handle,
1399 WindowParams {
1400 bounds,
1401 titlebar,
1402 kind,
1403 is_movable,
1404 app_owns_titlebar_drag,
1405 is_resizable,
1406 is_minimizable,
1407 focus,
1408 app_id: app_id.clone(),
1409 show,
1410 display_id,
1411 window_min_size,
1412 #[cfg(target_os = "macos")]
1413 tabbing_identifier,
1414 mouse_passthrough,
1415 icon,
1416 },
1417 )?;
1418
1419 let tab_bar_visible = platform_window.tab_bar_visible();
1420 SystemWindowTabController::init_visible(cx, tab_bar_visible);
1421 if let Some(tabs) = platform_window.tabbed_windows() {
1422 SystemWindowTabController::add_tab(cx, handle.window_id(), tabs);
1423 }
1424
1425 let display_id = platform_window.display().map(|display| display.id());
1426 let sprite_atlas = platform_window.sprite_atlas();
1427 let mouse_position = platform_window.mouse_position();
1428 let modifiers = platform_window.modifiers();
1429 let capslock = platform_window.capslock();
1430 let content_size = platform_window.content_size();
1431 let scale_factor = platform_window.scale_factor();
1432 let appearance = platform_window.appearance();
1433 let text_system = Arc::new(WindowTextSystem::new(cx.text_system().clone()));
1434 let invalidator = WindowInvalidator::new();
1435 let active = Rc::new(Cell::new(platform_window.is_active()));
1436 let visibility = platform_window.visibility();
1437 let hovered = Rc::new(Cell::new(platform_window.is_hovered()));
1438 let needs_present = Rc::new(Cell::new(false));
1439 let next_frame_callbacks: Rc<RefCell<Vec<FrameCallback>>> = Default::default();
1440 let input_rate_tracker = Rc::new(RefCell::new(InputRateTracker::default()));
1441 let last_frame_time = Rc::new(Cell::new(None::<Instant>));
1442
1443 platform_window
1444 .request_decorations(window_decorations.unwrap_or(WindowDecorations::Server));
1445 platform_window.set_background_appearance(window_background);
1446
1447 if let Some(ref window_open_state) = window_bounds {
1448 match window_open_state {
1449 WindowBounds::Fullscreen(_) => platform_window.toggle_fullscreen(),
1450 WindowBounds::Maximized(_) => platform_window.zoom(),
1451 WindowBounds::Windowed(_) => {}
1452 }
1453 }
1454
1455 let accessibility_force_disabled =
1456 cx.accessibility_force_disabled || !cfg!(feature = "accessibility");
1457 let a11y_active_flag = Arc::new(AtomicBool::new(false));
1458
1459 #[cfg(not(target_family = "wasm"))]
1460 if !accessibility_force_disabled {
1461 let initial_tree = accesskit::TreeUpdate {
1462 nodes: vec![(ROOT_NODE_ID, accesskit::Node::new(accesskit::Role::Window))],
1463 tree: Some(accesskit::Tree::new(ROOT_NODE_ID)),
1464 tree_id: accesskit::TreeId::ROOT,
1465 focus: ROOT_NODE_ID,
1466 };
1467 let (activation_sender, activation_receiver) = async_channel::unbounded::<()>();
1468 let (deactivation_sender, deactivation_receiver) = async_channel::unbounded::<()>();
1469 let (action_sender, action_receiver) =
1470 async_channel::unbounded::<accesskit::ActionRequest>();
1471
1472 platform_window.a11y_init(crate::A11yCallbacks {
1473 activation: {
1474 let active_flag = a11y_active_flag.clone();
1475 Box::new(move || {
1476 log::info!("Accessibility activated");
1477 active_flag.store(true, SeqCst);
1478 activation_sender.send_blocking(()).log_err();
1479 Some(initial_tree.clone())
1480 })
1481 },
1482 action: Box::new(move |request| {
1483 action_sender.send_blocking(request).log_err();
1484 }),
1485 deactivation: {
1486 let active_flag = a11y_active_flag.clone();
1487 Box::new(move || {
1488 log::info!("Accessibility deactivated");
1489 active_flag.store(false, SeqCst);
1490 deactivation_sender.send_blocking(()).log_err();
1491 })
1492 },
1493 });
1494
1495 let mut async_cx = cx.to_async();
1496 cx.foreground_executor()
1497 .spawn(async move {
1498 while activation_receiver.recv().await.is_ok() {
1499 handle
1500 .update(&mut async_cx, |_, window, _| window.refresh())
1501 .log_err();
1502 }
1503 })
1504 .detach();
1505
1506 let mut async_cx = cx.to_async();
1507 cx.foreground_executor()
1508 .spawn(async move {
1509 while deactivation_receiver.recv().await.is_ok() {
1510 handle
1511 .update(&mut async_cx, |_, window, _| window.refresh())
1512 .log_err();
1513 }
1514 })
1515 .detach();
1516
1517 let mut async_cx = cx.to_async();
1518 cx.foreground_executor()
1519 .spawn(async move {
1520 while let Ok(request) = action_receiver.recv().await {
1521 handle
1522 .update(&mut async_cx, |_, window, cx| {
1523 window.handle_a11y_action(request, cx);
1524 })
1525 .log_err();
1526 }
1527 })
1528 .detach();
1529 }
1530
1531 platform_window.on_close(Box::new({
1532 let window_id = handle.window_id();
1533 let mut cx = cx.to_async();
1534 move || {
1535 let _ = handle.update(&mut cx, |_, window, _| window.remove_window());
1536 let _ = cx.update(|cx| {
1537 SystemWindowTabController::remove_tab(cx, window_id);
1538 });
1539 }
1540 }));
1541 platform_window.on_request_frame(Box::new({
1542 let mut cx = cx.to_async();
1543 let invalidator = invalidator.clone();
1544 let active = active.clone();
1545 let needs_present = needs_present.clone();
1546 let next_frame_callbacks = next_frame_callbacks.clone();
1547 let input_rate_tracker = input_rate_tracker.clone();
1548 let last_frame_time = last_frame_time.clone();
1549 let mut deferred_force_render = false;
1550 move |request_frame_options| {
1551 if draw_in_progress() {
1567 log::debug!("deferring re-entrant window draw request");
1568 deferred_force_render |= request_frame_options.force_render;
1569 return;
1570 }
1571 let force_render =
1575 mem::take(&mut deferred_force_render) || request_frame_options.force_render;
1576
1577 let thermal_state = handle
1578 .update(&mut cx, |_, _, cx| cx.thermal_state())
1579 .log_err();
1580
1581 let has_high_rate_input = input_rate_tracker.borrow().is_high_rate();
1586 let min_frame_interval = frame_throttle_interval(
1587 force_render,
1588 request_frame_options.require_presentation,
1589 !next_frame_callbacks.borrow().is_empty(),
1590 active.get(),
1591 has_high_rate_input,
1592 matches!(
1593 thermal_state,
1594 Some(ThermalState::Critical | ThermalState::Serious)
1595 ),
1596 inactive_frame_interval,
1597 );
1598
1599 let now = Instant::now();
1600 if let Some(min_interval) = min_frame_interval {
1601 if let Some(last_frame) = last_frame_time.get() {
1602 if now.duration_since(last_frame) < min_interval {
1603 deferred_force_render |= force_render;
1605 handle
1607 .update(&mut cx, |_, window, _| {
1608 window.platform_window.schedule_frame();
1609 })
1610 .log_err();
1611 return;
1612 }
1613 }
1614 }
1615 last_frame_time.set(Some(now));
1616
1617 let next_frame_callbacks = next_frame_callbacks.take();
1618 if !next_frame_callbacks.is_empty() {
1619 handle
1620 .update(&mut cx, |_, window, cx| {
1621 for callback in next_frame_callbacks {
1622 callback(window, cx);
1623 }
1624 })
1625 .log_err();
1626 }
1627
1628 let needs_present = request_frame_options.require_presentation
1631 || needs_present.get()
1632 || has_high_rate_input;
1633
1634 if invalidator.is_dirty() || force_render {
1635 measure("frame duration", || {
1636 handle
1637 .update(&mut cx, |_, window, cx| {
1638 if force_render {
1639 window.refresh();
1640 }
1641 let arena_clear_needed = window.draw(cx);
1642 window.present();
1643 arena_clear_needed.clear();
1645 })
1646 .log_err();
1647 })
1648 } else if needs_present {
1649 handle
1650 .update(&mut cx, |_, window, _| window.present())
1651 .log_err();
1652 }
1653
1654 handle
1655 .update(&mut cx, |_, window, _| {
1656 if window.invalidator.is_dirty()
1657 || !window.next_frame_callbacks.borrow().is_empty()
1658 {
1659 window.platform_window.schedule_frame();
1660 }
1661 })
1662 .log_err();
1663 }
1664 }));
1665 platform_window.on_resize(Box::new({
1666 let mut cx = cx.to_async();
1667 move |_, _| {
1668 handle
1669 .update(&mut cx, |_, window, cx| window.bounds_changed(cx))
1670 .log_err();
1671 }
1672 }));
1673 platform_window.on_moved(Box::new({
1674 let mut cx = cx.to_async();
1675 move || {
1676 handle
1677 .update(&mut cx, |_, window, cx| window.bounds_changed(cx))
1678 .log_err();
1679 }
1680 }));
1681 platform_window.on_appearance_changed(Box::new({
1682 let cx = cx.to_async();
1683 let foreground_executor = cx.foreground_executor().clone();
1684 move || {
1685 let mut cx = cx.clone();
1686 foreground_executor
1689 .spawn(async move {
1690 handle
1691 .update(&mut cx, |_, window, cx| window.appearance_changed(cx))
1692 .log_err();
1693 })
1694 .detach();
1695 }
1696 }));
1697 platform_window.on_active_status_change(Box::new({
1698 let mut cx = cx.to_async();
1699 move |active| {
1700 handle
1701 .update(&mut cx, |_, window, cx| {
1702 if !active {
1703 window.platform_window.set_cursor_style(CursorStyle::Arrow);
1706 cx.platform.set_cursor_style(CursorStyle::Arrow);
1707 }
1708
1709 window.active.set(active);
1710 window.modifiers = window.platform_window.modifiers();
1711 window.capslock = window.platform_window.capslock();
1712 window
1713 .activation_observers
1714 .clone()
1715 .retain(&(), |callback| callback(window, cx));
1716
1717 window.bounds_changed(cx);
1718 window.refresh();
1719
1720 SystemWindowTabController::update_last_active(cx, window.handle.id);
1721 })
1722 .log_err();
1723 }
1724 }));
1725 platform_window.on_visibility_change(Box::new({
1726 let mut cx = cx.to_async();
1727 move |visibility| {
1728 handle
1729 .update(&mut cx, |_, window, cx| {
1730 if window.visibility == visibility {
1731 return;
1732 }
1733 window.visibility = visibility;
1734 window
1735 .visibility_observers
1736 .clone()
1737 .retain(&(), |callback| callback(visibility, window, cx));
1738 })
1739 .log_err();
1740 }
1741 }));
1742 platform_window.on_hover_status_change(Box::new({
1743 let mut cx = cx.to_async();
1744 move |active| {
1745 handle
1746 .update(&mut cx, |_, window, _| {
1747 window.hovered.set(active);
1748 window.refresh();
1749 })
1750 .log_err();
1751 }
1752 }));
1753 platform_window.on_input({
1754 let mut cx = cx.to_async();
1755 Box::new(move |event| {
1756 handle
1757 .update(&mut cx, |_, window, cx| window.dispatch_event(event, cx))
1758 .log_err()
1759 .unwrap_or(DispatchEventResult::default())
1760 })
1761 });
1762 platform_window.on_hit_test_window_control({
1763 let mut cx = cx.to_async();
1764 Box::new(move || {
1765 handle
1766 .update(&mut cx, |_, window, _cx| {
1767 for (area, hitbox) in &window.rendered_frame.window_control_hitboxes {
1768 if window.mouse_hit_test.ids.contains(&hitbox.id) {
1769 return Some(*area);
1770 }
1771 }
1772 None
1773 })
1774 .log_err()
1775 .unwrap_or(None)
1776 })
1777 });
1778 platform_window.on_move_tab_to_new_window({
1779 let mut cx = cx.to_async();
1780 Box::new(move || {
1781 handle
1782 .update(&mut cx, |_, _window, cx| {
1783 SystemWindowTabController::move_tab_to_new_window(cx, handle.window_id());
1784 })
1785 .log_err();
1786 })
1787 });
1788 platform_window.on_merge_all_windows({
1789 let mut cx = cx.to_async();
1790 Box::new(move || {
1791 handle
1792 .update(&mut cx, |_, _window, cx| {
1793 SystemWindowTabController::merge_all_windows(cx, handle.window_id());
1794 })
1795 .log_err();
1796 })
1797 });
1798 platform_window.on_select_next_tab({
1799 let mut cx = cx.to_async();
1800 Box::new(move || {
1801 handle
1802 .update(&mut cx, |_, _window, cx| {
1803 SystemWindowTabController::select_next_tab(cx, handle.window_id());
1804 })
1805 .log_err();
1806 })
1807 });
1808 platform_window.on_select_previous_tab({
1809 let mut cx = cx.to_async();
1810 Box::new(move || {
1811 handle
1812 .update(&mut cx, |_, _window, cx| {
1813 SystemWindowTabController::select_previous_tab(cx, handle.window_id())
1814 })
1815 .log_err();
1816 })
1817 });
1818 platform_window.on_toggle_tab_bar({
1819 let mut cx = cx.to_async();
1820 Box::new(move || {
1821 handle
1822 .update(&mut cx, |_, window, cx| {
1823 let tab_bar_visible = window.platform_window.tab_bar_visible();
1824 SystemWindowTabController::set_visible(cx, tab_bar_visible);
1825 })
1826 .log_err();
1827 })
1828 });
1829
1830 if let Some(app_id) = app_id {
1831 platform_window.set_app_id(&app_id);
1832 }
1833
1834 platform_window.map_window()?;
1835
1836 Ok(Window {
1837 handle,
1838 invalidator,
1839 removed: false,
1840 platform_window,
1841 a11y: A11y::new(a11y_active_flag, accessibility_force_disabled),
1842 display_id,
1843 sprite_atlas,
1844 text_system,
1845 rem_size: px(16.),
1846 rem_size_override_stack: SmallVec::new(),
1847 viewport_size: content_size,
1848 layout_engine: Some(TaffyLayoutEngine::new()),
1849 root: None,
1850 element_id_stack: SmallVec::default(),
1851 text_style_stack: SmallVec::new(),
1852 rendered_entity_stack: SmallVec::new(),
1853 element_offset_stack: SmallVec::new(),
1854 content_mask_stack: SmallVec::new(),
1855 element_opacity: 1.0,
1856 requested_autoscroll: None,
1857 rendered_frame: Frame::new(DispatchTree::new(cx.keymap.clone(), cx.actions.clone())),
1858 next_frame: Frame::new(DispatchTree::new(cx.keymap.clone(), cx.actions.clone())),
1859 next_frame_callbacks,
1860 next_hitbox_id: HitboxId(0),
1861 next_tooltip_id: TooltipId::default(),
1862 tooltip_bounds: None,
1863 dirty_views: FxHashSet::default(),
1864 focus_listeners: SubscriberSet::new(),
1865 focus_lost_listeners: SubscriberSet::new(),
1866 focus_lost_path: SmallVec::new(),
1867 default_prevented: true,
1868 mouse_position,
1869 mouse_hit_test: HitTest::default(),
1870 modifiers,
1871 capslock,
1872 scale_factor,
1873 bounds_observers: SubscriberSet::new(),
1874 appearance,
1875 appearance_observers: SubscriberSet::new(),
1876 active,
1877 visibility,
1878 visibility_observers: SubscriberSet::new(),
1879 hovered,
1880 needs_present,
1881 input_rate_tracker,
1882 #[cfg(feature = "input-latency-histogram")]
1883 input_latency_tracker: InputLatencyTracker::new()?,
1884 last_frame_time,
1885 last_input_was_keyboard: Cell::new(false),
1886 refreshing: false,
1887 activation_observers: SubscriberSet::new(),
1888 focus: None,
1889 focus_enabled: true,
1890 pending_input: None,
1891 pending_modifier: ModifierState::default(),
1892 pending_input_observers: SubscriberSet::new(),
1893 prompt: None,
1894 client_inset: None,
1895 image_cache_stack: SmallVec::new(),
1896 captured_hitbox: None,
1897 #[cfg(any(feature = "inspector", debug_assertions))]
1898 inspector: None,
1899 })
1900 }
1901
1902 pub(crate) fn new_focus_listener(
1903 &self,
1904 value: AnyWindowFocusListener,
1905 ) -> (Subscription, impl FnOnce() + use<>) {
1906 self.focus_listeners.insert((), value)
1907 }
1908}
1909
1910#[derive(Clone, Debug, Default, PartialEq, Eq)]
1911#[allow(missing_docs)]
1912pub struct DispatchEventResult {
1913 pub propagate: bool,
1914 pub default_prevented: bool,
1915}
1916
1917#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
1921#[repr(C)]
1922pub struct ContentMask<P: Clone + Debug + Default + PartialEq> {
1923 pub bounds: Bounds<P>,
1925}
1926
1927impl ContentMask<Pixels> {
1928 pub fn scale(&self, factor: f32) -> ContentMask<ScaledPixels> {
1930 ContentMask {
1931 bounds: self.bounds.scale(factor),
1932 }
1933 }
1934
1935 pub fn intersect(&self, other: &Self) -> Self {
1937 let bounds = self.bounds.intersect(&other.bounds);
1938 ContentMask { bounds }
1939 }
1940}
1941
1942impl Window {
1943 fn mark_view_dirty(&mut self, view_id: EntityId) {
1944 for view_id in self
1947 .rendered_frame
1948 .dispatch_tree
1949 .view_path(view_id)
1950 .into_iter()
1951 .rev()
1952 {
1953 if !self.dirty_views.insert(view_id) {
1954 break;
1955 }
1956 }
1957 }
1958
1959 pub fn visibility(&self) -> WindowVisibility {
1962 self.visibility
1963 }
1964
1965 pub fn is_visible(&self) -> bool {
1972 self.visibility.is_visible()
1973 }
1974
1975 pub fn observe_window_visibility(
1977 &self,
1978 mut callback: impl FnMut(WindowVisibility, &mut Window, &mut App) + 'static,
1979 ) -> Subscription {
1980 let (subscription, activate) = self.visibility_observers.insert(
1981 (),
1982 Box::new(move |visibility, window, cx| {
1983 callback(visibility, window, cx);
1984 true
1985 }),
1986 );
1987 activate();
1988 subscription
1989 }
1990
1991 pub fn observe_window_appearance(
1993 &self,
1994 mut callback: impl FnMut(&mut Window, &mut App) + 'static,
1995 ) -> Subscription {
1996 let (subscription, activate) = self.appearance_observers.insert(
1997 (),
1998 Box::new(move |window, cx| {
1999 callback(window, cx);
2000 true
2001 }),
2002 );
2003 activate();
2004 subscription
2005 }
2006
2007 pub fn replace_root<E>(
2009 &mut self,
2010 cx: &mut App,
2011 build_view: impl FnOnce(&mut Window, &mut Context<E>) -> E,
2012 ) -> Entity<E>
2013 where
2014 E: 'static + Render,
2015 {
2016 let view = cx.new(|cx| build_view(self, cx));
2017 self.root = Some(view.clone().into());
2018 self.refresh();
2019 view
2020 }
2021
2022 pub fn root<E>(&self) -> Option<Option<Entity<E>>>
2024 where
2025 E: 'static + Render,
2026 {
2027 self.root
2028 .as_ref()
2029 .map(|view| view.clone().downcast::<E>().ok())
2030 }
2031
2032 pub fn window_handle(&self) -> AnyWindowHandle {
2034 self.handle
2035 }
2036
2037 pub fn refresh(&mut self) {
2039 if self.invalidator.not_drawing() {
2040 self.refreshing = true;
2041 self.invalidator.set_dirty(true);
2042 }
2043 }
2044
2045 pub fn remove_window(&mut self) {
2047 self.removed = true;
2048 }
2049
2050 pub fn focused(&self, cx: &App) -> Option<FocusHandle> {
2052 self.focus
2053 .and_then(|id| FocusHandle::for_id(id, &cx.focus_handles))
2054 }
2055
2056 pub fn focus_lost_restore_target(&self, cx: &App) -> Option<FocusHandle> {
2060 let (_leaf, ancestors) = self.focus_lost_path.split_last()?;
2061 ancestors.iter().rev().find_map(|id| {
2062 self.rendered_frame.dispatch_tree.focusable_node_id(*id)?;
2063 FocusHandle::for_id(*id, &cx.focus_handles)
2064 })
2065 }
2066
2067 pub fn focus(&mut self, handle: &FocusHandle) {
2069 if !self.focus_enabled || self.focus == Some(handle.id) {
2070 return;
2071 }
2072
2073 self.focus = Some(handle.id);
2074 self.pending_input.take();
2075 self.refresh();
2076 }
2077
2078 pub fn blur(&mut self, cx: &mut App) {
2080 self.clear_pending_keystrokes(cx);
2081
2082 if !self.focus_enabled {
2083 return;
2084 }
2085
2086 self.focus = None;
2087 self.refresh();
2088 }
2089
2090 pub fn disable_focus(&mut self, cx: &mut App) {
2092 self.blur(cx);
2093 self.focus_enabled = false;
2094 }
2095
2096 pub fn focus_next(&mut self) {
2098 if !self.focus_enabled {
2099 return;
2100 }
2101
2102 if let Some(handle) = self.rendered_frame.tab_stops.next(self.focus.as_ref()) {
2103 self.focus(&handle)
2104 }
2105 }
2106
2107 pub fn focus_prev(&mut self) {
2109 if !self.focus_enabled {
2110 return;
2111 }
2112
2113 if let Some(handle) = self.rendered_frame.tab_stops.prev(self.focus.as_ref()) {
2114 self.focus(&handle)
2115 }
2116 }
2117
2118 pub fn text_system(&self) -> &Arc<WindowTextSystem> {
2120 &self.text_system
2121 }
2122
2123 pub fn text_style(&self) -> TextStyle {
2125 let mut style = TextStyle::default();
2126 for refinement in &self.text_style_stack {
2127 style.refine(refinement);
2128 }
2129 style
2130 }
2131
2132 pub fn is_maximized(&self) -> bool {
2135 self.platform_window.is_maximized()
2136 }
2137
2138 pub fn request_decorations(&self, decorations: WindowDecorations) {
2140 self.platform_window.request_decorations(decorations);
2141 }
2142
2143 pub fn set_exclusive_zone(&self, zone: Pixels) {
2145 self.platform_window.set_exclusive_zone(zone);
2146 }
2147
2148 #[cfg(all(any(target_os = "linux", target_os = "freebsd"), feature = "wayland"))]
2151 pub fn set_exclusive_edge(&self, edge: crate::layer_shell::Anchor) {
2152 self.platform_window.set_exclusive_edge(edge);
2153 }
2154
2155 pub fn start_window_resize(&self, edge: ResizeEdge) {
2157 self.platform_window.start_window_resize(edge);
2158 }
2159
2160 pub fn window_bounds(&self) -> WindowBounds {
2163 self.platform_window.window_bounds()
2164 }
2165
2166 pub fn inner_window_bounds(&self) -> WindowBounds {
2168 self.platform_window.inner_window_bounds()
2169 }
2170
2171 pub fn native_window_state(&self) -> Option<Vec<u8>> {
2174 self.platform_window.native_window_state()
2175 }
2176
2177 pub fn restore_native_window_state(&self, state: &[u8]) {
2180 self.platform_window.restore_native_window_state(state);
2181 }
2182
2183 pub fn dispatch_action(&mut self, action: Box<dyn Action>, cx: &mut App) {
2185 let focus_id = self.focused(cx).map(|handle| handle.id);
2186
2187 let window = self.handle;
2188 cx.defer(move |cx| {
2189 window
2190 .update(cx, |_, window, cx| {
2191 let node_id = window.focus_node_id_in_rendered_frame(focus_id);
2192 window.dispatch_action_on_node(node_id, action.as_ref(), cx);
2193 })
2194 .log_err();
2195 })
2196 }
2197
2198 pub(crate) fn dispatch_keystroke_observers(
2199 &mut self,
2200 keystroke: &Keystroke,
2201 input_preference: InputPreference,
2202 action: Option<&dyn Action>,
2203 context_stack: Vec<KeyContext>,
2204 cx: &mut App,
2205 ) {
2206 cx.keystroke_observers.clone().retain(&(), move |callback| {
2207 (callback)(
2208 &KeystrokeEvent {
2209 keystroke: keystroke.clone(),
2210 input_preference,
2211 action: action.map(|action| action.boxed_clone()),
2212 context_stack: context_stack.clone(),
2213 },
2214 self,
2215 cx,
2216 )
2217 });
2218 }
2219
2220 pub(crate) fn dispatch_keystroke_interceptors(
2221 &mut self,
2222 keystroke: &Keystroke,
2223 input_preference: InputPreference,
2224 context_stack: Vec<KeyContext>,
2225 cx: &mut App,
2226 ) {
2227 cx.keystroke_interceptors
2228 .clone()
2229 .retain(&(), move |callback| {
2230 (callback)(
2231 &KeystrokeEvent {
2232 keystroke: keystroke.clone(),
2233 input_preference,
2234 action: None,
2235 context_stack: context_stack.clone(),
2236 },
2237 self,
2238 cx,
2239 )
2240 });
2241 }
2242
2243 pub fn defer(&self, cx: &mut App, f: impl FnOnce(&mut Window, &mut App) + 'static) {
2246 let handle = self.handle;
2247 cx.defer(move |cx| {
2248 handle.update(cx, |_, window, cx| f(window, cx)).ok();
2249 });
2250 }
2251
2252 pub fn observe<T: 'static>(
2256 &mut self,
2257 observed: &Entity<T>,
2258 cx: &mut App,
2259 mut on_notify: impl FnMut(Entity<T>, &mut Window, &mut App) + 'static,
2260 ) -> Subscription {
2261 let entity_id = observed.entity_id();
2262 let observed = observed.downgrade();
2263 let window_handle = self.handle;
2264 cx.new_observer(
2265 entity_id,
2266 Box::new(move |cx| {
2267 window_handle
2268 .update(cx, |_, window, cx| {
2269 if let Some(handle) = observed.upgrade() {
2270 on_notify(handle, window, cx);
2271 true
2272 } else {
2273 false
2274 }
2275 })
2276 .unwrap_or(false)
2277 }),
2278 )
2279 }
2280
2281 pub fn subscribe<Emitter, Evt>(
2285 &mut self,
2286 entity: &Entity<Emitter>,
2287 cx: &mut App,
2288 mut on_event: impl FnMut(Entity<Emitter>, &Evt, &mut Window, &mut App) + 'static,
2289 ) -> Subscription
2290 where
2291 Emitter: EventEmitter<Evt>,
2292 Evt: 'static,
2293 {
2294 let entity_id = entity.entity_id();
2295 let handle = entity.downgrade();
2296 let window_handle = self.handle;
2297 cx.new_subscription(
2298 entity_id,
2299 (
2300 TypeId::of::<Evt>(),
2301 Box::new(move |event, cx| {
2302 window_handle
2303 .update(cx, |_, window, cx| {
2304 if let Some(entity) = handle.upgrade() {
2305 let event = event.downcast_ref().expect("invalid event type");
2306 on_event(entity, event, window, cx);
2307 true
2308 } else {
2309 false
2310 }
2311 })
2312 .unwrap_or(false)
2313 }),
2314 ),
2315 )
2316 }
2317
2318 pub fn observe_release<T>(
2320 &self,
2321 entity: &Entity<T>,
2322 cx: &mut App,
2323 mut on_release: impl FnOnce(&mut T, &mut Window, &mut App) + 'static,
2324 ) -> Subscription
2325 where
2326 T: 'static,
2327 {
2328 let entity_id = entity.entity_id();
2329 let window_handle = self.handle;
2330 let (subscription, activate) = cx.release_listeners.insert(
2331 entity_id,
2332 Box::new(move |entity, cx| {
2333 let entity = entity.downcast_mut().expect("invalid entity type");
2334 let _ = window_handle.update(cx, |_, window, cx| on_release(entity, window, cx));
2335 }),
2336 );
2337 activate();
2338 subscription
2339 }
2340
2341 pub fn to_async(&self, cx: &App) -> AsyncWindowContext {
2344 AsyncWindowContext::new_context(cx.to_async(), self.handle)
2345 }
2346
2347 pub fn on_next_frame(&self, callback: impl FnOnce(&mut Window, &mut App) + 'static) {
2349 RefCell::borrow_mut(&self.next_frame_callbacks).push(Box::new(callback));
2350 self.platform_window.schedule_frame();
2351 }
2352
2353 pub fn request_animation_frame(&self) {
2360 let entity = self.current_view();
2361 self.on_next_frame(move |_, cx| cx.notify(entity));
2362 }
2363
2364 #[track_caller]
2368 pub fn spawn<AsyncFn, R>(&self, cx: &App, f: AsyncFn) -> Task<R>
2369 where
2370 R: 'static,
2371 AsyncFn: AsyncFnOnce(&mut AsyncWindowContext) -> R + 'static,
2372 {
2373 let handle = self.handle;
2374 cx.spawn(async move |app| {
2375 let mut async_window_cx = AsyncWindowContext::new_context(app.clone(), handle);
2376 f(&mut async_window_cx).await
2377 })
2378 }
2379
2380 fn bounds_changed(&mut self, cx: &mut App) {
2381 self.scale_factor = self.platform_window.scale_factor();
2382 self.viewport_size = self.platform_window.content_size();
2383 self.display_id = self.platform_window.display().map(|display| display.id());
2384 self.mouse_position = self.platform_window.mouse_position();
2385 self.platform_window.a11y_update_window_bounds();
2386
2387 self.refresh();
2388
2389 self.bounds_observers
2390 .clone()
2391 .retain(&(), |callback| callback(self, cx));
2392 }
2393
2394 pub fn bounds(&self) -> Bounds<Pixels> {
2396 self.platform_window.bounds()
2397 }
2398
2399 pub fn resize(&mut self, size: Size<Pixels>) {
2401 self.platform_window.resize(size);
2402 }
2403
2404 pub fn is_fullscreen(&self) -> bool {
2406 self.platform_window.is_fullscreen()
2407 }
2408
2409 pub fn is_simple_fullscreen(&self) -> bool {
2413 self.platform_window.is_simple_fullscreen()
2414 }
2415
2416 pub(crate) fn appearance_changed(&mut self, cx: &mut App) {
2417 self.appearance = self.platform_window.appearance();
2418
2419 self.appearance_observers
2420 .clone()
2421 .retain(&(), |callback| callback(self, cx));
2422 }
2423
2424 pub fn appearance(&self) -> WindowAppearance {
2426 self.appearance
2427 }
2428
2429 pub fn viewport_size(&self) -> Size<Pixels> {
2431 self.viewport_size
2432 }
2433
2434 pub fn is_window_active(&self) -> bool {
2436 self.active.get()
2437 }
2438
2439 pub fn is_window_hovered(&self) -> bool {
2443 if cfg!(any(
2444 target_os = "windows",
2445 target_os = "linux",
2446 target_os = "freebsd"
2447 )) {
2448 self.hovered.get()
2449 } else {
2450 self.is_window_active()
2451 }
2452 }
2453
2454 pub fn last_input_was_keyboard(&self) -> bool {
2457 self.last_input_was_keyboard.get()
2458 }
2459
2460 pub fn zoom_window(&self) {
2462 self.platform_window.zoom();
2463 }
2464
2465 pub fn show_window_menu(&self, position: Point<Pixels>) {
2467 self.platform_window.show_window_menu(position)
2468 }
2469
2470 pub fn start_window_move(&self) {
2474 self.platform_window.start_window_move()
2475 }
2476
2477 pub fn set_client_inset(&mut self, inset: Pixels) {
2479 self.client_inset = Some(inset);
2480 self.platform_window.set_client_inset(inset);
2481 }
2482
2483 pub fn client_inset(&self) -> Option<Pixels> {
2485 self.client_inset
2486 }
2487
2488 pub fn window_decorations(&self) -> Decorations {
2490 self.platform_window.window_decorations()
2491 }
2492
2493 pub fn window_controls(&self) -> WindowControls {
2495 self.platform_window.window_controls()
2496 }
2497
2498 pub fn set_window_title(&mut self, title: &str) {
2500 self.platform_window.set_title(title);
2501 }
2502
2503 pub fn set_app_id(&mut self, app_id: &str) {
2505 self.platform_window.set_app_id(app_id);
2506 }
2507
2508 pub fn set_background_appearance(&self, background_appearance: WindowBackgroundAppearance) {
2510 self.platform_window
2511 .set_background_appearance(background_appearance);
2512 }
2513
2514 pub fn set_window_edited(&mut self, edited: bool) {
2516 self.platform_window.set_edited(edited);
2517 }
2518
2519 pub fn display(&self, cx: &App) -> Option<Rc<dyn PlatformDisplay>> {
2521 cx.platform
2522 .displays()
2523 .into_iter()
2524 .find(|display| Some(display.id()) == self.display_id)
2525 }
2526
2527 pub fn show_character_palette(&self) {
2529 self.platform_window.show_character_palette();
2530 }
2531
2532 pub fn scale_factor(&self) -> f32 {
2536 self.scale_factor
2537 }
2538
2539 pub fn rem_size(&self) -> Pixels {
2542 self.rem_size_override_stack
2543 .last()
2544 .copied()
2545 .unwrap_or(self.rem_size)
2546 }
2547
2548 pub fn set_rem_size(&mut self, rem_size: impl Into<Pixels>) {
2551 self.rem_size = rem_size.into();
2552 }
2553
2554 pub fn with_global_id<R>(
2557 &mut self,
2558 element_id: ElementId,
2559 f: impl FnOnce(&GlobalElementId, &mut Self) -> R,
2560 ) -> R {
2561 self.element_id_stack.push(element_id);
2562 let global_id = GlobalElementId(self.element_id_stack.clone());
2563 let result = f(&global_id, self);
2564 self.element_id_stack.pop();
2565 result
2566 }
2567
2568 pub fn with_rem_size<F, R>(&mut self, rem_size: Option<impl Into<Pixels>>, f: F) -> R
2572 where
2573 F: FnOnce(&mut Self) -> R,
2574 {
2575 self.invalidator.debug_assert_paint_or_prepaint();
2576
2577 if let Some(rem_size) = rem_size {
2578 self.rem_size_override_stack.push(rem_size.into());
2579 let result = f(self);
2580 self.rem_size_override_stack.pop();
2581 result
2582 } else {
2583 f(self)
2584 }
2585 }
2586
2587 pub fn line_height(&self) -> Pixels {
2589 self.text_style().line_height_in_pixels(self.rem_size())
2590 }
2591
2592 #[inline]
2594 pub fn pixel_snap(&self, value: Pixels) -> Pixels {
2595 px(round_to_device_pixel(value.0, self.scale_factor()) / self.scale_factor())
2596 }
2597
2598 #[inline]
2600 pub fn pixel_snap_f64(&self, value: f64) -> f64 {
2601 let scale_factor = f64::from(self.scale_factor());
2602 round_half_toward_zero_f64(value * scale_factor) / scale_factor
2603 }
2604
2605 #[inline]
2607 pub fn pixel_snap_bounds(&self, bounds: Bounds<Pixels>) -> Bounds<Pixels> {
2608 bounds.map(|c| self.pixel_snap(c))
2609 }
2610
2611 #[inline]
2613 pub fn pixel_snap_point(&self, position: Point<Pixels>) -> Point<Pixels> {
2614 position.map(|c| self.pixel_snap(c))
2615 }
2616
2617 #[inline]
2618 fn snap_bounds(&self, bounds: Bounds<Pixels>) -> Bounds<ScaledPixels> {
2619 let scale_factor = self.scale_factor();
2620 let left = round_to_device_pixel(bounds.left().0, scale_factor);
2621 let top = round_to_device_pixel(bounds.top().0, scale_factor);
2622 let right = round_to_device_pixel(bounds.right().0, scale_factor).max(left);
2623 let bottom = round_to_device_pixel(bounds.bottom().0, scale_factor).max(top);
2624 Bounds::from_corners(
2625 point(ScaledPixels(left), ScaledPixels(top)),
2626 point(ScaledPixels(right), ScaledPixels(bottom)),
2627 )
2628 }
2629
2630 #[inline]
2631 fn snap_stroke(&self, value: Pixels) -> ScaledPixels {
2632 ScaledPixels(round_stroke_to_device_pixel(value.0, self.scale_factor()))
2633 }
2634
2635 #[inline]
2636 fn snap_border_widths(&self, edges: Edges<Pixels>) -> Edges<ScaledPixels> {
2637 edges.map(|e| self.snap_stroke(*e))
2638 }
2639
2640 #[inline]
2641 fn cover_bounds(&self, bounds: Bounds<Pixels>) -> Bounds<ScaledPixels> {
2642 let scale_factor = self.scale_factor();
2643 let left = floor_to_device_pixel(bounds.left().0, scale_factor);
2644 let top = floor_to_device_pixel(bounds.top().0, scale_factor);
2645 let right = ceil_to_device_pixel(bounds.right().0, scale_factor).max(left);
2646 let bottom = ceil_to_device_pixel(bounds.bottom().0, scale_factor).max(top);
2647 Bounds::from_corners(
2648 point(ScaledPixels(left), ScaledPixels(top)),
2649 point(ScaledPixels(right), ScaledPixels(bottom)),
2650 )
2651 }
2652
2653 #[inline]
2654 fn snapped_content_mask(&self) -> ContentMask<ScaledPixels> {
2655 ContentMask {
2656 bounds: self.cover_bounds(self.content_mask().bounds),
2657 }
2658 }
2659
2660 pub fn prevent_default(&mut self) {
2663 self.default_prevented = true;
2664 }
2665
2666 pub fn default_prevented(&self) -> bool {
2668 self.default_prevented
2669 }
2670
2671 pub fn is_action_available(&self, action: &dyn Action, cx: &mut App) -> bool {
2673 let node_id =
2674 self.focus_node_id_in_rendered_frame(self.focused(cx).map(|handle| handle.id));
2675 self.rendered_frame
2676 .dispatch_tree
2677 .is_action_available(action, node_id)
2678 }
2679
2680 pub fn mouse_position(&self) -> Point<Pixels> {
2682 self.mouse_position
2683 }
2684
2685 pub fn capture_pointer(&mut self, hitbox_id: HitboxId) {
2692 self.captured_hitbox = Some(hitbox_id);
2693 }
2694
2695 pub fn release_pointer(&mut self) {
2697 self.captured_hitbox = None;
2698 }
2699
2700 pub fn captured_hitbox(&self) -> Option<HitboxId> {
2702 self.captured_hitbox
2703 }
2704
2705 pub fn modifiers(&self) -> Modifiers {
2707 self.modifiers
2708 }
2709
2710 pub fn capslock(&self) -> Capslock {
2712 self.capslock
2713 }
2714
2715 #[profiling::function]
2718 pub fn draw(&mut self, cx: &mut App) -> ArenaClearNeeded {
2719 let arena_scope = ElementArenaScope::enter();
2720 self.invalidate_entities();
2721 cx.entities.clear_accessed();
2722 debug_assert!(self.rendered_entity_stack.is_empty());
2723 self.invalidator.set_dirty(false);
2724 self.requested_autoscroll = None;
2725
2726 if let Some(input_handler) = self.platform_window.take_input_handler() {
2728 if let Some(slot) = self
2729 .rendered_frame
2730 .input_handlers
2731 .iter_mut()
2732 .rev()
2733 .find(|handler| handler.is_none())
2734 {
2735 *slot = Some(input_handler);
2736 } else {
2737 self.rendered_frame.input_handlers.push(Some(input_handler));
2738 }
2739 }
2740 self.draw_roots(cx);
2741 self.dirty_views.clear();
2742 self.next_frame.window_active = self.active.get();
2743
2744 if let Some(input_handler) = self
2746 .next_frame
2747 .input_handlers
2748 .iter_mut()
2749 .rev()
2750 .find_map(|handler| handler.take())
2751 {
2752 self.platform_window.set_input_handler(input_handler);
2753 }
2754
2755 self.layout_engine.as_mut().unwrap().clear();
2756 self.text_system().finish_frame();
2757 self.next_frame.finish(&mut self.rendered_frame);
2758
2759 self.invalidator.set_phase(DrawPhase::Focus);
2760 let previous_focus_path = self.rendered_frame.focus_path();
2761 let previous_window_active = self.rendered_frame.window_active;
2762 mem::swap(&mut self.rendered_frame, &mut self.next_frame);
2763 self.next_frame.clear();
2764 let current_focus_path = self.rendered_frame.focus_path();
2765 let current_window_active = self.rendered_frame.window_active;
2766
2767 if previous_focus_path != current_focus_path
2768 || previous_window_active != current_window_active
2769 {
2770 if !previous_focus_path.is_empty() && current_focus_path.is_empty() {
2771 self.focus_lost_path = previous_focus_path.clone();
2772 self.focus_lost_listeners
2773 .clone()
2774 .retain(&(), |listener| listener(self, cx));
2775 self.focus_lost_path = SmallVec::new();
2776 }
2777
2778 let event = WindowFocusEvent {
2779 previous_focus_path: if previous_window_active {
2780 previous_focus_path
2781 } else {
2782 Default::default()
2783 },
2784 current_focus_path: if current_window_active {
2785 current_focus_path
2786 } else {
2787 Default::default()
2788 },
2789 };
2790 self.focus_listeners
2791 .clone()
2792 .retain(&(), |listener| listener(&event, self, cx));
2793 }
2794
2795 debug_assert!(self.rendered_entity_stack.is_empty());
2796 self.record_entities_accessed(cx);
2797 self.reset_cursor_style(cx);
2798 self.refreshing = false;
2799 self.invalidator.set_phase(DrawPhase::None);
2800 self.needs_present.set(true);
2801
2802 drop(arena_scope);
2803 ArenaClearNeeded
2804 }
2805
2806 #[cfg(any(test, feature = "test-support"))]
2808 pub fn visual_render_artifact(&self) -> crate::VisualRenderArtifact {
2809 crate::VisualRenderArtifact::from_scene(&self.rendered_frame.scene)
2810 }
2811
2812 #[cfg(any(test, feature = "test-support"))]
2814 pub fn present_for_visual_test(&mut self) {
2815 self.present();
2816 }
2817
2818 #[cfg(any(test, feature = "test-support"))]
2820 pub fn render_to_image(&self) -> anyhow::Result<image::RgbaImage> {
2821 self.platform_window
2822 .render_to_image(&self.rendered_frame.scene)
2823 }
2824
2825 #[cfg(any(test, feature = "test-support"))]
2830 pub fn painted_quads(&self) -> Vec<Quad> {
2831 self.rendered_frame.scene.quads.clone()
2832 }
2833
2834 fn record_entities_accessed(&mut self, cx: &mut App) {
2835 let mut entities_ref = cx.entities.accessed_entities.borrow_mut();
2836 let mut entities = mem::take(entities_ref.deref_mut());
2837 drop(entities_ref);
2838 let handle = self.handle;
2839 cx.record_entities_accessed(
2840 handle,
2841 self.invalidator.clone(),
2843 &entities,
2844 );
2845 let mut entities_ref = cx.entities.accessed_entities.borrow_mut();
2846 mem::swap(&mut entities, entities_ref.deref_mut());
2847 }
2848
2849 fn invalidate_entities(&mut self) {
2850 let mut views = self.invalidator.take_views();
2851 for entity in views.drain() {
2852 self.mark_view_dirty(entity);
2853 }
2854 self.invalidator.replace_views(views);
2855 }
2856
2857 #[profiling::function]
2858 fn present(&mut self) {
2859 self.platform_window.draw(&self.rendered_frame.scene);
2860 #[cfg(feature = "input-latency-histogram")]
2861 self.input_latency_tracker.record_frame_presented();
2862 self.needs_present.set(false);
2863 profiling::finish_frame!();
2864 }
2865
2866 #[cfg(feature = "input-latency-histogram")]
2868 pub fn input_latency_snapshot(&self) -> InputLatencySnapshot {
2869 self.input_latency_tracker.snapshot()
2870 }
2871
2872 fn draw_roots(&mut self, cx: &mut App) {
2873 self.invalidator.set_phase(DrawPhase::Prepaint);
2874 self.tooltip_bounds.take();
2875
2876 self.a11y.sync_active_flag();
2877 if self.a11y.is_active() {
2878 self.a11y.begin_frame();
2879 }
2880
2881 let _inspector_width: Pixels = rems(30.0).to_pixels(self.rem_size());
2882 let root_size = {
2883 #[cfg(any(feature = "inspector", debug_assertions))]
2884 {
2885 if self.inspector.is_some() {
2886 let mut size = self.viewport_size;
2887 size.width = (size.width - _inspector_width).max(px(0.0));
2888 size
2889 } else {
2890 self.viewport_size
2891 }
2892 }
2893 #[cfg(not(any(feature = "inspector", debug_assertions)))]
2894 {
2895 self.viewport_size
2896 }
2897 };
2898
2899 let scale_factor = self.scale_factor();
2901 let mut root_element = self.root.as_ref().unwrap().clone().into_any();
2902 let root_layout_id = root_element.request_layout(self, cx);
2903 self.layout_engine
2904 .as_mut()
2905 .unwrap()
2906 .stretch_auto_size_to_fill(root_layout_id, root_size, scale_factor);
2907 root_element.prepaint_as_root(Point::default(), root_size.into(), self, cx);
2908
2909 #[cfg(any(feature = "inspector", debug_assertions))]
2910 let inspector_element = self.prepaint_inspector(_inspector_width, cx);
2911
2912 self.prepaint_deferred_draws(cx);
2913
2914 let mut prompt_element = None;
2915 let mut active_drag_element = None;
2916 let mut tooltip_element = None;
2917 if let Some(prompt) = self.prompt.take() {
2918 let mut element = prompt.view.any_view().into_any();
2919 let prompt_layout_id = element.request_layout(self, cx);
2920 self.layout_engine
2921 .as_mut()
2922 .unwrap()
2923 .stretch_auto_size_to_fill(prompt_layout_id, root_size, scale_factor);
2924 element.prepaint_as_root(Point::default(), root_size.into(), self, cx);
2925 prompt_element = Some(element);
2926 self.prompt = Some(prompt);
2927 } else if let Some(active_drag) = cx.active_drag.take() {
2928 let mut element = active_drag.view.clone().into_any();
2929 let offset = self.mouse_position() - active_drag.cursor_offset;
2930 element.prepaint_as_root(offset, AvailableSpace::min_size(), self, cx);
2931 active_drag_element = Some(element);
2932 cx.active_drag = Some(active_drag);
2933 } else {
2934 tooltip_element = self.prepaint_tooltip(cx);
2935 }
2936
2937 self.mouse_hit_test = self.next_frame.hit_test(self.mouse_position);
2938
2939 self.invalidator.set_phase(DrawPhase::Paint);
2941 root_element.paint(self, cx);
2942
2943 #[cfg(any(feature = "inspector", debug_assertions))]
2944 self.paint_inspector(inspector_element, cx);
2945
2946 let mut sorted_deferred_draws =
2947 (0..self.next_frame.deferred_draws.len()).collect::<SmallVec<[_; 8]>>();
2948 sorted_deferred_draws.sort_by_key(|ix| self.next_frame.deferred_draws[*ix].priority);
2949 self.paint_deferred_draws(&sorted_deferred_draws, cx);
2950
2951 if let Some(mut prompt_element) = prompt_element {
2952 prompt_element.paint(self, cx);
2953 } else if let Some(mut drag_element) = active_drag_element {
2954 drag_element.paint(self, cx);
2955 } else if let Some(mut tooltip_element) = tooltip_element {
2956 tooltip_element.paint(self, cx);
2957 }
2958
2959 #[cfg(any(feature = "inspector", debug_assertions))]
2960 self.paint_inspector_hitbox(cx);
2961
2962 let a11y_active_start_of_frame = self.a11y.is_active();
2963 self.a11y.sync_active_flag();
2964 let a11y_active_end_of_frame = self.a11y.is_active();
2965
2966 if a11y_active_start_of_frame {
2967 let tree_update = self.a11y.end_frame();
2968 if a11y_active_end_of_frame {
2969 log::debug!(
2970 "Sending a11y tree update: {} nodes",
2971 tree_update.nodes.len()
2972 );
2973 self.platform_window.a11y_tree_update(tree_update);
2974 }
2975 }
2976 }
2977
2978 fn prepaint_tooltip(&mut self, cx: &mut App) -> Option<AnyElement> {
2979 for tooltip_request_index in (0..self.next_frame.tooltip_requests.len()).rev() {
2981 let Some(Some(tooltip_request)) = self
2982 .next_frame
2983 .tooltip_requests
2984 .get(tooltip_request_index)
2985 .cloned()
2986 else {
2987 log::error!("Unexpectedly absent TooltipRequest");
2988 continue;
2989 };
2990 let mut element = tooltip_request.tooltip.view.clone().into_any();
2991 let mouse_position = tooltip_request.tooltip.mouse_position;
2992 let tooltip_size = element.layout_as_root(AvailableSpace::min_size(), self, cx);
2993
2994 let mut tooltip_bounds =
2995 Bounds::new(mouse_position + point(px(1.), px(1.)), tooltip_size);
2996 let window_bounds = Bounds {
2997 origin: Point::default(),
2998 size: self.viewport_size(),
2999 };
3000
3001 if tooltip_bounds.right() > window_bounds.right() {
3002 let new_x = mouse_position.x - tooltip_bounds.size.width - px(1.);
3003 if new_x >= Pixels::ZERO {
3004 tooltip_bounds.origin.x = new_x;
3005 } else {
3006 tooltip_bounds.origin.x = cmp::max(
3007 Pixels::ZERO,
3008 tooltip_bounds.origin.x - tooltip_bounds.right() - window_bounds.right(),
3009 );
3010 }
3011 }
3012
3013 if tooltip_bounds.bottom() > window_bounds.bottom() {
3014 let new_y = mouse_position.y - tooltip_bounds.size.height - px(1.);
3015 if new_y >= Pixels::ZERO {
3016 tooltip_bounds.origin.y = new_y;
3017 } else {
3018 tooltip_bounds.origin.y = cmp::max(
3019 Pixels::ZERO,
3020 tooltip_bounds.origin.y - tooltip_bounds.bottom() - window_bounds.bottom(),
3021 );
3022 }
3023 }
3024
3025 let is_visible =
3029 (tooltip_request.tooltip.check_visible_and_update)(tooltip_bounds, self, cx);
3030 if !is_visible {
3031 continue;
3032 }
3033
3034 self.with_absolute_element_offset(tooltip_bounds.origin, |window| {
3035 element.prepaint(window, cx)
3036 });
3037
3038 self.tooltip_bounds = Some(TooltipBounds {
3039 id: tooltip_request.id,
3040 bounds: tooltip_bounds,
3041 });
3042 return Some(element);
3043 }
3044 None
3045 }
3046
3047 fn prepaint_deferred_draws(&mut self, cx: &mut App) {
3048 assert_eq!(self.element_id_stack.len(), 0);
3049
3050 let mut round_start = 0;
3053 let mut depth = 0;
3054 loop {
3055 let round_end = self.next_frame.deferred_draws.len();
3056 if round_start == round_end {
3057 break;
3058 }
3059
3060 assert!(depth < 10, "Exceeded maximum (10) deferred depth");
3061 depth += 1;
3062
3063 let mut traversal_order = (round_start..round_end).collect::<SmallVec<[usize; 8]>>();
3064 traversal_order.sort_by_key(|ix| self.next_frame.deferred_draws[*ix].priority);
3065
3066 for deferred_draw_ix in traversal_order {
3067 let (element, parent_node, current_view, absolute_offset, prepaint_range) = {
3068 let deferred_draw = &mut self.next_frame.deferred_draws[deferred_draw_ix];
3069 self.element_id_stack
3070 .clone_from(&deferred_draw.element_id_stack);
3071 self.text_style_stack
3072 .clone_from(&deferred_draw.text_style_stack);
3073 (
3074 deferred_draw.element.take(),
3075 deferred_draw.parent_node,
3076 deferred_draw.current_view,
3077 deferred_draw.absolute_offset,
3078 deferred_draw.prepaint_range.clone(),
3079 )
3080 };
3081 self.next_frame.dispatch_tree.set_active_node(parent_node);
3082
3083 let prepaint_start = self.prepaint_index();
3084 if let Some(mut element) = element {
3085 self.with_rendered_view(current_view, |window| {
3086 window.with_absolute_element_offset(absolute_offset, |window| {
3087 element.prepaint(window, cx)
3088 });
3089 });
3090 self.next_frame.deferred_draws[deferred_draw_ix].element = Some(element);
3091 } else {
3092 self.reuse_prepaint(prepaint_range);
3093 }
3094 let prepaint_end = self.prepaint_index();
3095 self.next_frame.deferred_draws[deferred_draw_ix].prepaint_range =
3096 prepaint_start..prepaint_end;
3097 }
3098
3099 self.element_id_stack.clear();
3100 self.text_style_stack.clear();
3101 round_start = round_end;
3102 }
3103 }
3104
3105 fn paint_deferred_draws(&mut self, deferred_draw_indices: &[usize], cx: &mut App) {
3106 assert_eq!(self.element_id_stack.len(), 0);
3107
3108 let mut deferred_draws = mem::take(&mut self.next_frame.deferred_draws);
3109 for deferred_draw_ix in deferred_draw_indices {
3110 let mut deferred_draw = &mut deferred_draws[*deferred_draw_ix];
3111 self.element_id_stack
3112 .clone_from(&deferred_draw.element_id_stack);
3113 self.next_frame
3114 .dispatch_tree
3115 .set_active_node(deferred_draw.parent_node);
3116
3117 let paint_start = self.paint_index();
3118 if let Some(element) = deferred_draw.element.as_mut() {
3119 self.with_rendered_view(deferred_draw.current_view, |window| {
3120 element.paint(window, cx);
3121 })
3122 } else {
3123 self.reuse_paint(deferred_draw.paint_range.clone());
3124 }
3125 let paint_end = self.paint_index();
3126 deferred_draw.paint_range = paint_start..paint_end;
3127 }
3128 self.next_frame.deferred_draws = deferred_draws;
3129 self.element_id_stack.clear();
3130 }
3131
3132 pub(crate) fn prepaint_index(&self) -> PrepaintStateIndex {
3133 PrepaintStateIndex {
3134 hitboxes_index: self.next_frame.hitboxes.len(),
3135 tooltips_index: self.next_frame.tooltip_requests.len(),
3136 deferred_draws_index: self.next_frame.deferred_draws.len(),
3137 dispatch_tree_index: self.next_frame.dispatch_tree.len(),
3138 accessed_element_states_index: self.next_frame.accessed_element_states.len(),
3139 line_layout_index: self.text_system.layout_index(),
3140 }
3141 }
3142
3143 pub(crate) fn reuse_prepaint(&mut self, range: Range<PrepaintStateIndex>) {
3144 self.next_frame.hitboxes.extend(
3145 self.rendered_frame.hitboxes[range.start.hitboxes_index..range.end.hitboxes_index]
3146 .iter()
3147 .cloned(),
3148 );
3149 self.next_frame.tooltip_requests.extend(
3150 self.rendered_frame.tooltip_requests
3151 [range.start.tooltips_index..range.end.tooltips_index]
3152 .iter_mut()
3153 .map(|request| request.take()),
3154 );
3155 self.next_frame.accessed_element_states.extend(
3156 self.rendered_frame.accessed_element_states[range.start.accessed_element_states_index
3157 ..range.end.accessed_element_states_index]
3158 .iter()
3159 .map(|(id, type_id)| (GlobalElementId(id.0.clone()), *type_id)),
3160 );
3161 self.text_system
3162 .reuse_layouts(range.start.line_layout_index..range.end.line_layout_index);
3163
3164 let reused_subtree = self.next_frame.dispatch_tree.reuse_subtree(
3165 range.start.dispatch_tree_index..range.end.dispatch_tree_index,
3166 &mut self.rendered_frame.dispatch_tree,
3167 self.focus,
3168 );
3169
3170 if reused_subtree.contains_focus() {
3171 self.next_frame.focus = self.focus;
3172 }
3173
3174 self.next_frame.deferred_draws.extend(
3175 self.rendered_frame.deferred_draws
3176 [range.start.deferred_draws_index..range.end.deferred_draws_index]
3177 .iter()
3178 .map(|deferred_draw| DeferredDraw {
3179 current_view: deferred_draw.current_view,
3180 parent_node: reused_subtree.refresh_node_id(deferred_draw.parent_node),
3181 element_id_stack: deferred_draw.element_id_stack.clone(),
3182 text_style_stack: deferred_draw.text_style_stack.clone(),
3183 priority: deferred_draw.priority,
3184 element: None,
3185 absolute_offset: deferred_draw.absolute_offset,
3186 prepaint_range: deferred_draw.prepaint_range.clone(),
3187 paint_range: deferred_draw.paint_range.clone(),
3188 }),
3189 );
3190 }
3191
3192 pub(crate) fn paint_index(&self) -> PaintIndex {
3193 PaintIndex {
3194 scene_index: self.next_frame.scene.len(),
3195 #[cfg(any(test, feature = "test-support"))]
3196 debug_bounds_index: self.next_frame.debug_bounds_records.len(),
3197 mouse_listeners_index: self.next_frame.mouse_listeners.len(),
3198 input_handlers_index: self.next_frame.input_handlers.len(),
3199 cursor_styles_index: self.next_frame.cursor_styles.len(),
3200 accessed_element_states_index: self.next_frame.accessed_element_states.len(),
3201 tab_handle_index: self.next_frame.tab_stops.paint_index(),
3202 line_layout_index: self.text_system.layout_index(),
3203 }
3204 }
3205
3206 pub(crate) fn reuse_paint(&mut self, range: Range<PaintIndex>) {
3207 #[cfg(any(test, feature = "test-support"))]
3209 for (selector, bounds) in &self.rendered_frame.debug_bounds_records
3210 [range.start.debug_bounds_index..range.end.debug_bounds_index]
3211 {
3212 self.next_frame
3213 .record_debug_bounds(selector.clone(), *bounds);
3214 }
3215 self.next_frame.cursor_styles.extend(
3216 self.rendered_frame.cursor_styles
3217 [range.start.cursor_styles_index..range.end.cursor_styles_index]
3218 .iter()
3219 .cloned(),
3220 );
3221 self.next_frame.input_handlers.extend(
3222 self.rendered_frame.input_handlers
3223 [range.start.input_handlers_index..range.end.input_handlers_index]
3224 .iter_mut()
3225 .map(|handler| handler.take()),
3226 );
3227 self.next_frame.mouse_listeners.extend(
3228 self.rendered_frame.mouse_listeners
3229 [range.start.mouse_listeners_index..range.end.mouse_listeners_index]
3230 .iter_mut()
3231 .map(|listener| listener.take()),
3232 );
3233 self.next_frame.accessed_element_states.extend(
3234 self.rendered_frame.accessed_element_states[range.start.accessed_element_states_index
3235 ..range.end.accessed_element_states_index]
3236 .iter()
3237 .map(|(id, type_id)| (GlobalElementId(id.0.clone()), *type_id)),
3238 );
3239 self.next_frame.tab_stops.replay(
3240 &self.rendered_frame.tab_stops.insertion_history
3241 [range.start.tab_handle_index..range.end.tab_handle_index],
3242 );
3243
3244 self.text_system
3245 .reuse_layouts(range.start.line_layout_index..range.end.line_layout_index);
3246 self.next_frame.scene.replay(
3247 range.start.scene_index..range.end.scene_index,
3248 &self.rendered_frame.scene,
3249 );
3250 }
3251
3252 pub fn with_text_style<F, R>(&mut self, style: Option<TextStyleRefinement>, f: F) -> R
3256 where
3257 F: FnOnce(&mut Self) -> R,
3258 {
3259 self.invalidator.debug_assert_paint_or_prepaint();
3260 if let Some(style) = style {
3261 self.text_style_stack.push(style);
3262 let result = f(self);
3263 self.text_style_stack.pop();
3264 result
3265 } else {
3266 f(self)
3267 }
3268 }
3269
3270 pub fn set_cursor_style(&mut self, style: CursorStyle, hitbox: &Hitbox) {
3273 self.invalidator.debug_assert_paint();
3274 self.next_frame.cursor_styles.push(CursorStyleRequest {
3275 hitbox_id: Some(hitbox.id),
3276 style,
3277 });
3278 }
3279
3280 pub fn set_window_cursor_style(&mut self, style: CursorStyle) {
3285 self.invalidator.debug_assert_paint();
3286 self.next_frame.cursor_styles.push(CursorStyleRequest {
3287 hitbox_id: None,
3288 style,
3289 })
3290 }
3291
3292 pub fn set_tooltip(&mut self, tooltip: AnyTooltip) -> TooltipId {
3295 self.invalidator.debug_assert_prepaint();
3296 let id = TooltipId(post_inc(&mut self.next_tooltip_id.0));
3297 self.next_frame
3298 .tooltip_requests
3299 .push(Some(TooltipRequest { id, tooltip }));
3300 id
3301 }
3302
3303 pub fn with_content_mask<R>(
3306 &mut self,
3307 mask: Option<ContentMask<Pixels>>,
3308 f: impl FnOnce(&mut Self) -> R,
3309 ) -> R {
3310 self.invalidator.debug_assert_paint_or_prepaint();
3311 if let Some(mask) = mask {
3312 let mask = mask.intersect(&self.content_mask());
3313 self.content_mask_stack.push(mask);
3314 let result = f(self);
3315 self.content_mask_stack.pop();
3316 result
3317 } else {
3318 f(self)
3319 }
3320 }
3321
3322 pub fn with_element_offset<R>(
3325 &mut self,
3326 offset: Point<Pixels>,
3327 f: impl FnOnce(&mut Self) -> R,
3328 ) -> R {
3329 self.invalidator.debug_assert_prepaint();
3330
3331 if offset.is_zero() {
3332 return f(self);
3333 };
3334
3335 let abs_offset = self.element_offset() + offset;
3336 self.with_absolute_element_offset(abs_offset, f)
3337 }
3338
3339 pub fn with_absolute_element_offset<R>(
3343 &mut self,
3344 offset: Point<Pixels>,
3345 f: impl FnOnce(&mut Self) -> R,
3346 ) -> R {
3347 self.invalidator.debug_assert_prepaint();
3348 self.element_offset_stack.push(offset);
3349 let result = f(self);
3350 self.element_offset_stack.pop();
3351 result
3352 }
3353
3354 pub(crate) fn with_element_opacity<R>(
3355 &mut self,
3356 opacity: Option<f32>,
3357 f: impl FnOnce(&mut Self) -> R,
3358 ) -> R {
3359 self.invalidator.debug_assert_paint_or_prepaint();
3360
3361 let Some(opacity) = opacity else {
3362 return f(self);
3363 };
3364
3365 let previous_opacity = self.element_opacity;
3366 self.element_opacity = previous_opacity * opacity;
3367 let result = f(self);
3368 self.element_opacity = previous_opacity;
3369 result
3370 }
3371
3372 pub fn transact<T, U>(&mut self, f: impl FnOnce(&mut Self) -> Result<T, U>) -> Result<T, U> {
3378 self.invalidator.debug_assert_prepaint();
3379 let index = self.prepaint_index();
3380 let result = f(self);
3381 if result.is_err() {
3382 self.next_frame.hitboxes.truncate(index.hitboxes_index);
3383 self.next_frame
3384 .tooltip_requests
3385 .truncate(index.tooltips_index);
3386 self.next_frame
3387 .deferred_draws
3388 .truncate(index.deferred_draws_index);
3389 self.next_frame
3390 .dispatch_tree
3391 .truncate(index.dispatch_tree_index);
3392 self.next_frame
3393 .accessed_element_states
3394 .truncate(index.accessed_element_states_index);
3395 self.text_system.truncate_layouts(index.line_layout_index);
3396 }
3397 result
3398 }
3399
3400 pub fn request_autoscroll(&mut self, bounds: Bounds<Pixels>) {
3406 self.invalidator.debug_assert_prepaint();
3407 self.requested_autoscroll = Some(bounds);
3408 }
3409
3410 pub fn take_autoscroll(&mut self) -> Option<Bounds<Pixels>> {
3413 self.invalidator.debug_assert_prepaint();
3414 self.requested_autoscroll.take()
3415 }
3416
3417 pub fn use_asset<A: Asset>(&mut self, source: &A::Source, cx: &mut App) -> Option<A::Output> {
3423 cx.asset_entry::<A>(source).use_by(self.current_view())
3424 }
3425
3426 pub fn get_asset<A: Asset>(&mut self, source: &A::Source, cx: &mut App) -> Option<A::Output> {
3432 cx.fetch_asset::<A>(source)
3433 }
3434 pub fn element_offset(&self) -> Point<Pixels> {
3437 self.invalidator.debug_assert_prepaint();
3438 self.element_offset_stack
3439 .last()
3440 .copied()
3441 .unwrap_or_default()
3442 }
3443
3444 #[inline]
3447 pub(crate) fn element_opacity(&self) -> f32 {
3448 self.invalidator.debug_assert_paint_or_prepaint();
3449 self.element_opacity
3450 }
3451
3452 pub fn content_mask(&self) -> ContentMask<Pixels> {
3454 self.invalidator.debug_assert_paint_or_prepaint();
3455 self.content_mask_stack
3456 .last()
3457 .cloned()
3458 .unwrap_or_else(|| ContentMask {
3459 bounds: Bounds {
3460 origin: Point::default(),
3461 size: self.viewport_size,
3462 },
3463 })
3464 }
3465
3466 pub fn with_element_namespace<R>(
3469 &mut self,
3470 element_id: impl Into<ElementId>,
3471 f: impl FnOnce(&mut Self) -> R,
3472 ) -> R {
3473 self.element_id_stack.push(element_id.into());
3474 let result = f(self);
3475 self.element_id_stack.pop();
3476 result
3477 }
3478
3479 pub fn use_keyed_state<S: 'static>(
3481 &mut self,
3482 key: impl Into<ElementId>,
3483 cx: &mut App,
3484 init: impl FnOnce(&mut Self, &mut Context<S>) -> S,
3485 ) -> Entity<S> {
3486 let current_view = self.current_view();
3487 self.with_global_id(key.into(), |global_id, window| {
3488 window.with_element_state(global_id, |state: Option<Entity<S>>, window| {
3489 if let Some(state) = state {
3490 (state.clone(), state)
3491 } else {
3492 let new_state = cx.new(|cx| init(window, cx));
3493 cx.observe(&new_state, move |_, cx| {
3494 cx.notify(current_view);
3495 })
3496 .detach();
3497 (new_state.clone(), new_state)
3498 }
3499 })
3500 })
3501 }
3502
3503 pub fn with_id<R>(&mut self, id: impl Into<ElementId>, f: impl FnOnce(&mut Self) -> R) -> R {
3505 self.with_global_id(id.into(), |_, window| f(window))
3506 }
3507
3508 #[track_caller]
3514 pub fn use_state<S: 'static>(
3515 &mut self,
3516 cx: &mut App,
3517 init: impl FnOnce(&mut Self, &mut Context<S>) -> S,
3518 ) -> Entity<S> {
3519 self.use_keyed_state(
3520 ElementId::CodeLocation(*core::panic::Location::caller()),
3521 cx,
3522 init,
3523 )
3524 }
3525
3526 pub fn with_element_state<S, R>(
3531 &mut self,
3532 global_id: &GlobalElementId,
3533 f: impl FnOnce(Option<S>, &mut Self) -> (R, S),
3534 ) -> R
3535 where
3536 S: 'static,
3537 {
3538 self.invalidator.debug_assert_paint_or_prepaint();
3539
3540 let key = (GlobalElementId(global_id.0.clone()), TypeId::of::<S>());
3541 self.next_frame
3542 .accessed_element_states
3543 .push((GlobalElementId(key.0.clone()), TypeId::of::<S>()));
3544
3545 if let Some(any) = self
3546 .next_frame
3547 .element_states
3548 .remove(&key)
3549 .or_else(|| self.rendered_frame.element_states.remove(&key))
3550 {
3551 let ElementStateBox {
3552 inner,
3553 #[cfg(debug_assertions)]
3554 type_name,
3555 } = any;
3556 let mut state_box = inner
3558 .downcast::<Option<S>>()
3559 .map_err(|_| {
3560 #[cfg(debug_assertions)]
3561 {
3562 anyhow::anyhow!(
3563 "invalid element state type for id, requested {:?}, actual: {:?}",
3564 std::any::type_name::<S>(),
3565 type_name
3566 )
3567 }
3568
3569 #[cfg(not(debug_assertions))]
3570 {
3571 anyhow::anyhow!(
3572 "invalid element state type for id, requested {:?}",
3573 std::any::type_name::<S>(),
3574 )
3575 }
3576 })
3577 .unwrap();
3578
3579 let state = state_box.take().expect(
3580 "reentrant call to with_element_state for the same state type and element id",
3581 );
3582 let (result, state) = f(Some(state), self);
3583 state_box.replace(state);
3584 self.next_frame.element_states.insert(
3585 key,
3586 ElementStateBox {
3587 inner: state_box,
3588 #[cfg(debug_assertions)]
3589 type_name,
3590 },
3591 );
3592 result
3593 } else {
3594 let (result, state) = f(None, self);
3595 self.next_frame.element_states.insert(
3596 key,
3597 ElementStateBox {
3598 inner: Box::new(Some(state)),
3599 #[cfg(debug_assertions)]
3600 type_name: std::any::type_name::<S>(),
3601 },
3602 );
3603 result
3604 }
3605 }
3606
3607 pub fn with_optional_element_state<S, R>(
3614 &mut self,
3615 global_id: Option<&GlobalElementId>,
3616 f: impl FnOnce(Option<Option<S>>, &mut Self) -> (R, Option<S>),
3617 ) -> R
3618 where
3619 S: 'static,
3620 {
3621 self.invalidator.debug_assert_paint_or_prepaint();
3622
3623 if let Some(global_id) = global_id {
3624 self.with_element_state(global_id, |state, cx| {
3625 let (result, state) = f(Some(state), cx);
3626 let state =
3627 state.expect("you must return some state when you pass some element id");
3628 (result, state)
3629 })
3630 } else {
3631 let (result, state) = f(None, self);
3632 debug_assert!(
3633 state.is_none(),
3634 "you must not return an element state when passing None for the global id"
3635 );
3636 result
3637 }
3638 }
3639
3640 #[inline]
3642 pub fn with_tab_group<R>(&mut self, index: Option<isize>, f: impl FnOnce(&mut Self) -> R) -> R {
3643 if let Some(index) = index {
3644 self.next_frame.tab_stops.begin_group(index);
3645 let result = f(self);
3646 self.next_frame.tab_stops.end_group();
3647 result
3648 } else {
3649 f(self)
3650 }
3651 }
3652
3653 pub fn defer_draw(
3659 &mut self,
3660 element: AnyElement,
3661 absolute_offset: Point<Pixels>,
3662 priority: usize,
3663 ) {
3664 self.invalidator.debug_assert_prepaint();
3665 let parent_node = self.next_frame.dispatch_tree.active_node_id().unwrap();
3666 self.next_frame.deferred_draws.push(DeferredDraw {
3667 current_view: self.current_view(),
3668 parent_node,
3669 element_id_stack: self.element_id_stack.clone(),
3670 text_style_stack: self.text_style_stack.clone(),
3671 priority,
3672 element: Some(element),
3673 absolute_offset,
3674 prepaint_range: PrepaintStateIndex::default()..PrepaintStateIndex::default(),
3675 paint_range: PaintIndex::default()..PaintIndex::default(),
3676 });
3677 }
3678
3679 pub fn paint_layer<R>(&mut self, bounds: Bounds<Pixels>, f: impl FnOnce(&mut Self) -> R) -> R {
3685 self.invalidator.debug_assert_paint();
3686
3687 let content_mask = self.content_mask();
3688 let clipped_bounds = bounds.intersect(&content_mask.bounds);
3689 if !clipped_bounds.is_empty() {
3690 self.next_frame
3691 .scene
3692 .push_layer(self.cover_bounds(clipped_bounds));
3693 }
3694
3695 let result = f(self);
3696
3697 if !clipped_bounds.is_empty() {
3698 self.next_frame.scene.pop_layer();
3699 }
3700
3701 result
3702 }
3703
3704 pub fn paint_shadows(
3708 &mut self,
3709 bounds: Bounds<Pixels>,
3710 corner_radii: Corners<Pixels>,
3711 shadows: &[BoxShadow],
3712 ) {
3713 self.invalidator.debug_assert_paint();
3714
3715 let scale_factor = self.scale_factor();
3716 let content_mask = self.snapped_content_mask();
3717 let opacity = self.element_opacity();
3718 for shadow in shadows {
3719 let shadow_bounds = if shadow.inset {
3720 bounds.contract(shadow.spread_radius)
3721 } else {
3722 (bounds + shadow.offset).dilate(shadow.spread_radius)
3723 };
3724 self.next_frame.scene.insert_primitive(Shadow {
3725 order: 0,
3726 blur_radius: shadow.blur_radius.scale(scale_factor),
3727 bounds: if shadow.inset {
3728 self.snap_bounds(shadow_bounds)
3729 } else {
3730 self.cover_bounds(shadow_bounds)
3731 },
3732 content_mask: if shadow.inset {
3733 ContentMask {
3734 bounds: self.snap_bounds(bounds),
3735 }
3736 } else {
3737 content_mask
3738 },
3739 corner_radii: corner_radii.scale(scale_factor),
3740 color: shadow.color.opacity(opacity),
3741 inset: if shadow.inset { 1 } else { 0 },
3742 _pad_end: 0,
3743 });
3744 }
3745 }
3746
3747 pub fn paint_quad(&mut self, quad: PaintQuad) {
3757 self.invalidator.debug_assert_paint();
3758
3759 let opacity = self.element_opacity();
3760 let snapped_bounds = self.snap_bounds(quad.bounds);
3761 let snapped_border_widths = self.snap_border_widths(quad.border_widths);
3762 let quad = Quad {
3763 order: 0,
3764 bounds: snapped_bounds,
3765 content_mask: self.snapped_content_mask(),
3766 background: quad.background.opacity(opacity),
3767 border_color: quad.border_color.opacity(opacity),
3768 corner_radii: quad.corner_radii.scale(self.scale_factor()),
3769 border_widths: snapped_border_widths,
3770 border_style: quad.border_style,
3771 continuous_corners: if quad.continuous_corners { 1 } else { 0 },
3772 _pad_before_transform: 0,
3773 transform: quad.transform,
3774 blend_mode: quad.blend_mode as u32,
3775 _pad_end: 0,
3776 };
3777
3778 if !quad.background.is_transparent() {
3779 self.next_frame.scene.insert_primitive(quad);
3780 return;
3781 }
3782
3783 let Some(strips) =
3784 border_only_quad_strips(quad.bounds, quad.border_widths, quad.corner_radii)
3785 else {
3786 self.next_frame.scene.insert_primitive(quad);
3787 return;
3788 };
3789
3790 for strip in strips {
3791 let mask_bounds = quad.content_mask.bounds.intersect(&strip);
3792 if !mask_bounds.is_empty() {
3793 self.next_frame.scene.insert_primitive(Quad {
3794 content_mask: ContentMask {
3795 bounds: mask_bounds,
3796 },
3797 ..quad
3798 });
3799 }
3800 }
3801 }
3802
3803 pub fn paint_path(&mut self, mut path: Path<Pixels>, color: impl Into<Background>) {
3807 self.invalidator.debug_assert_paint();
3808
3809 let scale_factor = self.scale_factor();
3810 let content_mask = self.content_mask();
3811 let opacity = self.element_opacity();
3812 path.content_mask = content_mask;
3813 let color: Background = color.into();
3814 path.color = color.opacity(opacity);
3815 self.next_frame
3816 .scene
3817 .insert_primitive(path.scale(scale_factor));
3818 }
3819
3820 pub fn paint_underline(
3824 &mut self,
3825 origin: Point<Pixels>,
3826 width: Pixels,
3827 style: &UnderlineStyle,
3828 ) {
3829 self.invalidator.debug_assert_paint();
3830
3831 let scale_factor = self.scale_factor();
3832 let thickness = self.snap_stroke(style.thickness);
3833 let height = if style.wavy {
3834 ScaledPixels(thickness.0 * 3.)
3835 } else {
3836 thickness
3837 };
3838 let bounds = Bounds {
3839 origin: origin.map(|c| ScaledPixels(round_to_device_pixel(c.0, scale_factor))),
3840 size: size(self.snap_stroke(width), height),
3841 };
3842 let element_opacity = self.element_opacity();
3843
3844 self.next_frame.scene.insert_primitive(Underline {
3845 order: 0,
3846 pad: 0,
3847 bounds,
3848 content_mask: self.snapped_content_mask(),
3849 color: style.color.unwrap_or_default().opacity(element_opacity),
3850 thickness,
3851 wavy: style.wavy.into(),
3852 });
3853 }
3854
3855 pub fn paint_strikethrough(
3859 &mut self,
3860 origin: Point<Pixels>,
3861 width: Pixels,
3862 style: &StrikethroughStyle,
3863 ) {
3864 self.invalidator.debug_assert_paint();
3865
3866 let scale_factor = self.scale_factor();
3867 let height = style.thickness;
3868 let bounds = Bounds {
3869 origin: origin.map(|c| ScaledPixels(round_to_device_pixel(c.0, scale_factor))),
3870 size: size(self.snap_stroke(width), self.snap_stroke(height)),
3871 };
3872 let opacity = self.element_opacity();
3873
3874 self.next_frame.scene.insert_primitive(Underline {
3875 order: 0,
3876 pad: 0,
3877 bounds,
3878 content_mask: self.snapped_content_mask(),
3879 thickness: self.snap_stroke(style.thickness),
3880 color: style.color.unwrap_or_default().opacity(opacity),
3881 wavy: false.into(),
3882 });
3883 }
3884
3885 pub fn paint_glyph(
3894 &mut self,
3895 origin: Point<Pixels>,
3896 font_id: FontId,
3897 glyph_id: GlyphId,
3898 font_size: Pixels,
3899 color: Hsla,
3900 ) -> Result<()> {
3901 self.invalidator.debug_assert_paint();
3902
3903 let element_opacity = self.element_opacity();
3904 let scale_factor = self.scale_factor();
3905 let glyph_origin = origin.scale(scale_factor);
3906
3907 let quantized_origin = Point::new(
3908 round_half_toward_zero(glyph_origin.x.0 * SUBPIXEL_VARIANTS_X as f32)
3909 / SUBPIXEL_VARIANTS_X as f32,
3910 round_half_toward_zero(glyph_origin.y.0 * SUBPIXEL_VARIANTS_Y as f32)
3911 / SUBPIXEL_VARIANTS_Y as f32,
3912 );
3913 let subpixel_variant = Point::new(
3914 (quantized_origin.x.fract() * SUBPIXEL_VARIANTS_X as f32) as u8,
3915 (quantized_origin.y.fract() * SUBPIXEL_VARIANTS_Y as f32) as u8,
3916 );
3917 let integer_origin = quantized_origin.map(|c| ScaledPixels(c.trunc()));
3918 let dilation = self.text_system().glyph_dilation_for_color(color);
3919 let params = RenderGlyphParams {
3920 font_id,
3921 glyph_id,
3922 font_size,
3923 subpixel_variant,
3924 scale_factor,
3925 is_emoji: false,
3926 dilation,
3927 };
3928
3929 let raster_bounds = self.text_system().raster_bounds(¶ms)?;
3930 if !raster_bounds.is_zero() {
3931 let tile = self
3932 .sprite_atlas
3933 .get_or_insert_with(¶ms.clone().into(), &mut || {
3934 let (size, bytes) = self.text_system().rasterize_glyph(¶ms)?;
3935 Ok(Some((size, Cow::Owned(bytes))))
3936 })?
3937 .expect("Callback above only errors or returns Some");
3938 let bounds = Bounds {
3939 origin: integer_origin + raster_bounds.origin.map(Into::into),
3940 size: tile.bounds.size.map(Into::into),
3941 };
3942 let content_mask = self.snapped_content_mask();
3943 self.next_frame.scene.insert_primitive(MonochromeSprite {
3944 order: 0,
3945 pad: 0,
3946 bounds,
3947 content_mask,
3948 color: color.opacity(element_opacity),
3949 tile,
3950 transformation: TransformationMatrix::unit(),
3951 });
3952 }
3953 Ok(())
3954 }
3955
3956 pub fn paint_emoji(
3965 &mut self,
3966 origin: Point<Pixels>,
3967 font_id: FontId,
3968 glyph_id: GlyphId,
3969 font_size: Pixels,
3970 ) -> Result<()> {
3971 self.invalidator.debug_assert_paint();
3972
3973 let scale_factor = self.scale_factor();
3974 let glyph_origin = origin.scale(scale_factor);
3975 let integer_origin = glyph_origin.map(|c| ScaledPixels(round_half_toward_zero(c.0)));
3976 let params = RenderGlyphParams {
3977 font_id,
3978 glyph_id,
3979 font_size,
3980 subpixel_variant: Default::default(),
3981 scale_factor,
3982 is_emoji: true,
3983 dilation: 0, };
3985
3986 let raster_bounds = self.text_system().raster_bounds(¶ms)?;
3987 if !raster_bounds.is_zero() {
3988 let tile = self
3989 .sprite_atlas
3990 .get_or_insert_with(¶ms.clone().into(), &mut || {
3991 let (size, bytes) = self.text_system().rasterize_glyph(¶ms)?;
3992 Ok(Some((size, Cow::Owned(bytes))))
3993 })?
3994 .expect("Callback above only errors or returns Some");
3995
3996 let bounds = Bounds {
3997 origin: integer_origin + raster_bounds.origin.map(Into::into),
3998 size: tile.bounds.size.map(Into::into),
3999 };
4000 let content_mask = self.snapped_content_mask();
4001 let opacity = self.element_opacity();
4002
4003 self.next_frame.scene.insert_primitive(PolychromeSprite {
4004 order: 0,
4005 pad: 0,
4006 grayscale: false.into(),
4007 bounds,
4008 corner_radii: Default::default(),
4009 content_mask,
4010 tile,
4011 opacity,
4012 });
4013 }
4014 Ok(())
4015 }
4016
4017 pub fn paint_svg(
4021 &mut self,
4022 bounds: Bounds<Pixels>,
4023 path: SharedString,
4024 transformation: TransformationMatrix,
4025 color: Hsla,
4026 cx: &App,
4027 ) -> Result<()> {
4028 self.paint_svg_from(bounds, path, None, transformation, color, cx)
4029 }
4030
4031 pub(crate) fn paint_svg_from(
4033 &mut self,
4034 bounds: Bounds<Pixels>,
4035 path: SharedString,
4036 data: Option<&[u8]>,
4037 transformation: TransformationMatrix,
4038 color: Hsla,
4039 cx: &App,
4040 ) -> Result<()> {
4041 self.invalidator.debug_assert_paint();
4042
4043 let element_opacity = self.element_opacity();
4044 let bounds = self.snap_bounds(bounds);
4045 let params = RenderSvgParams {
4046 path,
4047 size: bounds.size.map(|pixels| {
4048 DevicePixels::from((pixels.0 * SMOOTH_SVG_SCALE_FACTOR).ceil() as i32)
4049 }),
4050 };
4051
4052 let Some(tile) =
4053 self.sprite_atlas
4054 .get_or_insert_with(¶ms.clone().into(), &mut || {
4055 let Some((size, bytes)) = cx.svg_renderer.render(¶ms, data)? else {
4056 return Ok(None);
4057 };
4058 Ok(Some((size, Cow::Owned(bytes))))
4059 })?
4060 else {
4061 return Ok(());
4062 };
4063 let content_mask = self.snapped_content_mask();
4064 let svg_bounds = Bounds {
4065 origin: bounds.center()
4066 - Point::new(
4067 ScaledPixels(tile.bounds.size.width.0 as f32 / SMOOTH_SVG_SCALE_FACTOR / 2.),
4068 ScaledPixels(tile.bounds.size.height.0 as f32 / SMOOTH_SVG_SCALE_FACTOR / 2.),
4069 ),
4070 size: tile
4071 .bounds
4072 .size
4073 .map(|value| ScaledPixels(value.0 as f32 / SMOOTH_SVG_SCALE_FACTOR)),
4074 };
4075 let final_bounds = svg_bounds
4076 .map_origin(|origin| ScaledPixels(round_half_toward_zero(origin.0)))
4077 .map_size(|size| size.ceil());
4078
4079 self.next_frame.scene.insert_primitive(MonochromeSprite {
4080 order: 0,
4081 pad: 0,
4082 bounds: final_bounds,
4083 content_mask,
4084 color: color.opacity(element_opacity),
4085 tile,
4086 transformation,
4087 });
4088
4089 Ok(())
4090 }
4091
4092 pub fn paint_image(
4097 &mut self,
4098 bounds: Bounds<Pixels>,
4099 image_bounds: Bounds<Pixels>,
4100 corner_radii: Corners<Pixels>,
4101 data: Arc<RenderImage>,
4102 frame_index: usize,
4103 grayscale: bool,
4104 ) -> Result<()> {
4105 self.invalidator.debug_assert_paint();
4106
4107 let visible_bounds = bounds.intersect(&image_bounds);
4108 if visible_bounds.size.width <= Pixels::ZERO || visible_bounds.size.height <= Pixels::ZERO {
4109 return Ok(());
4110 }
4111 if image_bounds.size.width <= Pixels::ZERO || image_bounds.size.height <= Pixels::ZERO {
4112 return Ok(());
4113 }
4114
4115 let params = RenderImageParams {
4116 image_id: data.id,
4117 frame_index,
4118 };
4119 let Some(bytes) = data.as_bytes(frame_index) else {
4120 return Ok(());
4121 };
4122 let image_size = data.size(frame_index);
4123
4124 let tile = self
4125 .sprite_atlas
4126 .get_or_insert_with(¶ms.into(), &mut || {
4127 Ok(Some((image_size, Cow::Borrowed(bytes))))
4128 })?
4129 .expect("Callback above only returns Some");
4130
4131 let visible_bounds_snapped = self.snap_bounds(visible_bounds);
4132 let sub_tile = if visible_bounds == image_bounds {
4133 tile
4134 } else {
4135 let x_offset_ratio =
4136 (visible_bounds.origin.x - image_bounds.origin.x) / image_bounds.size.width;
4137 let y_offset_ratio =
4138 (visible_bounds.origin.y - image_bounds.origin.y) / image_bounds.size.height;
4139 let width_ratio = visible_bounds.size.width / image_bounds.size.width;
4140 let height_ratio = visible_bounds.size.height / image_bounds.size.height;
4141
4142 let tile_origin_x = tile.bounds.origin.x.0;
4143 let tile_origin_y = tile.bounds.origin.y.0;
4144 let tile_width = tile.bounds.size.width.0;
4145 let tile_height = tile.bounds.size.height.0;
4146
4147 let sub_origin_x = tile_origin_x + (x_offset_ratio * tile_width as f32).round() as i32;
4148 let sub_origin_y = tile_origin_y + (y_offset_ratio * tile_height as f32).round() as i32;
4149 let sub_width = (width_ratio * tile_width as f32).round() as i32;
4150 let sub_height = (height_ratio * tile_height as f32).round() as i32;
4151
4152 let max_x = tile_origin_x + tile_width;
4153 let max_y = tile_origin_y + tile_height;
4154 let clamped_origin_x = sub_origin_x.clamp(tile_origin_x, max_x);
4155 let clamped_origin_y = sub_origin_y.clamp(tile_origin_y, max_y);
4156 let clamped_width = sub_width.min(max_x - clamped_origin_x).max(0);
4157 let clamped_height = sub_height.min(max_y - clamped_origin_y).max(0);
4158
4159 AtlasTile {
4160 bounds: Bounds {
4161 origin: point(
4162 DevicePixels(clamped_origin_x),
4163 DevicePixels(clamped_origin_y),
4164 ),
4165 size: size(DevicePixels(clamped_width), DevicePixels(clamped_height)),
4166 },
4167 ..tile
4168 }
4169 };
4170
4171 let content_mask = self.snapped_content_mask();
4172 let corner_radii = corner_radii
4173 .clamp_radii_for_quad_size(visible_bounds.size)
4174 .scale(self.scale_factor());
4175 let opacity = self.element_opacity();
4176
4177 self.next_frame.scene.insert_primitive(PolychromeSprite {
4178 order: 0,
4179 pad: 0,
4180 grayscale: grayscale.into(),
4181 bounds: visible_bounds_snapped,
4182 content_mask,
4183 corner_radii,
4184 tile: sub_tile,
4185 opacity,
4186 });
4187 Ok(())
4188 }
4189
4190 #[cfg(target_os = "macos")]
4194 pub fn paint_surface(&mut self, bounds: Bounds<Pixels>, image_buffer: CVPixelBuffer) {
4195 use crate::PaintSurface;
4196
4197 self.invalidator.debug_assert_paint();
4198
4199 let bounds = self.snap_bounds(bounds);
4200 let content_mask = self.snapped_content_mask();
4201 self.next_frame.scene.insert_primitive(PaintSurface {
4202 order: 0,
4203 bounds,
4204 content_mask,
4205 image_buffer,
4206 });
4207 }
4208
4209 pub fn drop_image(&mut self, data: Arc<RenderImage>) -> Result<()> {
4211 for frame_index in 0..data.frame_count() {
4212 let params = RenderImageParams {
4213 image_id: data.id,
4214 frame_index,
4215 };
4216
4217 self.sprite_atlas.remove(¶ms.clone().into());
4218 }
4219
4220 Ok(())
4221 }
4222
4223 #[must_use]
4229 pub fn request_layout(
4230 &mut self,
4231 style: Style,
4232 children: impl IntoIterator<Item = LayoutId>,
4233 cx: &mut App,
4234 ) -> LayoutId {
4235 self.invalidator.debug_assert_prepaint();
4236
4237 cx.layout_id_buffer.clear();
4238 cx.layout_id_buffer.extend(children);
4239 let rem_size = self.rem_size();
4240 let scale_factor = self.scale_factor();
4241
4242 self.layout_engine.as_mut().unwrap().request_layout(
4243 style,
4244 rem_size,
4245 scale_factor,
4246 &cx.layout_id_buffer,
4247 )
4248 }
4249
4250 pub fn request_measured_layout<
4259 F: FnMut(Size<Option<Pixels>>, Size<AvailableSpace>, &mut Window, &mut App) -> Size<Pixels>
4260 + 'static,
4261 >(
4262 &mut self,
4263 style: Style,
4264 measure: F,
4265 ) -> LayoutId {
4266 self.invalidator.debug_assert_prepaint();
4267
4268 let rem_size = self.rem_size();
4269 let scale_factor = self.scale_factor();
4270 self.layout_engine
4271 .as_mut()
4272 .unwrap()
4273 .request_measured_layout(style, rem_size, scale_factor, measure)
4274 }
4275
4276 pub fn compute_layout(
4282 &mut self,
4283 layout_id: LayoutId,
4284 available_space: Size<AvailableSpace>,
4285 cx: &mut App,
4286 ) {
4287 self.invalidator.debug_assert_prepaint();
4288
4289 let mut layout_engine = self.layout_engine.take().unwrap();
4290 layout_engine.compute_layout(layout_id, available_space, self, cx);
4291 self.layout_engine = Some(layout_engine);
4292 }
4293
4294 pub fn layout_bounds(&mut self, layout_id: LayoutId) -> Bounds<Pixels> {
4299 self.invalidator.debug_assert_prepaint();
4300
4301 let scale_factor = self.scale_factor();
4302 let mut bounds = self
4303 .layout_engine
4304 .as_mut()
4305 .unwrap()
4306 .layout_bounds(layout_id, scale_factor)
4307 .map(Into::into);
4308 bounds.origin += self.pixel_snap_point(self.element_offset());
4309 bounds
4310 }
4311
4312 pub fn insert_hitbox(&mut self, bounds: Bounds<Pixels>, behavior: HitboxBehavior) -> Hitbox {
4318 self.invalidator.debug_assert_prepaint();
4319
4320 let content_mask = self.content_mask();
4321 let mut id = self.next_hitbox_id;
4322 self.next_hitbox_id = self.next_hitbox_id.next();
4323 let hitbox = Hitbox {
4324 id,
4325 bounds,
4326 content_mask,
4327 behavior,
4328 };
4329 self.next_frame.hitboxes.push(hitbox.clone());
4330 hitbox
4331 }
4332
4333 pub fn insert_window_control_hitbox(&mut self, area: WindowControlArea, hitbox: Hitbox) {
4337 self.invalidator.debug_assert_paint();
4338 self.next_frame.window_control_hitboxes.push((area, hitbox));
4339 }
4340
4341 pub fn set_key_context(&mut self, context: KeyContext) {
4346 self.invalidator.debug_assert_paint();
4347 self.next_frame.dispatch_tree.set_key_context(context);
4348 }
4349
4350 pub fn set_focus_handle(&mut self, focus_handle: &FocusHandle, _: &App) {
4355 self.invalidator.debug_assert_prepaint();
4356 if focus_handle.is_focused(self) {
4357 self.next_frame.focus = Some(focus_handle.id);
4358 }
4359 self.next_frame.dispatch_tree.set_focus_id(focus_handle.id);
4360 }
4361
4362 pub fn set_view_id(&mut self, view_id: EntityId) {
4368 self.invalidator.debug_assert_prepaint();
4369 self.next_frame.dispatch_tree.set_view_id(view_id);
4370 }
4371
4372 pub fn current_view(&self) -> EntityId {
4374 self.invalidator.debug_assert_paint_or_prepaint();
4375 self.rendered_entity_stack.last().copied().unwrap()
4376 }
4377
4378 pub(crate) fn with_rendered_view<R>(
4379 &mut self,
4380 id: EntityId,
4381 f: impl FnOnce(&mut Self) -> R,
4382 ) -> R {
4383 self.rendered_entity_stack.push(id);
4384 let result = f(self);
4385 self.rendered_entity_stack.pop();
4386 result
4387 }
4388
4389 pub fn with_image_cache<F, R>(&mut self, image_cache: Option<AnyImageCache>, f: F) -> R
4391 where
4392 F: FnOnce(&mut Self) -> R,
4393 {
4394 if let Some(image_cache) = image_cache {
4395 self.image_cache_stack.push(image_cache);
4396 let result = f(self);
4397 self.image_cache_stack.pop();
4398 result
4399 } else {
4400 f(self)
4401 }
4402 }
4403
4404 pub fn handle_input(
4413 &mut self,
4414 focus_handle: &FocusHandle,
4415 input_handler: impl InputHandler,
4416 cx: &App,
4417 ) {
4418 self.invalidator.debug_assert_paint();
4419
4420 if focus_handle.is_focused(self) {
4421 let cx = self.to_async(cx);
4422 self.next_frame
4423 .input_handlers
4424 .push(Some(PlatformInputHandler::new(cx, Box::new(input_handler))));
4425 }
4426 }
4427
4428 pub fn on_mouse_event<Event: MouseEvent>(
4434 &mut self,
4435 mut handler: impl FnMut(&Event, DispatchPhase, &mut Window, &mut App) + 'static,
4436 ) {
4437 self.invalidator.debug_assert_paint();
4438
4439 self.next_frame.mouse_listeners.push(Some(Box::new(
4440 move |event: &dyn Any, phase: DispatchPhase, window: &mut Window, cx: &mut App| {
4441 if let Some(event) = event.downcast_ref() {
4442 handler(event, phase, window, cx)
4443 }
4444 },
4445 )));
4446 }
4447
4448 pub fn on_key_event<Event: KeyEvent>(
4457 &mut self,
4458 listener: impl Fn(&Event, DispatchPhase, &mut Window, &mut App) + 'static,
4459 ) {
4460 self.invalidator.debug_assert_paint();
4461
4462 self.next_frame.dispatch_tree.on_key_event(Rc::new(
4463 move |event: &dyn Any, phase, window: &mut Window, cx: &mut App| {
4464 if let Some(event) = event.downcast_ref::<Event>() {
4465 listener(event, phase, window, cx)
4466 }
4467 },
4468 ));
4469 }
4470
4471 pub fn on_modifiers_changed(
4478 &mut self,
4479 listener: impl Fn(&ModifiersChangedEvent, &mut Window, &mut App) + 'static,
4480 ) {
4481 self.invalidator.debug_assert_paint();
4482
4483 self.next_frame.dispatch_tree.on_modifiers_changed(Rc::new(
4484 move |event: &ModifiersChangedEvent, window: &mut Window, cx: &mut App| {
4485 listener(event, window, cx)
4486 },
4487 ));
4488 }
4489
4490 pub fn on_focus_in(
4494 &mut self,
4495 handle: &FocusHandle,
4496 cx: &mut App,
4497 mut listener: impl FnMut(&mut Window, &mut App) + 'static,
4498 ) -> Subscription {
4499 let focus_id = handle.id;
4500 let (subscription, activate) =
4501 self.new_focus_listener(Box::new(move |event, window, cx| {
4502 if event.is_focus_in(focus_id) {
4503 listener(window, cx);
4504 }
4505 true
4506 }));
4507 cx.defer(move |_| activate());
4508 subscription
4509 }
4510
4511 pub fn on_focus_out(
4514 &mut self,
4515 handle: &FocusHandle,
4516 cx: &mut App,
4517 mut listener: impl FnMut(FocusOutEvent, &mut Window, &mut App) + 'static,
4518 ) -> Subscription {
4519 let focus_id = handle.id;
4520 let (subscription, activate) =
4521 self.new_focus_listener(Box::new(move |event, window, cx| {
4522 if let Some(blurred_id) = event.previous_focus_path.last().copied()
4523 && event.is_focus_out(focus_id)
4524 {
4525 let event = FocusOutEvent {
4526 blurred: WeakFocusHandle {
4527 id: blurred_id,
4528 handles: Arc::downgrade(&cx.focus_handles),
4529 },
4530 };
4531 listener(event, window, cx)
4532 }
4533 true
4534 }));
4535 cx.defer(move |_| activate());
4536 subscription
4537 }
4538
4539 fn reset_cursor_style(&self, cx: &mut App) {
4540 if self.is_window_hovered() {
4542 let style = self
4543 .rendered_frame
4544 .cursor_style(self)
4545 .unwrap_or(CursorStyle::Arrow);
4546 self.platform_window.set_cursor_style(style);
4552 cx.platform.set_cursor_style(style);
4553 }
4554 }
4555
4556 pub fn dispatch_keystroke(&mut self, keystroke: Keystroke, cx: &mut App) -> bool {
4559 let keystroke = keystroke.with_simulated_ime();
4560 let result = self.dispatch_event(
4561 PlatformInput::KeyDown(KeyDownEvent {
4562 keystroke: keystroke.clone(),
4563 is_held: false,
4564 prefer_character_input: false,
4565 }),
4566 cx,
4567 );
4568 if !result.propagate {
4569 return true;
4570 }
4571
4572 if let Some(input) = keystroke.key_char
4573 && let Some(mut input_handler) = self.platform_window.take_input_handler()
4574 {
4575 input_handler.dispatch_input(&input, self, cx);
4576 self.platform_window.set_input_handler(input_handler);
4577 return true;
4578 }
4579
4580 false
4581 }
4582
4583 pub fn keystroke_text_for(&self, action: &dyn Action) -> String {
4586 self.highest_precedence_binding_for_action(action)
4587 .map(|binding| {
4588 binding
4589 .keystrokes()
4590 .iter()
4591 .map(ToString::to_string)
4592 .collect::<Vec<_>>()
4593 .join(" ")
4594 })
4595 .unwrap_or_else(|| action.name().to_string())
4596 }
4597
4598 #[profiling::function]
4600 pub fn dispatch_event(&mut self, event: PlatformInput, cx: &mut App) -> DispatchEventResult {
4601 #[cfg(feature = "input-latency-histogram")]
4602 let dispatch_time = Instant::now();
4603 let update_count_before = self.invalidator.update_count();
4604
4605 cx.propagate_event = true;
4607 self.default_prevented = false;
4609
4610 let event = match event {
4611 PlatformInput::MouseMove(mouse_move) => {
4614 self.mouse_position = mouse_move.position;
4615 self.modifiers = mouse_move.modifiers;
4616 PlatformInput::MouseMove(mouse_move)
4617 }
4618 PlatformInput::MouseDown(mouse_down) => {
4619 self.mouse_position = mouse_down.position;
4620 self.modifiers = mouse_down.modifiers;
4621 PlatformInput::MouseDown(mouse_down)
4622 }
4623 PlatformInput::MouseUp(mouse_up) => {
4624 self.mouse_position = mouse_up.position;
4625 self.modifiers = mouse_up.modifiers;
4626 PlatformInput::MouseUp(mouse_up)
4627 }
4628 PlatformInput::MouseExited(mouse_exited) => {
4629 self.modifiers = mouse_exited.modifiers;
4630 PlatformInput::MouseExited(mouse_exited)
4631 }
4632 PlatformInput::ModifiersChanged(modifiers_changed) => {
4633 self.modifiers = modifiers_changed.modifiers;
4634 self.capslock = modifiers_changed.capslock;
4635 PlatformInput::ModifiersChanged(modifiers_changed)
4636 }
4637 PlatformInput::ScrollWheel(scroll_wheel) => {
4638 self.mouse_position = scroll_wheel.position;
4639 self.modifiers = scroll_wheel.modifiers;
4640 PlatformInput::ScrollWheel(scroll_wheel)
4641 }
4642 PlatformInput::Pinch(pinch) => {
4643 self.mouse_position = pinch.position;
4644 self.modifiers = pinch.modifiers;
4645 PlatformInput::Pinch(pinch)
4646 }
4647 PlatformInput::FileDrop(file_drop) => match file_drop {
4650 FileDropEvent::Entered { position, paths } => {
4651 self.mouse_position = position;
4652 if cx.active_drag.is_none() {
4653 cx.active_drag = Some(AnyDrag {
4654 value: Arc::new(paths.clone()),
4655 view: cx.new(|_| paths).into(),
4656 cursor_offset: position,
4657 cursor_style: None,
4658 });
4659 }
4660 PlatformInput::MouseMove(MouseMoveEvent {
4661 position,
4662 pressed_button: Some(MouseButton::Left),
4663 modifiers: Modifiers::default(),
4664 })
4665 }
4666 FileDropEvent::Pending { position } => {
4667 self.mouse_position = position;
4668 PlatformInput::MouseMove(MouseMoveEvent {
4669 position,
4670 pressed_button: Some(MouseButton::Left),
4671 modifiers: Modifiers::default(),
4672 })
4673 }
4674 FileDropEvent::Submit { position } => {
4675 cx.activate(true);
4676 self.mouse_position = position;
4677 PlatformInput::MouseUp(MouseUpEvent {
4678 button: MouseButton::Left,
4679 position,
4680 modifiers: Modifiers::default(),
4681 click_count: 1,
4682 })
4683 }
4684 FileDropEvent::Exited => {
4685 cx.active_drag.take();
4686 PlatformInput::FileDrop(FileDropEvent::Exited)
4687 }
4688 },
4689 PlatformInput::KeyDown(_) | PlatformInput::KeyUp(_) => event,
4690 };
4691
4692 if let Some(any_mouse_event) = event.mouse_event() {
4693 self.dispatch_mouse_event(any_mouse_event, cx);
4694 } else if let Some(any_key_event) = event.keyboard_event() {
4695 self.dispatch_key_event(any_key_event, cx);
4696 }
4697
4698 if self.invalidator.update_count() > update_count_before {
4699 self.input_rate_tracker.borrow_mut().record_input();
4700 #[cfg(feature = "input-latency-histogram")]
4701 if self.invalidator.not_drawing() {
4702 self.input_latency_tracker.record_input(dispatch_time);
4703 } else {
4704 self.input_latency_tracker.record_mid_draw_input();
4705 }
4706 }
4707
4708 DispatchEventResult {
4709 propagate: cx.propagate_event,
4710 default_prevented: self.default_prevented,
4711 }
4712 }
4713
4714 fn dispatch_mouse_event(&mut self, event: &dyn Any, cx: &mut App) {
4715 self.last_input_was_keyboard.set(false);
4716
4717 let hit_test = self.rendered_frame.hit_test(self.mouse_position());
4718 if hit_test != self.mouse_hit_test {
4719 self.mouse_hit_test = hit_test;
4720 self.reset_cursor_style(cx);
4721 }
4722
4723 #[cfg(any(feature = "inspector", debug_assertions))]
4724 if self.is_inspector_picking(cx) {
4725 self.handle_inspector_mouse_event(event, cx);
4726 return;
4728 }
4729
4730 let mut mouse_listeners = mem::take(&mut self.rendered_frame.mouse_listeners);
4731
4732 for listener in &mut mouse_listeners {
4735 let listener = listener.as_mut().unwrap();
4736 listener(event, DispatchPhase::Capture, self, cx);
4737 if !cx.propagate_event {
4738 break;
4739 }
4740 }
4741
4742 if cx.propagate_event {
4744 for listener in mouse_listeners.iter_mut().rev() {
4745 let listener = listener.as_mut().unwrap();
4746 listener(event, DispatchPhase::Bubble, self, cx);
4747 if !cx.propagate_event {
4748 break;
4749 }
4750 }
4751 }
4752
4753 self.rendered_frame.mouse_listeners = mouse_listeners;
4754
4755 if cx.has_active_drag() {
4756 if event.is::<MouseMoveEvent>() {
4757 self.refresh();
4760 } else if event.is::<MouseUpEvent>() {
4761 cx.active_drag = None;
4764 self.refresh();
4765 }
4766 }
4767
4768 if event.is::<MouseUpEvent>() && self.captured_hitbox.is_some() {
4769 self.captured_hitbox = None;
4770 }
4771 }
4772
4773 fn dispatch_key_event(&mut self, event: &dyn Any, cx: &mut App) {
4774 self.last_input_was_keyboard.set(true);
4775
4776 if self.invalidator.is_dirty() {
4777 self.draw(cx).clear();
4778 }
4779
4780 let node_id = self.focus_node_id_in_rendered_frame(self.focus);
4781 let dispatch_path = self.rendered_frame.dispatch_tree.dispatch_path(node_id);
4782
4783 let mut keystroke: Option<Keystroke> = None;
4784
4785 if let Some(event) = event.downcast_ref::<ModifiersChangedEvent>() {
4786 if event.modifiers.number_of_modifiers() == 0
4787 && self.pending_modifier.modifiers.number_of_modifiers() == 1
4788 && !self.pending_modifier.saw_other_input
4789 {
4790 let key = match self.pending_modifier.modifiers {
4791 modifiers if modifiers.shift => Some("shift"),
4792 modifiers if modifiers.control => Some("control"),
4793 modifiers if modifiers.alt => Some("alt"),
4794 modifiers if modifiers.platform => Some("platform"),
4795 modifiers if modifiers.function => Some("function"),
4796 _ => None,
4797 };
4798 if let Some(key) = key {
4799 keystroke = Some(Keystroke {
4800 key: key.to_string(),
4801 key_char: None,
4802 modifiers: Modifiers::default(),
4803 });
4804 }
4805 }
4806
4807 if self.pending_modifier.modifiers.number_of_modifiers() == 0
4808 && event.modifiers.number_of_modifiers() == 1
4809 {
4810 self.pending_modifier.saw_other_input = false
4811 } else if event.modifiers.number_of_modifiers() > 1 {
4812 self.pending_modifier.saw_other_input = true
4813 }
4814 self.pending_modifier.modifiers = event.modifiers
4815 } else if let Some(key_down_event) = event.downcast_ref::<KeyDownEvent>() {
4816 self.pending_modifier.saw_other_input = true;
4817 keystroke = Some(key_down_event.keystroke.clone());
4818 }
4819
4820 let Some(keystroke) = keystroke else {
4821 self.finish_dispatch_key_event(
4822 event,
4823 None,
4824 InputPreference::KeyBindings,
4825 dispatch_path,
4826 self.context_stack(),
4827 cx,
4828 );
4829 return;
4830 };
4831
4832 let input_preference = self.input_preference(event, cx);
4833
4834 cx.propagate_event = true;
4835 self.dispatch_keystroke_interceptors(
4836 &keystroke,
4837 input_preference,
4838 self.context_stack(),
4839 cx,
4840 );
4841 if !cx.propagate_event {
4842 self.finish_dispatch_key_event(
4843 event,
4844 Some(&keystroke),
4845 input_preference,
4846 dispatch_path,
4847 self.context_stack(),
4848 cx,
4849 );
4850 return;
4851 }
4852
4853 let mut currently_pending = self.pending_input.take().unwrap_or_default();
4854 if currently_pending.focus.is_some() && currently_pending.focus != self.focus {
4855 currently_pending = PendingInput::default();
4856 }
4857
4858 let match_result = self.rendered_frame.dispatch_tree.dispatch_key(
4859 currently_pending.keystrokes,
4860 keystroke.clone(),
4861 &dispatch_path,
4862 );
4863
4864 if !match_result.to_replay.is_empty() {
4865 self.replay_pending_input(match_result.to_replay, cx);
4866 cx.propagate_event = true;
4867 }
4868
4869 if !match_result.pending.is_empty() {
4870 let previous_timeout = currently_pending.timeout.take();
4871 currently_pending.keystrokes = match_result.pending;
4872 currently_pending.focus = self.focus;
4873
4874 currently_pending.timeout = match previous_timeout {
4878 Some(mut timeout) if timeout.is_paused() => {
4879 timeout.reset_duration(PENDING_INPUT_TIMEOUT);
4880 Some(timeout)
4881 }
4882 previous_timeout => {
4883 drop(previous_timeout);
4884 Some(self.new_pending_input_timeout(PENDING_INPUT_TIMEOUT, cx))
4885 }
4886 };
4887 self.pending_input = Some(currently_pending);
4888 self.pending_input_changed(cx);
4889 cx.propagate_event = false;
4890 return;
4891 }
4892
4893 let input_preference = self.input_preference(event, cx);
4895 if input_preference == InputPreference::KeyBindings {
4896 for binding in match_result.bindings {
4897 self.dispatch_action_on_node(node_id, binding.action.as_ref(), cx);
4898 if !cx.propagate_event {
4899 self.dispatch_keystroke_observers(
4900 &keystroke,
4901 input_preference,
4902 Some(binding.action.as_ref()),
4903 match_result.context_stack,
4904 cx,
4905 );
4906 self.pending_input_changed(cx);
4907 return;
4908 }
4909 }
4910 }
4911
4912 self.finish_dispatch_key_event(
4913 event,
4914 Some(&keystroke),
4915 input_preference,
4916 dispatch_path,
4917 match_result.context_stack,
4918 cx,
4919 );
4920 self.pending_input_changed(cx);
4921 }
4922
4923 fn input_preference(&mut self, event: &dyn Any, cx: &mut App) -> InputPreference {
4926 let prefer_character_input = event
4927 .downcast_ref::<KeyDownEvent>()
4928 .is_some_and(|key_down_event| key_down_event.prefer_character_input);
4929 if !prefer_character_input {
4930 return InputPreference::KeyBindings;
4931 }
4932 let Some(mut input_handler) = self.platform_window.take_input_handler() else {
4933 return InputPreference::KeyBindings;
4934 };
4935 let accepts_text_input = input_handler.accepts_text_input(self, cx);
4936 self.platform_window.set_input_handler(input_handler);
4937 if accepts_text_input {
4938 InputPreference::CharacterInput
4939 } else {
4940 InputPreference::KeyBindings
4941 }
4942 }
4943
4944 fn new_pending_input_timeout(&self, duration: Duration, cx: &App) -> PendingInputTimeout {
4945 let (started_at, task) = self.start_pending_input_timeout(duration, cx);
4946 PendingInputTimeout {
4947 duration,
4948 remaining: duration,
4949 state: PendingInputTimeoutState::Running { started_at, task },
4950 }
4951 }
4952
4953 fn start_pending_input_timeout(&self, remaining: Duration, cx: &App) -> (Instant, Task<()>) {
4954 let started_at = cx.background_executor().now();
4955 let task = self.spawn(cx, async move |cx| {
4956 cx.background_executor.timer(remaining).await;
4957 cx.update(move |window, cx| {
4958 let Some(currently_pending) = window
4959 .pending_input
4960 .take()
4961 .filter(|pending| pending.focus == window.focus)
4962 else {
4963 return;
4964 };
4965
4966 let node_id = window.focus_node_id_in_rendered_frame(window.focus);
4967 let dispatch_path = window.rendered_frame.dispatch_tree.dispatch_path(node_id);
4968
4969 let to_replay = window
4970 .rendered_frame
4971 .dispatch_tree
4972 .flush_dispatch(currently_pending.keystrokes, &dispatch_path);
4973
4974 window.pending_input_changed(cx);
4975 window.replay_pending_input(to_replay, cx)
4976 })
4977 .log_err();
4978 });
4979 (started_at, task)
4980 }
4981
4982 fn finish_dispatch_key_event(
4983 &mut self,
4984 event: &dyn Any,
4985 recognized_keystroke: Option<&Keystroke>,
4986 input_preference: InputPreference,
4987 dispatch_path: SmallVec<[DispatchNodeId; 32]>,
4988 context_stack: Vec<KeyContext>,
4989 cx: &mut App,
4990 ) {
4991 self.dispatch_key_down_up_event(event, &dispatch_path, cx);
4992 if !cx.propagate_event {
4993 return;
4994 }
4995
4996 self.dispatch_modifiers_changed_event(event, &dispatch_path, cx);
4997 if !cx.propagate_event {
4998 return;
4999 }
5000
5001 if let Some(keystroke) = recognized_keystroke {
5002 self.dispatch_keystroke_observers(keystroke, input_preference, None, context_stack, cx);
5003 }
5004 }
5005
5006 fn pending_input_changed(&mut self, cx: &mut App) {
5007 self.pending_input_observers
5008 .clone()
5009 .retain(&(), |callback| callback(self, cx));
5010 }
5011
5012 fn dispatch_key_down_up_event(
5013 &mut self,
5014 event: &dyn Any,
5015 dispatch_path: &SmallVec<[DispatchNodeId; 32]>,
5016 cx: &mut App,
5017 ) {
5018 for node_id in dispatch_path {
5020 let node = self.rendered_frame.dispatch_tree.node(*node_id);
5021
5022 for key_listener in node.key_listeners.clone() {
5023 key_listener(event, DispatchPhase::Capture, self, cx);
5024 if !cx.propagate_event {
5025 return;
5026 }
5027 }
5028 }
5029
5030 for node_id in dispatch_path.iter().rev() {
5032 let node = self.rendered_frame.dispatch_tree.node(*node_id);
5034 for key_listener in node.key_listeners.clone() {
5035 key_listener(event, DispatchPhase::Bubble, self, cx);
5036 if !cx.propagate_event {
5037 return;
5038 }
5039 }
5040 }
5041 }
5042
5043 fn dispatch_modifiers_changed_event(
5044 &mut self,
5045 event: &dyn Any,
5046 dispatch_path: &SmallVec<[DispatchNodeId; 32]>,
5047 cx: &mut App,
5048 ) {
5049 let Some(event) = event.downcast_ref::<ModifiersChangedEvent>() else {
5050 return;
5051 };
5052 for node_id in dispatch_path.iter().rev() {
5053 let node = self.rendered_frame.dispatch_tree.node(*node_id);
5054 for listener in node.modifiers_changed_listeners.clone() {
5055 listener(event, self, cx);
5056 if !cx.propagate_event {
5057 return;
5058 }
5059 }
5060 }
5061 }
5062
5063 pub fn has_pending_keystrokes(&self) -> bool {
5065 self.pending_input().is_some()
5066 }
5067
5068 #[cfg(test)]
5069 pub(crate) fn pending_input_is_none(&self) -> bool {
5070 self.pending_input.is_none()
5071 }
5072
5073 fn defer_pending_input_changed(&self, cx: &mut App) {
5074 self.defer(cx, |window, cx| {
5077 window.pending_input_changed(cx);
5078 });
5079 }
5080
5081 pub(crate) fn clear_pending_keystrokes(&mut self, cx: &mut App) {
5082 if self.pending_input.take().is_some() {
5083 self.defer_pending_input_changed(cx);
5084 }
5085 }
5086
5087 pub fn pending_input(&self) -> Option<PendingInputStatus<'_>> {
5090 self.pending_input
5091 .as_ref()
5092 .filter(|pending_input| pending_input.focus == self.focus)
5093 .map(|pending_input| PendingInputStatus {
5094 keystrokes: pending_input.keystrokes.as_slice(),
5095 timeout: pending_input
5096 .timeout
5097 .as_ref()
5098 .map(PendingInputTimeout::status),
5099 })
5100 }
5101
5102 pub fn set_pending_input_timeout_paused<T: 'static>(
5107 &mut self,
5108 owner: &Entity<T>,
5109 paused: bool,
5110 cx: &mut App,
5111 ) -> bool {
5112 let owner_id = owner.entity_id();
5113 if !paused {
5114 return self.resume_pending_input_timeout(owner_id, cx);
5115 }
5116
5117 let timeout = self
5118 .pending_input
5119 .as_ref()
5120 .filter(|pending_input| pending_input.focus == self.focus)
5121 .and_then(|pending_input| pending_input.timeout.as_ref());
5122 let Some(timeout) = timeout else {
5123 return false;
5124 };
5125 if timeout.is_paused() {
5126 return false;
5127 }
5128
5129 let release_subscription = self.observe_release(owner, cx, move |_, window, cx| {
5130 window.resume_pending_input_timeout(owner_id, cx);
5131 });
5132 let now = cx.background_executor().now();
5133 let changed = self
5134 .pending_input
5135 .as_mut()
5136 .filter(|pending_input| pending_input.focus == self.focus)
5137 .and_then(|pending_input| pending_input.timeout.as_mut())
5138 .is_some_and(|timeout| {
5139 timeout.pause(
5140 PendingInputTimeoutPause {
5141 owner_id,
5142 _release_subscription: release_subscription,
5143 },
5144 now,
5145 )
5146 });
5147
5148 if changed {
5149 self.defer_pending_input_changed(cx);
5150 }
5151 changed
5152 }
5153
5154 fn resume_pending_input_timeout(&mut self, owner_id: EntityId, cx: &mut App) -> bool {
5155 let Some(remaining) = self
5156 .pending_input
5157 .as_ref()
5158 .filter(|pending_input| pending_input.focus == self.focus)
5159 .and_then(|pending_input| pending_input.timeout.as_ref())
5160 .filter(|timeout| timeout.pause_owner_id() == Some(owner_id))
5161 .map(|timeout| timeout.remaining)
5162 else {
5163 return false;
5164 };
5165
5166 let (started_at, task) = self.start_pending_input_timeout(remaining, cx);
5167 let changed = self
5168 .pending_input
5169 .as_mut()
5170 .filter(|pending_input| pending_input.focus == self.focus)
5171 .and_then(|pending_input| pending_input.timeout.as_mut())
5172 .is_some_and(|timeout| timeout.resume(owner_id, started_at, task));
5173
5174 if changed {
5175 self.defer_pending_input_changed(cx);
5176 }
5177 changed
5178 }
5179
5180 pub fn pending_input_keystrokes(&self) -> Option<&[Keystroke]> {
5182 self.pending_input()
5183 .map(|pending_input| pending_input.keystrokes())
5184 }
5185
5186 fn replay_pending_input(&mut self, replays: SmallVec<[Replay; 1]>, cx: &mut App) {
5187 let node_id = self.focus_node_id_in_rendered_frame(self.focus);
5188 let dispatch_path = self.rendered_frame.dispatch_tree.dispatch_path(node_id);
5189
5190 'replay: for replay in replays {
5191 let event = KeyDownEvent {
5192 keystroke: replay.keystroke.clone(),
5193 is_held: false,
5194 prefer_character_input: true,
5195 };
5196
5197 cx.propagate_event = true;
5198 for binding in replay.bindings {
5199 self.dispatch_action_on_node(node_id, binding.action.as_ref(), cx);
5200 if !cx.propagate_event {
5201 self.dispatch_keystroke_observers(
5202 &replay.keystroke,
5203 InputPreference::KeyBindings,
5204 Some(binding.action.as_ref()),
5205 Vec::default(),
5206 cx,
5207 );
5208 continue 'replay;
5209 }
5210 }
5211
5212 self.dispatch_key_down_up_event(&event, &dispatch_path, cx);
5213 if !cx.propagate_event {
5214 continue 'replay;
5215 }
5216 if let Some(input) = replay.keystroke.key_char.as_ref().cloned()
5217 && let Some(mut input_handler) = self.platform_window.take_input_handler()
5218 {
5219 input_handler.dispatch_input(&input, self, cx);
5220 self.platform_window.set_input_handler(input_handler)
5221 }
5222 }
5223 }
5224
5225 fn focus_node_id_in_rendered_frame(&self, focus_id: Option<FocusId>) -> DispatchNodeId {
5226 focus_id
5227 .and_then(|focus_id| {
5228 self.rendered_frame
5229 .dispatch_tree
5230 .focusable_node_id(focus_id)
5231 })
5232 .unwrap_or_else(|| self.rendered_frame.dispatch_tree.root_node_id())
5233 }
5234
5235 fn dispatch_action_on_node(
5236 &mut self,
5237 node_id: DispatchNodeId,
5238 action: &dyn Action,
5239 cx: &mut App,
5240 ) {
5241 let dispatch_path = self.rendered_frame.dispatch_tree.dispatch_path(node_id);
5242
5243 cx.propagate_event = true;
5245 if let Some(mut global_listeners) = cx
5246 .global_action_listeners
5247 .remove(&action.as_any().type_id())
5248 {
5249 for listener in &global_listeners {
5250 listener(action.as_any(), DispatchPhase::Capture, cx);
5251 if !cx.propagate_event {
5252 break;
5253 }
5254 }
5255
5256 global_listeners.extend(
5257 cx.global_action_listeners
5258 .remove(&action.as_any().type_id())
5259 .unwrap_or_default(),
5260 );
5261
5262 cx.global_action_listeners
5263 .insert(action.as_any().type_id(), global_listeners);
5264 }
5265
5266 if !cx.propagate_event {
5267 return;
5268 }
5269
5270 for node_id in &dispatch_path {
5272 let node = self.rendered_frame.dispatch_tree.node(*node_id);
5273 for DispatchActionListener {
5274 action_type,
5275 listener,
5276 } in node.action_listeners.clone()
5277 {
5278 let any_action = action.as_any();
5279 if action_type == any_action.type_id() {
5280 listener(any_action, DispatchPhase::Capture, self, cx);
5281
5282 if !cx.propagate_event {
5283 return;
5284 }
5285 }
5286 }
5287 }
5288
5289 for node_id in dispatch_path.iter().rev() {
5291 let node = self.rendered_frame.dispatch_tree.node(*node_id);
5292 for DispatchActionListener {
5293 action_type,
5294 listener,
5295 } in node.action_listeners.clone()
5296 {
5297 let any_action = action.as_any();
5298 if action_type == any_action.type_id() {
5299 cx.propagate_event = false; listener(any_action, DispatchPhase::Bubble, self, cx);
5301
5302 if !cx.propagate_event {
5303 return;
5304 }
5305 }
5306 }
5307 }
5308
5309 if let Some(mut global_listeners) = cx
5311 .global_action_listeners
5312 .remove(&action.as_any().type_id())
5313 {
5314 for listener in global_listeners.iter().rev() {
5315 cx.propagate_event = false; listener(action.as_any(), DispatchPhase::Bubble, cx);
5318 if !cx.propagate_event {
5319 break;
5320 }
5321 }
5322
5323 global_listeners.extend(
5324 cx.global_action_listeners
5325 .remove(&action.as_any().type_id())
5326 .unwrap_or_default(),
5327 );
5328
5329 cx.global_action_listeners
5330 .insert(action.as_any().type_id(), global_listeners);
5331 }
5332 }
5333
5334 pub fn observe_global<G: Global>(
5337 &mut self,
5338 cx: &mut App,
5339 f: impl Fn(&mut Window, &mut App) + 'static,
5340 ) -> Subscription {
5341 let window_handle = self.handle;
5342 let (subscription, activate) = cx.global_observers.insert(
5343 TypeId::of::<G>(),
5344 Box::new(move |cx| {
5345 window_handle
5346 .update(cx, |_, window, cx| f(window, cx))
5347 .is_ok()
5348 }),
5349 );
5350 cx.defer(move |_| activate());
5351 subscription
5352 }
5353
5354 pub fn activate_window(&self) {
5356 self.platform_window.activate();
5357 }
5358
5359 pub fn request_attention(&self) {
5361 self.platform_window.request_attention();
5362 }
5363
5364 pub fn minimize_window(&self) {
5366 self.platform_window.minimize();
5367 }
5368
5369 pub fn show_window(&self) {
5371 self.platform_window.show();
5372 }
5373
5374 pub fn hide_window(&self) {
5376 self.platform_window.hide();
5377 }
5378
5379 pub fn is_window_visible(&self) -> bool {
5381 self.platform_window.is_visible()
5382 }
5383
5384 pub fn set_mouse_passthrough(&self, passthrough: bool) {
5386 self.platform_window.set_mouse_passthrough(passthrough);
5387 }
5388
5389 pub fn set_input_region(&self, region: Option<&[Bounds<Pixels>]>) {
5396 self.platform_window.set_input_region(region);
5397 }
5398
5399 pub fn toggle_fullscreen(&self) {
5401 self.platform_window.toggle_fullscreen();
5402 }
5403
5404 pub fn toggle_simple_fullscreen(&self) {
5409 self.platform_window.toggle_simple_fullscreen();
5410 }
5411
5412 pub fn set_progress_bar(&self, state: ProgressBarState) {
5414 self.platform_window.set_progress_bar(state);
5415 }
5416
5417 pub fn window_state(&self) -> WindowState {
5419 let bounds = self.platform_window.window_bounds();
5420 let display_id = self.platform_window.display().map(|d| d.id());
5421 let fullscreen = self.platform_window.is_fullscreen();
5422 WindowState {
5423 bounds,
5424 display_id,
5425 fullscreen,
5426 }
5427 }
5428
5429 pub fn restore_window_state(&self, state: &WindowState) {
5435 let is_fullscreen = self.platform_window.is_fullscreen();
5436 if state.fullscreen != is_fullscreen {
5437 self.platform_window.toggle_fullscreen();
5438 }
5439 }
5440
5441 pub fn invalidate_character_coordinates(&self) {
5443 self.on_next_frame(|window, cx| {
5444 if let Some(mut input_handler) = window.platform_window.take_input_handler() {
5445 if let Some(bounds) = input_handler.selected_bounds(window, cx) {
5446 window.platform_window.update_ime_position(bounds);
5447 }
5448 window.platform_window.set_input_handler(input_handler);
5449 }
5450 });
5451 }
5452
5453 pub fn prompt<T>(
5457 &mut self,
5458 level: PromptLevel,
5459 message: &str,
5460 detail: Option<&str>,
5461 answers: &[T],
5462 cx: &mut App,
5463 ) -> oneshot::Receiver<usize>
5464 where
5465 T: Clone + Into<PromptButton>,
5466 {
5467 let prompt_builder = cx.prompt_builder.take();
5468 let Some(prompt_builder) = prompt_builder else {
5469 unreachable!("Re-entrant window prompting is not supported by GPUI");
5470 };
5471
5472 let answers = answers
5473 .iter()
5474 .map(|answer| answer.clone().into())
5475 .collect::<Vec<_>>();
5476
5477 let receiver = match &prompt_builder {
5478 PromptBuilder::Default => self
5479 .platform_window
5480 .prompt(level, message, detail, &answers)
5481 .unwrap_or_else(|| {
5482 self.build_custom_prompt(&prompt_builder, level, message, detail, &answers, cx)
5483 }),
5484 PromptBuilder::Custom(_) => {
5485 self.build_custom_prompt(&prompt_builder, level, message, detail, &answers, cx)
5486 }
5487 };
5488
5489 cx.prompt_builder = Some(prompt_builder);
5490
5491 receiver
5492 }
5493
5494 fn build_custom_prompt(
5495 &mut self,
5496 prompt_builder: &PromptBuilder,
5497 level: PromptLevel,
5498 message: &str,
5499 detail: Option<&str>,
5500 answers: &[PromptButton],
5501 cx: &mut App,
5502 ) -> oneshot::Receiver<usize> {
5503 let (sender, receiver) = oneshot::channel();
5504 let handle = PromptHandle::new(sender);
5505 let handle = (prompt_builder)(level, message, detail, answers, handle, self, cx);
5506 self.prompt = Some(handle);
5507 receiver
5508 }
5509
5510 pub fn has_active_prompt(&self) -> bool {
5514 self.prompt.is_some()
5515 }
5516
5517 pub fn context_stack(&self) -> Vec<KeyContext> {
5519 let node_id = self.focus_node_id_in_rendered_frame(self.focus);
5520 let dispatch_tree = &self.rendered_frame.dispatch_tree;
5521 dispatch_tree
5522 .dispatch_path(node_id)
5523 .iter()
5524 .filter_map(move |&node_id| dispatch_tree.node(node_id).context.clone())
5525 .collect()
5526 }
5527
5528 pub fn available_actions(&self, cx: &App) -> Vec<Box<dyn Action>> {
5530 let node_id = self.focus_node_id_in_rendered_frame(self.focus);
5531 let mut actions = self.rendered_frame.dispatch_tree.available_actions(node_id);
5532 for action_type in cx.global_action_listeners.keys() {
5533 if let Err(ix) = actions.binary_search_by_key(action_type, |a| a.as_any().type_id()) {
5534 let action = cx.actions.build_action_type(action_type).ok();
5535 if let Some(action) = action {
5536 actions.insert(ix, action);
5537 }
5538 }
5539 }
5540 actions
5541 }
5542
5543 pub fn bindings_for_action(&self, action: &dyn Action) -> Vec<KeyBinding> {
5546 self.rendered_frame
5547 .dispatch_tree
5548 .bindings_for_action(action, &self.rendered_frame.dispatch_tree.context_stack)
5549 }
5550
5551 pub fn highest_precedence_binding_for_action(&self, action: &dyn Action) -> Option<KeyBinding> {
5554 self.rendered_frame
5555 .dispatch_tree
5556 .highest_precedence_binding_for_action(
5557 action,
5558 &self.rendered_frame.dispatch_tree.context_stack,
5559 )
5560 }
5561
5562 pub fn bindings_for_action_in_context(
5564 &self,
5565 action: &dyn Action,
5566 context: KeyContext,
5567 ) -> Vec<KeyBinding> {
5568 let dispatch_tree = &self.rendered_frame.dispatch_tree;
5569 dispatch_tree.bindings_for_action(action, &[context])
5570 }
5571
5572 pub fn highest_precedence_binding_for_action_in_context(
5575 &self,
5576 action: &dyn Action,
5577 context: KeyContext,
5578 ) -> Option<KeyBinding> {
5579 let dispatch_tree = &self.rendered_frame.dispatch_tree;
5580 dispatch_tree.highest_precedence_binding_for_action(action, &[context])
5581 }
5582
5583 pub fn bindings_for_action_in(
5587 &self,
5588 action: &dyn Action,
5589 focus_handle: &FocusHandle,
5590 ) -> Vec<KeyBinding> {
5591 let dispatch_tree = &self.rendered_frame.dispatch_tree;
5592 let Some(context_stack) = self.context_stack_for_focus_handle(focus_handle) else {
5593 return vec![];
5594 };
5595 dispatch_tree.bindings_for_action(action, &context_stack)
5596 }
5597
5598 pub fn highest_precedence_binding_for_action_in(
5602 &self,
5603 action: &dyn Action,
5604 focus_handle: &FocusHandle,
5605 ) -> Option<KeyBinding> {
5606 let dispatch_tree = &self.rendered_frame.dispatch_tree;
5607 let context_stack = self.context_stack_for_focus_handle(focus_handle)?;
5608 dispatch_tree.highest_precedence_binding_for_action(action, &context_stack)
5609 }
5610
5611 fn context_stack_for_focus_handle(
5612 &self,
5613 focus_handle: &FocusHandle,
5614 ) -> Option<Vec<KeyContext>> {
5615 let dispatch_tree = &self.rendered_frame.dispatch_tree;
5616 let node_id = dispatch_tree.focusable_node_id(focus_handle.id)?;
5617 let context_stack: Vec<_> = dispatch_tree
5618 .dispatch_path(node_id)
5619 .into_iter()
5620 .filter_map(|node_id| dispatch_tree.node(node_id).context.clone())
5621 .collect();
5622 Some(context_stack)
5623 }
5624
5625 pub fn listener_for<V: Render, E>(
5627 &self,
5628 view: &Entity<V>,
5629 f: impl Fn(&mut V, &E, &mut Window, &mut Context<V>) + 'static,
5630 ) -> impl Fn(&E, &mut Window, &mut App) + 'static {
5631 let view = view.downgrade();
5632 move |e: &E, window: &mut Window, cx: &mut App| {
5633 view.update(cx, |view, cx| f(view, e, window, cx)).ok();
5634 }
5635 }
5636
5637 pub fn handler_for<V: Render, Callback: Fn(&mut V, &mut Window, &mut Context<V>) + 'static>(
5639 &self,
5640 view: &Entity<V>,
5641 f: Callback,
5642 ) -> impl Fn(&mut Window, &mut App) + use<V, Callback> {
5643 let view = view.downgrade();
5644 move |window: &mut Window, cx: &mut App| {
5645 view.update(cx, |view, cx| f(view, window, cx)).ok();
5646 }
5647 }
5648
5649 pub fn on_window_should_close(
5652 &self,
5653 cx: &App,
5654 f: impl Fn(&mut Window, &mut App) -> bool + 'static,
5655 ) {
5656 let mut cx = self.to_async(cx);
5657 self.platform_window.on_should_close(Box::new(move || {
5658 cx.update(|window, cx| f(window, cx)).unwrap_or(true)
5659 }))
5660 }
5661
5662 pub fn on_action(
5669 &mut self,
5670 action_type: TypeId,
5671 listener: impl Fn(&dyn Any, DispatchPhase, &mut Window, &mut App) + 'static,
5672 ) {
5673 self.next_frame
5674 .dispatch_tree
5675 .on_action(action_type, Rc::new(listener));
5676 }
5677
5678 pub fn on_action_when(
5685 &mut self,
5686 condition: bool,
5687 action_type: TypeId,
5688 listener: impl Fn(&dyn Any, DispatchPhase, &mut Window, &mut App) + 'static,
5689 ) {
5690 if condition {
5691 self.next_frame
5692 .dispatch_tree
5693 .on_action(action_type, Rc::new(listener));
5694 }
5695 }
5696
5697 pub fn gpu_specs(&self) -> Option<GpuSpecs> {
5700 self.platform_window.gpu_specs()
5701 }
5702
5703 pub fn titlebar_double_click(&self) {
5706 self.platform_window.titlebar_double_click();
5707 }
5708
5709 pub fn window_title(&self) -> String {
5712 self.platform_window.get_title()
5713 }
5714
5715 pub fn tabbed_windows(&self) -> Option<Vec<SystemWindowTab>> {
5718 self.platform_window.tabbed_windows()
5719 }
5720
5721 pub fn tab_bar_visible(&self) -> bool {
5724 self.platform_window.tab_bar_visible()
5725 }
5726
5727 pub fn merge_all_windows(&self) {
5730 self.platform_window.merge_all_windows()
5731 }
5732
5733 pub fn move_tab_to_new_window(&self) {
5736 self.platform_window.move_tab_to_new_window()
5737 }
5738
5739 pub fn toggle_window_tab_overview(&self) {
5742 self.platform_window.toggle_window_tab_overview()
5743 }
5744
5745 pub fn set_tabbing_identifier(&self, tabbing_identifier: Option<String>) {
5748 self.platform_window
5749 .set_tabbing_identifier(tabbing_identifier)
5750 }
5751
5752 pub fn play_system_bell(&self) {
5754 self.platform_window.play_system_bell()
5755 }
5756
5757 pub fn is_a11y_enabled(&self) -> bool {
5764 self.a11y.is_enabled()
5765 }
5766
5767 pub fn debug_a11y_tree_json(&self) -> Option<String> {
5771 self.a11y.debug_tree_json()
5772 }
5773
5774 pub fn on_a11y_action(
5778 &mut self,
5779 node_id: accesskit::NodeId,
5780 action: accesskit::Action,
5781 listener: impl FnMut(Option<&accesskit::ActionData>, &mut Window, &mut App) + 'static,
5782 ) {
5783 self.a11y
5784 .action_listeners
5785 .entry(node_id)
5786 .or_default()
5787 .push((action, Box::new(listener)));
5788 }
5789
5790 #[cfg(not(target_family = "wasm"))]
5791 pub(crate) fn handle_a11y_action(&mut self, request: accesskit::ActionRequest, cx: &mut App) {
5792 if let Some(mut listeners) = self.a11y.action_listeners.remove(&request.target_node) {
5793 let action_data = request.data.as_ref();
5794 let mut matched = false;
5795 for (action, listener) in &mut listeners {
5796 if *action == request.action {
5797 listener(action_data, self, cx);
5798 matched = true;
5799 }
5800 }
5801 self.a11y
5802 .action_listeners
5803 .insert(request.target_node, listeners);
5804 if matched {
5805 return;
5806 }
5807 }
5808
5809 match request.action {
5810 accesskit::Action::Click => {
5811 if let Some(bounds) = self.a11y.node_bounds.get(&request.target_node).copied() {
5812 let center = bounds.center();
5813 self.dispatch_event(
5814 PlatformInput::MouseDown(crate::MouseDownEvent {
5815 button: MouseButton::Left,
5816 position: center,
5817 modifiers: Modifiers::default(),
5818 click_count: 1,
5819 first_mouse: false,
5820 }),
5821 cx,
5822 );
5823 self.dispatch_event(
5824 PlatformInput::MouseUp(MouseUpEvent {
5825 button: MouseButton::Left,
5826 position: center,
5827 modifiers: Modifiers::default(),
5828 click_count: 1,
5829 }),
5830 cx,
5831 );
5832 }
5833 }
5834 accesskit::Action::Focus => {
5835 if let Some(focus_id) = self.a11y.focus_ids.get(&request.target_node).copied()
5836 && let Some(handle) = FocusHandle::for_id(focus_id, &cx.focus_handles)
5837 {
5838 self.focus(&handle);
5839 }
5840 }
5841 accesskit::Action::Blur => self.blur(cx),
5842 _ => {
5843 log::debug!(
5844 "Unhandled a11y action: {:?} on {:?}",
5845 request.action,
5846 request.target_node
5847 );
5848 }
5849 }
5850 }
5851
5852 #[cfg(any(feature = "inspector", debug_assertions))]
5854 pub fn toggle_inspector(&mut self, cx: &mut App) {
5855 self.inspector = match self.inspector {
5856 None => Some(cx.new(|_| Inspector::new())),
5857 Some(_) => None,
5858 };
5859 self.refresh();
5860 }
5861
5862 pub fn is_inspector_picking(&self, _cx: &App) -> bool {
5864 #[cfg(any(feature = "inspector", debug_assertions))]
5865 {
5866 if let Some(inspector) = &self.inspector {
5867 return inspector.read(_cx).is_picking();
5868 }
5869 }
5870 false
5871 }
5872
5873 #[cfg(any(feature = "inspector", debug_assertions))]
5875 pub fn with_inspector_state<T: 'static, R>(
5876 &mut self,
5877 _inspector_id: Option<&crate::InspectorElementId>,
5878 cx: &mut App,
5879 f: impl FnOnce(&mut Option<T>, &mut Self) -> R,
5880 ) -> R {
5881 if let Some(inspector_id) = _inspector_id
5882 && let Some(inspector) = &self.inspector
5883 {
5884 let inspector = inspector.clone();
5885 let active_element_id = inspector.read(cx).active_element_id();
5886 if Some(inspector_id) == active_element_id {
5887 return inspector.update(cx, |inspector, _cx| {
5888 inspector.with_active_element_state(self, f)
5889 });
5890 }
5891 }
5892 f(&mut None, self)
5893 }
5894
5895 #[cfg(any(feature = "inspector", debug_assertions))]
5896 pub(crate) fn build_inspector_element_id(
5897 &mut self,
5898 path: crate::InspectorElementPath,
5899 ) -> crate::InspectorElementId {
5900 self.invalidator.debug_assert_paint_or_prepaint();
5901 let path = Rc::new(path);
5902 let next_instance_id = self
5903 .next_frame
5904 .next_inspector_instance_ids
5905 .entry(path.clone())
5906 .or_insert(0);
5907 let instance_id = *next_instance_id;
5908 *next_instance_id += 1;
5909 crate::InspectorElementId { path, instance_id }
5910 }
5911
5912 #[cfg(any(feature = "inspector", debug_assertions))]
5913 fn prepaint_inspector(&mut self, inspector_width: Pixels, cx: &mut App) -> Option<AnyElement> {
5914 if let Some(inspector) = self.inspector.take() {
5915 let mut inspector_element = AnyView::from(inspector.clone()).into_any_element();
5916 inspector_element.prepaint_as_root(
5917 point(self.viewport_size.width - inspector_width, px(0.0)),
5918 size(inspector_width, self.viewport_size.height).into(),
5919 self,
5920 cx,
5921 );
5922 self.inspector = Some(inspector);
5923 Some(inspector_element)
5924 } else {
5925 None
5926 }
5927 }
5928
5929 #[cfg(any(feature = "inspector", debug_assertions))]
5930 fn paint_inspector(&mut self, mut inspector_element: Option<AnyElement>, cx: &mut App) {
5931 if let Some(mut inspector_element) = inspector_element {
5932 inspector_element.paint(self, cx);
5933 };
5934 }
5935
5936 #[cfg(any(feature = "inspector", debug_assertions))]
5939 pub fn insert_inspector_hitbox(
5940 &mut self,
5941 hitbox_id: HitboxId,
5942 inspector_id: Option<&crate::InspectorElementId>,
5943 cx: &App,
5944 ) {
5945 self.invalidator.debug_assert_paint_or_prepaint();
5946 if !self.is_inspector_picking(cx) {
5947 return;
5948 }
5949 if let Some(inspector_id) = inspector_id {
5950 self.next_frame
5951 .inspector_hitboxes
5952 .insert(hitbox_id, inspector_id.clone());
5953 }
5954 }
5955
5956 #[cfg(any(feature = "inspector", debug_assertions))]
5957 fn paint_inspector_hitbox(&mut self, cx: &App) {
5958 if let Some(inspector) = self.inspector.as_ref() {
5959 let inspector = inspector.read(cx);
5960 if let Some((hitbox_id, _)) = self.hovered_inspector_hitbox(inspector, &self.next_frame)
5961 && let Some(hitbox) = self
5962 .next_frame
5963 .hitboxes
5964 .iter()
5965 .find(|hitbox| hitbox.id == hitbox_id)
5966 {
5967 self.paint_quad(crate::fill(hitbox.bounds, crate::rgba(0x61afef4d)));
5968 }
5969 }
5970 }
5971
5972 #[cfg(any(feature = "inspector", debug_assertions))]
5973 fn handle_inspector_mouse_event(&mut self, event: &dyn Any, cx: &mut App) {
5974 let Some(inspector) = self.inspector.clone() else {
5975 return;
5976 };
5977 if event.downcast_ref::<MouseMoveEvent>().is_some() {
5978 inspector.update(cx, |inspector, _cx| {
5979 if let Some((_, inspector_id)) =
5980 self.hovered_inspector_hitbox(inspector, &self.rendered_frame)
5981 {
5982 inspector.hover(inspector_id, self);
5983 }
5984 });
5985 } else if event.downcast_ref::<crate::MouseDownEvent>().is_some() {
5986 inspector.update(cx, |inspector, _cx| {
5987 if let Some((_, inspector_id)) =
5988 self.hovered_inspector_hitbox(inspector, &self.rendered_frame)
5989 {
5990 inspector.select(inspector_id, self);
5991 }
5992 });
5993 } else if let Some(event) = event.downcast_ref::<crate::ScrollWheelEvent>() {
5994 const SCROLL_LINES: f32 = 3.0;
5996 const SCROLL_PIXELS_PER_LAYER: f32 = 36.0;
5997 let delta_y = event
5998 .delta
5999 .pixel_delta(px(SCROLL_PIXELS_PER_LAYER / SCROLL_LINES))
6000 .y;
6001 if let Some(inspector) = self.inspector.clone() {
6002 inspector.update(cx, |inspector, _cx| {
6003 if let Some(depth) = inspector.pick_depth.as_mut() {
6004 *depth += f32::from(delta_y) / SCROLL_PIXELS_PER_LAYER;
6005 let max_depth = self.mouse_hit_test.ids.len() as f32 - 0.5;
6006 if *depth < 0.0 {
6007 *depth = 0.0;
6008 } else if *depth > max_depth {
6009 *depth = max_depth;
6010 }
6011 if let Some((_, inspector_id)) =
6012 self.hovered_inspector_hitbox(inspector, &self.rendered_frame)
6013 {
6014 inspector.set_active_element_id(inspector_id, self);
6015 }
6016 }
6017 });
6018 }
6019 }
6020 }
6021
6022 #[cfg(any(feature = "inspector", debug_assertions))]
6023 fn hovered_inspector_hitbox(
6024 &self,
6025 inspector: &Inspector,
6026 frame: &Frame,
6027 ) -> Option<(HitboxId, crate::InspectorElementId)> {
6028 if let Some(pick_depth) = inspector.pick_depth {
6029 let depth = (pick_depth as i64).try_into().unwrap_or(0);
6030 let max_skipped = self.mouse_hit_test.ids.len().saturating_sub(1);
6031 let skip_count = (depth as usize).min(max_skipped);
6032 for hitbox_id in self.mouse_hit_test.ids.iter().skip(skip_count) {
6033 if let Some(inspector_id) = frame.inspector_hitboxes.get(hitbox_id) {
6034 return Some((*hitbox_id, inspector_id.clone()));
6035 }
6036 }
6037 }
6038 None
6039 }
6040
6041 #[cfg(any(test, feature = "test-support"))]
6044 pub fn set_modifiers(&mut self, modifiers: Modifiers) {
6045 self.modifiers = modifiers;
6046 }
6047}
6048
6049slotmap::new_key_type! {
6051 pub struct WindowId;
6053}
6054
6055impl WindowId {
6056 pub fn as_u64(&self) -> u64 {
6058 self.0.as_ffi()
6059 }
6060}
6061
6062impl From<u64> for WindowId {
6063 fn from(value: u64) -> Self {
6064 WindowId(slotmap::KeyData::from_ffi(value))
6065 }
6066}
6067
6068#[derive(Deref, DerefMut)]
6071pub struct WindowHandle<V> {
6072 #[deref]
6073 #[deref_mut]
6074 pub(crate) any_handle: AnyWindowHandle,
6075 state_type: PhantomData<V>,
6076}
6077
6078impl<V> Debug for WindowHandle<V> {
6079 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
6080 f.debug_struct("WindowHandle")
6081 .field("any_handle", &self.any_handle.id.as_u64())
6082 .finish()
6083 }
6084}
6085
6086impl<V: 'static + Render> WindowHandle<V> {
6087 pub fn new(id: WindowId) -> Self {
6090 WindowHandle {
6091 any_handle: AnyWindowHandle {
6092 id,
6093 state_type: TypeId::of::<V>(),
6094 },
6095 state_type: PhantomData,
6096 }
6097 }
6098
6099 #[cfg(any(test, feature = "test-support"))]
6103 pub fn root<C>(&self, cx: &mut C) -> Result<Entity<V>>
6104 where
6105 C: AppContext,
6106 {
6107 crate::Flatten::flatten(cx.update_window(self.any_handle, |root_view, _, _| {
6108 root_view
6109 .downcast::<V>()
6110 .map_err(|_| anyhow!("the type of the window's root view has changed"))
6111 }))
6112 }
6113
6114 pub fn update<C, R>(
6118 &self,
6119 cx: &mut C,
6120 update: impl FnOnce(&mut V, &mut Window, &mut Context<V>) -> R,
6121 ) -> Result<R>
6122 where
6123 C: AppContext,
6124 {
6125 cx.update_window(self.any_handle, |root_view, window, cx| {
6126 let view = root_view
6127 .downcast::<V>()
6128 .map_err(|_| anyhow!("the type of the window's root view has changed"))?;
6129
6130 Ok(view.update(cx, |view, cx| update(view, window, cx)))
6131 })?
6132 }
6133
6134 pub fn read<'a>(&self, cx: &'a App) -> Result<&'a V> {
6138 let x = cx
6139 .windows
6140 .get(self.id)
6141 .and_then(|window| {
6142 window
6143 .as_ref()
6144 .and_then(|window| window.root.clone())
6145 .map(|root_view| root_view.downcast::<V>())
6146 })
6147 .context("window not found")?
6148 .map_err(|_| anyhow!("the type of the window's root view has changed"))?;
6149
6150 Ok(x.read(cx))
6151 }
6152
6153 pub fn read_with<C, R>(&self, cx: &C, read_with: impl FnOnce(&V, &App) -> R) -> Result<R>
6157 where
6158 C: AppContext,
6159 {
6160 cx.read_window(self, |root_view, cx| read_with(root_view.read(cx), cx))
6161 }
6162
6163 pub fn entity<C>(&self, cx: &C) -> Result<Entity<V>>
6167 where
6168 C: AppContext,
6169 {
6170 cx.read_window(self, |root_view, _cx| root_view)
6171 }
6172
6173 pub fn is_active(&self, cx: &mut App) -> Option<bool> {
6178 cx.update_window(self.any_handle, |_, window, _| window.is_window_active())
6179 .ok()
6180 }
6181}
6182
6183impl<V> Copy for WindowHandle<V> {}
6184
6185impl<V> Clone for WindowHandle<V> {
6186 fn clone(&self) -> Self {
6187 *self
6188 }
6189}
6190
6191impl<V> PartialEq for WindowHandle<V> {
6192 fn eq(&self, other: &Self) -> bool {
6193 self.any_handle == other.any_handle
6194 }
6195}
6196
6197impl<V> Eq for WindowHandle<V> {}
6198
6199impl<V> Hash for WindowHandle<V> {
6200 fn hash<H: Hasher>(&self, state: &mut H) {
6201 self.any_handle.hash(state);
6202 }
6203}
6204
6205impl<V: 'static> From<WindowHandle<V>> for AnyWindowHandle {
6206 fn from(val: WindowHandle<V>) -> Self {
6207 val.any_handle
6208 }
6209}
6210
6211unsafe impl<V> Send for WindowHandle<V> {}
6212unsafe impl<V> Sync for WindowHandle<V> {}
6213
6214#[derive(Copy, Clone, PartialEq, Eq, Hash)]
6216pub struct AnyWindowHandle {
6217 pub(crate) id: WindowId,
6218 state_type: TypeId,
6219}
6220
6221impl AnyWindowHandle {
6222 pub fn window_id(&self) -> WindowId {
6224 self.id
6225 }
6226
6227 pub fn downcast<T: 'static>(&self) -> Option<WindowHandle<T>> {
6230 if TypeId::of::<T>() == self.state_type {
6231 Some(WindowHandle {
6232 any_handle: *self,
6233 state_type: PhantomData,
6234 })
6235 } else {
6236 None
6237 }
6238 }
6239
6240 pub fn update<C, R>(
6244 self,
6245 cx: &mut C,
6246 update: impl FnOnce(AnyView, &mut Window, &mut App) -> R,
6247 ) -> Result<R>
6248 where
6249 C: AppContext,
6250 {
6251 cx.update_window(self, update)
6252 }
6253
6254 pub fn read<T, C, R>(self, cx: &C, read: impl FnOnce(Entity<T>, &App) -> R) -> Result<R>
6258 where
6259 C: AppContext,
6260 T: 'static,
6261 {
6262 let view = self
6263 .downcast::<T>()
6264 .context("the type of the window's root view has changed")?;
6265
6266 cx.read_window(&view, read)
6267 }
6268}
6269
6270impl HasWindowHandle for Window {
6271 fn window_handle(&self) -> Result<raw_window_handle::WindowHandle<'_>, HandleError> {
6272 self.platform_window.window_handle()
6273 }
6274}
6275
6276impl HasDisplayHandle for Window {
6277 fn display_handle(
6278 &self,
6279 ) -> std::result::Result<raw_window_handle::DisplayHandle<'_>, HandleError> {
6280 self.platform_window.display_handle()
6281 }
6282}
6283
6284#[derive(Clone, Debug, Eq, PartialEq, Hash)]
6289pub enum ElementId {
6290 View(EntityId),
6292 Integer(u64),
6294 Name(SharedString),
6296 Uuid(Uuid),
6298 FocusHandle(FocusId),
6300 NamedInteger(SharedString, u64),
6302 Path(Arc<std::path::Path>),
6304 CodeLocation(core::panic::Location<'static>),
6306 NamedChild(Box<ElementId>, SharedString),
6308 OpaqueId([u8; 20]),
6310}
6311
6312impl ElementId {
6313 pub fn named_usize(name: impl Into<SharedString>, integer: usize) -> ElementId {
6315 Self::NamedInteger(name.into(), integer as u64)
6316 }
6317}
6318
6319impl Display for ElementId {
6320 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
6321 match self {
6322 ElementId::View(entity_id) => write!(f, "view-{}", entity_id)?,
6323 ElementId::Integer(ix) => write!(f, "{}", ix)?,
6324 ElementId::Name(name) => write!(f, "{}", name)?,
6325 ElementId::FocusHandle(_) => write!(f, "FocusHandle")?,
6326 ElementId::NamedInteger(s, i) => write!(f, "{}-{}", s, i)?,
6327 ElementId::Uuid(uuid) => write!(f, "{}", uuid)?,
6328 ElementId::Path(path) => write!(f, "{}", path.display())?,
6329 ElementId::CodeLocation(location) => write!(f, "{}", location)?,
6330 ElementId::NamedChild(id, name) => write!(f, "{}-{}", id, name)?,
6331 ElementId::OpaqueId(opaque_id) => write!(f, "{:x?}", opaque_id)?,
6332 }
6333
6334 Ok(())
6335 }
6336}
6337
6338impl TryInto<SharedString> for ElementId {
6339 type Error = anyhow::Error;
6340
6341 fn try_into(self) -> anyhow::Result<SharedString> {
6342 if let ElementId::Name(name) = self {
6343 Ok(name)
6344 } else {
6345 anyhow::bail!("element id is not string")
6346 }
6347 }
6348}
6349
6350impl From<u64> for ElementId {
6351 fn from(id: u64) -> Self {
6352 ElementId::Integer(id)
6353 }
6354}
6355
6356impl From<usize> for ElementId {
6357 fn from(id: usize) -> Self {
6358 ElementId::Integer(id as u64)
6359 }
6360}
6361
6362impl From<i32> for ElementId {
6363 fn from(id: i32) -> Self {
6364 Self::Integer(id as u64)
6365 }
6366}
6367
6368impl From<SharedString> for ElementId {
6369 fn from(name: SharedString) -> Self {
6370 ElementId::Name(name)
6371 }
6372}
6373
6374impl From<String> for ElementId {
6375 fn from(name: String) -> Self {
6376 ElementId::Name(name.into())
6377 }
6378}
6379
6380impl From<Arc<str>> for ElementId {
6381 fn from(name: Arc<str>) -> Self {
6382 ElementId::Name(name.into())
6383 }
6384}
6385
6386impl From<Arc<std::path::Path>> for ElementId {
6387 fn from(path: Arc<std::path::Path>) -> Self {
6388 ElementId::Path(path)
6389 }
6390}
6391
6392impl From<&'static str> for ElementId {
6393 fn from(name: &'static str) -> Self {
6394 ElementId::Name(SharedString::new_static(name))
6395 }
6396}
6397
6398impl<'a> From<&'a FocusHandle> for ElementId {
6399 fn from(handle: &'a FocusHandle) -> Self {
6400 ElementId::FocusHandle(handle.id)
6401 }
6402}
6403
6404impl From<(&'static str, EntityId)> for ElementId {
6405 fn from((name, id): (&'static str, EntityId)) -> Self {
6406 ElementId::NamedInteger(SharedString::new_static(name), id.as_u64())
6407 }
6408}
6409
6410impl From<(&'static str, usize)> for ElementId {
6411 fn from((name, id): (&'static str, usize)) -> Self {
6412 ElementId::NamedInteger(SharedString::new_static(name), id as u64)
6413 }
6414}
6415
6416impl From<(SharedString, usize)> for ElementId {
6417 fn from((name, id): (SharedString, usize)) -> Self {
6418 ElementId::NamedInteger(name, id as u64)
6419 }
6420}
6421
6422impl From<(&'static str, u64)> for ElementId {
6423 fn from((name, id): (&'static str, u64)) -> Self {
6424 ElementId::NamedInteger(SharedString::new_static(name), id)
6425 }
6426}
6427
6428impl From<Uuid> for ElementId {
6429 fn from(value: Uuid) -> Self {
6430 Self::Uuid(value)
6431 }
6432}
6433
6434impl From<(&'static str, u32)> for ElementId {
6435 fn from((name, id): (&'static str, u32)) -> Self {
6436 ElementId::NamedInteger(SharedString::new_static(name), id.into())
6437 }
6438}
6439
6440impl<T: Into<SharedString>> From<(ElementId, T)> for ElementId {
6441 fn from((id, name): (ElementId, T)) -> Self {
6442 ElementId::NamedChild(Box::new(id), name.into())
6443 }
6444}
6445
6446impl From<&'static core::panic::Location<'static>> for ElementId {
6447 fn from(location: &'static core::panic::Location<'static>) -> Self {
6448 ElementId::CodeLocation(*location)
6449 }
6450}
6451
6452impl From<[u8; 20]> for ElementId {
6453 fn from(opaque_id: [u8; 20]) -> Self {
6454 ElementId::OpaqueId(opaque_id)
6455 }
6456}
6457
6458#[derive(Clone)]
6461pub struct PaintQuad {
6462 pub bounds: Bounds<Pixels>,
6464 pub corner_radii: Corners<Pixels>,
6466 pub background: Background,
6468 pub border_widths: Edges<Pixels>,
6470 pub border_color: Hsla,
6472 pub border_style: BorderStyle,
6474 pub continuous_corners: bool,
6476 pub transform: TransformationMatrix,
6478 pub blend_mode: BlendMode,
6480}
6481
6482impl PaintQuad {
6483 pub fn corner_radii(self, corner_radii: impl Into<Corners<Pixels>>) -> Self {
6485 PaintQuad {
6486 corner_radii: corner_radii.into(),
6487 ..self
6488 }
6489 }
6490
6491 pub fn border_widths(self, border_widths: impl Into<Edges<Pixels>>) -> Self {
6493 PaintQuad {
6494 border_widths: border_widths.into(),
6495 ..self
6496 }
6497 }
6498
6499 pub fn border_color(self, border_color: impl Into<Hsla>) -> Self {
6501 PaintQuad {
6502 border_color: border_color.into(),
6503 ..self
6504 }
6505 }
6506
6507 pub fn background(self, background: impl Into<Background>) -> Self {
6509 PaintQuad {
6510 background: background.into(),
6511 ..self
6512 }
6513 }
6514}
6515
6516pub fn quad(
6518 bounds: Bounds<Pixels>,
6519 corner_radii: impl Into<Corners<Pixels>>,
6520 background: impl Into<Background>,
6521 border_widths: impl Into<Edges<Pixels>>,
6522 border_color: impl Into<Hsla>,
6523 border_style: BorderStyle,
6524) -> PaintQuad {
6525 PaintQuad {
6526 bounds,
6527 corner_radii: corner_radii.into(),
6528 background: background.into(),
6529 border_widths: border_widths.into(),
6530 border_color: border_color.into(),
6531 border_style,
6532 continuous_corners: false,
6533 transform: TransformationMatrix::unit(),
6534 blend_mode: BlendMode::Normal,
6535 }
6536}
6537
6538pub fn fill(bounds: impl Into<Bounds<Pixels>>, background: impl Into<Background>) -> PaintQuad {
6540 PaintQuad {
6541 bounds: bounds.into(),
6542 corner_radii: (0.).into(),
6543 background: background.into(),
6544 border_widths: (0.).into(),
6545 border_color: transparent_black(),
6546 border_style: BorderStyle::default(),
6547 continuous_corners: false,
6548 transform: TransformationMatrix::unit(),
6549 blend_mode: BlendMode::Normal,
6550 }
6551}
6552
6553pub fn outline(
6555 bounds: impl Into<Bounds<Pixels>>,
6556 border_color: impl Into<Hsla>,
6557 border_style: BorderStyle,
6558) -> PaintQuad {
6559 PaintQuad {
6560 bounds: bounds.into(),
6561 corner_radii: (0.).into(),
6562 background: transparent_black().into(),
6563 border_widths: (1.).into(),
6564 border_color: border_color.into(),
6565 border_style,
6566 continuous_corners: false,
6567 transform: TransformationMatrix::unit(),
6568 blend_mode: BlendMode::Normal,
6569 }
6570}
6571
6572#[cfg(test)]
6573mod tests {
6574 use super::*;
6575 use crate::{
6576 ContentMask, Context, ExternalPaths, HitboxBehavior, InputEvent as _, QuitMode, Render,
6577 TestAppContext, WindowOptions, bounds, canvas, div, hsla, point, px, size,
6578 };
6579 use std::{
6580 cell::{Cell, RefCell},
6581 path::PathBuf,
6582 rc::Rc,
6583 };
6584
6585 #[test]
6586 fn high_rate_input_avoids_inactive_window_throttling() {
6587 let default_inactive = Some(Duration::from_micros(33333));
6588 assert_eq!(
6589 frame_throttle_interval(true, false, false, false, false, false, default_inactive),
6590 default_inactive
6591 );
6592 assert_eq!(
6593 frame_throttle_interval(true, false, false, false, true, false, default_inactive),
6594 None
6595 );
6596 assert_eq!(
6597 frame_throttle_interval(true, false, false, false, true, true, default_inactive),
6598 Some(Duration::from_micros(16667)),
6599 "thermal pressure still caps high-rate input"
6600 );
6601 }
6602
6603 #[test]
6604 fn inactive_frame_interval_is_configurable() {
6605 let custom = Some(Duration::from_millis(16));
6606 assert_eq!(
6607 frame_throttle_interval(true, false, false, false, false, false, custom),
6608 custom
6609 );
6610 assert_eq!(
6611 frame_throttle_interval(true, false, false, false, false, false, None),
6612 None,
6613 "None disables inactive-window throttling"
6614 );
6615 }
6616
6617 #[test]
6618 fn hovered_at_ignores_pointer_capture() {
6619 let mut cx = TestAppContext::single();
6620 let window = cx.add_window(|_, _| EmptyView);
6621 let window: AnyWindowHandle = window.into();
6622
6623 cx.update_window(window, |_, window, _| {
6624 let bounds = bounds(point(px(0.), px(0.)), size(px(10.), px(10.)));
6625 let hitbox = Hitbox {
6626 id: HitboxId(1),
6627 bounds,
6628 content_mask: ContentMask { bounds },
6629 behavior: HitboxBehavior::Normal,
6630 };
6631 window.rendered_frame.hitboxes.push(hitbox.clone());
6632 window.capture_pointer(hitbox.id);
6633
6634 assert!(hitbox.is_hovered(window));
6635 assert!(hitbox.is_hovered_at(point(px(5.), px(5.)), window));
6636 assert!(!hitbox.is_hovered_at(point(px(20.), px(20.)), window));
6637 })
6638 .unwrap();
6639 }
6640
6641 #[test]
6642 fn hovered_at_respects_content_masks_and_occlusion() {
6643 let mut cx = TestAppContext::single();
6644 let window = cx.add_window(|_, _| EmptyView);
6645 let window: AnyWindowHandle = window.into();
6646
6647 cx.update_window(window, |_, window, _| {
6648 let target_bounds = bounds(point(px(0.), px(0.)), size(px(20.), px(20.)));
6649 let target = Hitbox {
6650 id: HitboxId(1),
6651 bounds: target_bounds,
6652 content_mask: ContentMask {
6653 bounds: bounds(point(px(0.), px(0.)), size(px(10.), px(20.))),
6654 },
6655 behavior: HitboxBehavior::Normal,
6656 };
6657 let blocker = Hitbox {
6658 id: HitboxId(2),
6659 bounds: target_bounds,
6660 content_mask: ContentMask {
6661 bounds: target_bounds,
6662 },
6663 behavior: HitboxBehavior::BlockMouse,
6664 };
6665 window.rendered_frame.hitboxes.push(target.clone());
6666 assert!(target.is_hovered_at(point(px(5.), px(5.)), window));
6667 assert!(!target.is_hovered_at(point(px(15.), px(5.)), window));
6668
6669 window.rendered_frame.hitboxes.push(blocker.clone());
6670
6671 assert!(!target.is_hovered_at(point(px(5.), px(5.)), window));
6672 assert!(blocker.is_hovered_at(point(px(15.), px(5.)), window));
6673 })
6674 .unwrap();
6675 }
6676
6677 #[test]
6678 fn hovered_at_ignores_keyboard_input_modality() {
6679 let mut cx = TestAppContext::single();
6680 let window = cx.add_window(|_, _| EmptyView);
6681 let window: AnyWindowHandle = window.into();
6682
6683 cx.update_window(window, |_, window, _| {
6684 let bounds = bounds(point(px(0.), px(0.)), size(px(10.), px(10.)));
6685 let hitbox = Hitbox {
6686 id: HitboxId(1),
6687 bounds,
6688 content_mask: ContentMask { bounds },
6689 behavior: HitboxBehavior::Normal,
6690 };
6691 window.rendered_frame.hitboxes.push(hitbox.clone());
6692 window.last_input_was_keyboard.set(true);
6693
6694 assert!(!hitbox.is_hovered(window));
6695 assert!(hitbox.is_hovered_at(point(px(5.), px(5.)), window));
6696 })
6697 .unwrap();
6698 }
6699
6700 #[test]
6704 fn draw_in_progress_tracks_element_arena_scope() {
6705 assert!(!draw_in_progress());
6706
6707 let scope = ElementArenaScope::enter();
6708 assert!(draw_in_progress());
6709
6710 let nested = ElementArenaScope::enter();
6711 assert!(draw_in_progress());
6712 drop(nested);
6713 assert!(draw_in_progress(), "outer draw is still in progress");
6714
6715 drop(scope);
6716 assert!(!draw_in_progress());
6717 }
6718
6719 struct EmptyView;
6720
6721 impl Render for EmptyView {
6722 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
6723 div()
6724 }
6725 }
6726
6727 struct FileDropExitView(Rc<Cell<usize>>);
6728
6729 impl Render for FileDropExitView {
6730 fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
6731 div().size_full().on_file_drop_exit({
6732 let observed_file_drop_exit = self.0.clone();
6733 move |_, _, _| observed_file_drop_exit.set(observed_file_drop_exit.get() + 1)
6734 })
6735 }
6736 }
6737
6738 #[test]
6742 fn file_drop_exit_is_window_local() {
6743 let mut cx = TestAppContext::single();
6744 let first_destination_exit_count = Rc::new(Cell::new(0));
6745 let first_destination: AnyWindowHandle = cx
6746 .add_window({
6747 let first_destination_exit_count = first_destination_exit_count.clone();
6748 move |_, _| FileDropExitView(first_destination_exit_count)
6749 })
6750 .into();
6751 let second_destination_exit_count = Rc::new(Cell::new(0));
6752 let second_destination: AnyWindowHandle = cx
6753 .add_window({
6754 let second_destination_exit_count = second_destination_exit_count.clone();
6755 move |_, _| FileDropExitView(second_destination_exit_count)
6756 })
6757 .into();
6758 let reentry_position = point(px(30.), px(30.));
6759 let external_paths =
6760 || ExternalPaths([PathBuf::from("/tmp/dropped.txt")].into_iter().collect());
6761
6762 let update_result = cx.update_window(first_destination, |_, window, cx| {
6763 window.draw(cx).clear();
6764 window.dispatch_event(
6765 FileDropEvent::Entered {
6766 position: reentry_position,
6767 paths: external_paths(),
6768 }
6769 .to_platform_input(),
6770 cx,
6771 );
6772 window.dispatch_event(FileDropEvent::Exited.to_platform_input(), cx);
6773 assert!(cx.active_drag.is_none());
6774 assert_eq!(first_destination_exit_count.get(), 1);
6775 assert_eq!(second_destination_exit_count.get(), 0);
6776 });
6777 assert!(
6778 update_result.is_ok(),
6779 "failed to handle drag in first destination window: {update_result:?}"
6780 );
6781
6782 let update_result = cx.update_window(second_destination, |_, window, cx| {
6783 window.draw(cx).clear();
6784 window.dispatch_event(
6785 PlatformInput::KeyDown(KeyDownEvent {
6786 keystroke: Keystroke::parse("down").expect("valid keystroke"),
6787 is_held: false,
6788 prefer_character_input: false,
6789 }),
6790 cx,
6791 );
6792 window.dispatch_event(
6793 FileDropEvent::Entered {
6794 position: reentry_position,
6795 paths: external_paths(),
6796 }
6797 .to_platform_input(),
6798 cx,
6799 );
6800 assert!(
6801 cx.active_drag
6802 .as_ref()
6803 .is_some_and(|drag| drag.value.downcast_ref::<ExternalPaths>().is_some())
6804 );
6805 assert_eq!(first_destination_exit_count.get(), 1);
6806 assert_eq!(second_destination_exit_count.get(), 0);
6807
6808 window.dispatch_event(FileDropEvent::Exited.to_platform_input(), cx);
6809 assert!(cx.active_drag.is_none());
6810 assert_eq!(first_destination_exit_count.get(), 1);
6811 assert_eq!(second_destination_exit_count.get(), 1);
6812 });
6813 assert!(
6814 update_result.is_ok(),
6815 "failed to handle drag in second destination window: {update_result:?}"
6816 );
6817 }
6818
6819 #[test]
6820 fn open_window_propagates_platform_map_error() {
6821 let cx = TestAppContext::single();
6822 cx.test_platform()
6823 .fail_next_window_map("test window mapping failed");
6824
6825 let result =
6826 cx.update(|cx| cx.open_window(WindowOptions::default(), |_, cx| cx.new(|_| EmptyView)));
6827
6828 let error = match result {
6829 Ok(_) => panic!("window mapping unexpectedly succeeded"),
6830 Err(error) => error,
6831 };
6832 assert_eq!(error.to_string(), "test window mapping failed");
6833 assert!(cx.read(|cx| cx.windows().is_empty()));
6834 }
6835
6836 struct OpensWindowOnPaint {
6837 opened: Rc<Cell<bool>>,
6838 }
6839
6840 impl Render for OpensWindowOnPaint {
6841 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
6842 let opened = self.opened.clone();
6843 div()
6844 .size_full()
6845 .child(canvas(
6846 |_, _, _| {},
6847 move |_, _, _window, cx| {
6848 if !opened.replace(true) {
6849 cx.open_window(WindowOptions::default(), |_, cx| cx.new(|_| EmptyView))
6850 .unwrap();
6851 }
6852 },
6853 ))
6854 .child(div().child("after"))
6855 }
6856 }
6857
6858 #[test]
6862 fn opening_a_window_during_draw_keeps_outer_elements_alive() {
6863 let mut cx = TestAppContext::single();
6864 let opened = Rc::new(Cell::new(false));
6865 let window = cx.add_window({
6866 let opened = opened.clone();
6867 move |_, _| OpensWindowOnPaint { opened }
6868 });
6869
6870 assert!(opened.get());
6871 assert_eq!(cx.windows().len(), 2);
6872
6873 cx.update_window(window.into(), |_, window, cx| window.draw(cx).clear())
6874 .unwrap();
6875 }
6876
6877 struct FocusLostRestoreView {
6878 parent: FocusHandle,
6879 child: FocusHandle,
6880 show_child: bool,
6881 observed_restore: Option<FocusHandle>,
6882 _subscription: Subscription,
6883 }
6884
6885 impl FocusLostRestoreView {
6886 fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
6887 Self {
6888 parent: cx.focus_handle(),
6889 child: cx.focus_handle(),
6890 show_child: true,
6891 observed_restore: None,
6892 _subscription: cx.on_focus_lost(window, |this, window, cx| {
6893 this.observed_restore = window.focus_lost_restore_target(cx);
6894 }),
6895 }
6896 }
6897 }
6898
6899 impl Render for FocusLostRestoreView {
6900 fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
6901 div()
6902 .id("parent")
6903 .track_focus(&self.parent)
6904 .when(self.show_child, |parent| {
6905 parent.child(div().id("child").track_focus(&self.child))
6906 })
6907 }
6908 }
6909
6910 #[test]
6913 fn focus_lost_restore_target_is_nearest_surviving_ancestor() {
6914 let mut cx = TestAppContext::single();
6915 let window = cx.add_window(FocusLostRestoreView::new);
6916
6917 window
6918 .update(&mut cx, |view, window, _| {
6919 window.focus(&view.child);
6920 })
6921 .unwrap();
6922
6923 cx.update_window(window.into(), |_, window, cx| {
6924 window.draw(cx).clear();
6925 assert!(
6926 window.focus_lost_restore_target(cx).is_none(),
6927 "restore target is only set while focus-lost listeners run"
6928 );
6929 })
6930 .unwrap();
6931
6932 window
6933 .update(&mut cx, |view, window, _| {
6934 assert!(view.child.is_focused(window));
6935 view.show_child = false;
6936 })
6937 .unwrap();
6938
6939 cx.update_window(window.into(), |_, window, cx| {
6940 window.draw(cx).clear();
6941 assert!(
6942 window.focus_lost_restore_target(cx).is_none(),
6943 "restore target must be cleared after focus-lost listeners return"
6944 );
6945 })
6946 .unwrap();
6947
6948 window
6949 .update(&mut cx, |view, _, _| {
6950 assert_eq!(
6951 view.observed_restore.as_ref(),
6952 Some(&view.parent),
6953 "restore target should be the parent that remained in the tree"
6954 );
6955 })
6956 .unwrap();
6957 }
6958
6959 #[gpui::test]
6960 fn test_window_reports_no_raw_handle_instead_of_panicking(cx: &mut TestAppContext) {
6961 use raw_window_handle::{HandleError, HasDisplayHandle as _, HasWindowHandle as _};
6962
6963 let window = cx.add_window(|_, _| EmptyView);
6964 window
6965 .update(cx, |_, window, _| {
6966 assert!(matches!(
6967 window.window_handle(),
6968 Err(HandleError::NotSupported)
6969 ));
6970 assert!(matches!(
6971 window.display_handle(),
6972 Err(HandleError::NotSupported)
6973 ));
6974 })
6975 .unwrap();
6976 }
6977
6978 #[gpui::test]
6982 fn test_window_visibility(cx: &mut TestAppContext) {
6983 let window = cx.add_window(|_, _| EmptyView);
6984 let observed = Rc::new(RefCell::new(Vec::new()));
6985 let _subscription = window
6986 .update(cx, {
6987 let observed = observed.clone();
6988 move |_, window, _| {
6989 assert_eq!(window.visibility(), WindowVisibility::Visible);
6990 assert!(window.is_visible());
6991 window.observe_window_visibility(move |visibility, window, _| {
6992 assert_eq!(window.visibility(), visibility);
6993 observed.borrow_mut().push(visibility);
6994 })
6995 }
6996 })
6997 .unwrap();
6998 let test_window = cx.test_window(window.into());
6999 window
7003 .update(cx, |_, window, _| {
7004 window.invalidator.set_dirty(false);
7005 window.needs_present.set(false);
7006 })
7007 .unwrap();
7008 let frame_wake_count = test_window.frame_wake_count();
7009
7010 test_window.simulate_visibility_change(WindowVisibility::Hidden);
7011 assert_eq!(*observed.borrow(), [WindowVisibility::Hidden]);
7012 window
7013 .update(cx, |_, window, _| assert!(!window.is_visible()))
7014 .unwrap();
7015
7016 test_window.simulate_visibility_change(WindowVisibility::Hidden);
7018 assert_eq!(observed.borrow().len(), 1);
7019
7020 test_window.simulate_visibility_change(WindowVisibility::Visible);
7021 assert_eq!(
7022 *observed.borrow(),
7023 [WindowVisibility::Hidden, WindowVisibility::Visible]
7024 );
7025 window
7026 .update(cx, |_, window, _| assert!(window.is_visible()))
7027 .unwrap();
7028 assert_eq!(test_window.frame_wake_count(), frame_wake_count);
7029 }
7030
7031 #[gpui::test]
7032 fn test_appearance_change_runs_after_app_update(cx: &mut TestAppContext) {
7033 let window = cx.add_window(|_, _| EmptyView);
7034 let observed_appearance = Rc::new(Cell::new(None));
7035 let _subscription = window
7036 .update(cx, {
7037 let observed_appearance = observed_appearance.clone();
7038 move |_, window, _| {
7039 window.observe_window_appearance(move |window, _| {
7040 observed_appearance.set(Some(window.appearance()));
7041 })
7042 }
7043 })
7044 .unwrap();
7045 let test_window = cx.test_window(window.into());
7046
7047 cx.update(|_| {
7048 test_window.simulate_appearance_change(WindowAppearance::Dark);
7049 assert_eq!(observed_appearance.get(), None);
7050 });
7051 cx.run_until_parked();
7052
7053 assert_eq!(observed_appearance.get(), Some(WindowAppearance::Dark));
7054 }
7055
7056 #[test]
7057 fn test_scale_factor_change_preserves_bounds_and_survives_resize() {
7058 let mut cx = TestAppContext::single();
7059 let window = cx.add_window(|_, _| EmptyView);
7060 let handle: AnyWindowHandle = window.into();
7061 let window_state = |cx: &mut TestAppContext| {
7062 cx.update_window(handle, |_, window, _| {
7063 (
7064 window.scale_factor(),
7065 window.bounds(),
7066 window.viewport_size(),
7067 )
7068 })
7069 .unwrap()
7070 };
7071
7072 let (scale_factor, mut expected_bounds, _) = window_state(&mut cx);
7073 assert_eq!(scale_factor, 2.0);
7074
7075 for (scale_factor, resized_size) in [
7076 (1.0, size(px(800.), px(600.))),
7077 (1.25, size(px(640.), px(480.))),
7078 (2.0, size(px(1024.), px(768.))),
7079 ] {
7080 cx.simulate_window_scale_factor_change(handle, scale_factor);
7081 assert_eq!(
7082 window_state(&mut cx),
7083 (scale_factor, expected_bounds, expected_bounds.size)
7084 );
7085
7086 cx.simulate_window_resize(handle, resized_size);
7087 expected_bounds.size = resized_size;
7088 assert_eq!(
7089 window_state(&mut cx),
7090 (scale_factor, expected_bounds, resized_size)
7091 );
7092 }
7093 }
7094
7095 struct RootView {
7096 explicit_size: bool,
7097 child_bounds: Rc<Cell<Bounds<Pixels>>>,
7098 }
7099
7100 impl Render for RootView {
7101 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
7102 let child_bounds = self.child_bounds.clone();
7103 let mut root = div().flex().flex_col().child(
7104 canvas(
7105 move |bounds, _, _| child_bounds.set(bounds),
7106 |_, _, _, _| {},
7107 )
7108 .size_full(),
7109 );
7110 if self.explicit_size {
7111 root = root.w(px(300.)).h(px(200.));
7112 }
7113 root
7114 }
7115 }
7116
7117 #[test]
7118 fn auto_sized_window_root_fills_the_window() {
7119 let mut cx = TestAppContext::single();
7120 let child_bounds = Rc::new(Cell::new(Bounds::default()));
7121 let window = cx.add_window({
7122 let child_bounds = child_bounds.clone();
7123 move |_, _| RootView {
7124 explicit_size: false,
7125 child_bounds,
7126 }
7127 });
7128
7129 let viewport_size = cx
7130 .update_window(window.into(), |_, window, cx| {
7131 window.draw(cx).clear();
7132 window.viewport_size()
7133 })
7134 .unwrap();
7135
7136 assert_eq!(child_bounds.get().size, viewport_size);
7137 }
7138
7139 #[test]
7140 fn explicitly_sized_window_root_keeps_its_size() {
7141 let mut cx = TestAppContext::single();
7142 let child_bounds = Rc::new(Cell::new(Bounds::default()));
7143 let window = cx.add_window({
7144 let child_bounds = child_bounds.clone();
7145 move |_, _| RootView {
7146 explicit_size: true,
7147 child_bounds,
7148 }
7149 });
7150
7151 cx.update_window(window.into(), |_, window, cx| {
7152 window.draw(cx).clear();
7153 })
7154 .unwrap();
7155
7156 assert_eq!(child_bounds.get().size, size(px(300.), px(200.)));
7157 }
7158
7159 fn scaled(value: f32) -> ScaledPixels {
7160 ScaledPixels(value)
7161 }
7162
7163 #[test]
7164 fn border_only_quad_strips_cover_asymmetric_borders_and_corners() {
7165 let bounds = Bounds::new(
7166 point(scaled(0.), scaled(0.)),
7167 size(scaled(100.), scaled(80.)),
7168 );
7169 let widths = Edges {
7170 top: scaled(6.),
7171 right: scaled(4.),
7172 bottom: scaled(8.),
7173 left: scaled(2.),
7174 };
7175 let radii = Corners {
7176 top_left: scaled(10.),
7177 top_right: scaled(12.),
7178 bottom_right: scaled(16.),
7179 bottom_left: scaled(14.),
7180 };
7181
7182 let strips = border_only_quad_strips(bounds, widths, radii).unwrap();
7183 assert_eq!(
7184 strips,
7185 [
7186 Bounds::from_corners(
7187 point(scaled(0.), scaled(0.)),
7188 point(scaled(100.), scaled(13.)),
7189 ),
7190 Bounds::from_corners(
7191 point(scaled(0.), scaled(63.)),
7192 point(scaled(100.), scaled(80.)),
7193 ),
7194 Bounds::from_corners(
7195 point(scaled(0.), scaled(13.)),
7196 point(scaled(3.), scaled(63.)),
7197 ),
7198 Bounds::from_corners(
7199 point(scaled(95.), scaled(13.)),
7200 point(scaled(100.), scaled(63.)),
7201 ),
7202 ]
7203 );
7204 }
7205
7206 #[test]
7207 fn border_only_quad_keeps_one_primitive_when_interior_is_too_small() {
7208 let bounds = Bounds::new(
7209 point(scaled(0.), scaled(0.)),
7210 size(scaled(10.), scaled(10.)),
7211 );
7212 let widths = Edges {
7213 top: scaled(5.),
7214 right: scaled(5.),
7215 bottom: scaled(5.),
7216 left: scaled(5.),
7217 };
7218
7219 assert!(border_only_quad_strips(bounds, widths, Corners::default()).is_none());
7220 }
7221
7222 struct BorderOnlyQuadView;
7223
7224 impl Render for BorderOnlyQuadView {
7225 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
7226 canvas(
7227 |_, _, _| {},
7228 |bounds, _, window, _| {
7229 window.paint_quad(outline(bounds, hsla(0., 0., 1., 1.), BorderStyle::Solid));
7230 },
7231 )
7232 .size(px(100.))
7233 }
7234 }
7235
7236 #[test]
7237 fn border_only_quad_emits_four_clipped_primitives() {
7238 let mut cx = TestAppContext::single();
7239 let window = cx.add_window(|_, _| BorderOnlyQuadView);
7240
7241 let primitive_count = cx
7242 .update_window(window.into(), |_, window, cx| {
7243 window.draw(cx).clear();
7244 window.rendered_frame.scene.quads.len()
7245 })
7246 .unwrap();
7247
7248 assert_eq!(primitive_count, 4);
7249 }
7250
7251 #[test]
7252 fn resource_profile_gpu_budget_reaches_the_platform() {
7253 let cx = TestAppContext::single();
7254
7255 let budget = cx.test_platform().gpu_resource_budget.lock().clone();
7256 assert_eq!(budget.instance_buffer_initial_size, 2 * 1024 * 1024);
7257 assert_eq!(budget.instance_buffer_max_size, 256 * 1024 * 1024);
7258 }
7259
7260 #[test]
7261 fn window_attention_is_forwarded_to_the_platform_window() {
7262 let mut cx = TestAppContext::single();
7263 let window = cx.add_window(|_, _| BorderOnlyQuadView);
7264 let window = AnyWindowHandle::from(window);
7265
7266 cx.update_window(window, |_, window, _| window.request_attention())
7267 .unwrap();
7268
7269 assert_eq!(cx.test_window(window).0.lock().attention_requests, 1);
7270 }
7271
7272 #[test]
7273 fn quit_mode_explicit_keeps_app_alive_after_last_window_closed() {
7274 let mut cx = TestAppContext::single();
7275 cx.update(|cx| cx.set_quit_mode(QuitMode::Explicit));
7276 assert_eq!(
7277 *cx.test_platform().last_quit_mode.lock(),
7278 Some(QuitMode::Explicit)
7279 );
7280 let window = cx.add_window(|_, _| BorderOnlyQuadView);
7281 let window = AnyWindowHandle::from(window);
7282
7283 cx.update_window(window, |_, window, _| window.remove_window())
7284 .unwrap();
7285
7286 assert!(!*cx.test_platform().did_quit.lock());
7287 }
7288
7289 #[test]
7290 fn quit_mode_last_window_closed_quits_after_last_window_closed() {
7291 let mut cx = TestAppContext::single();
7292 cx.update(|cx| cx.set_quit_mode(QuitMode::LastWindowClosed));
7293 let window = cx.add_window(|_, _| BorderOnlyQuadView);
7294 let window = AnyWindowHandle::from(window);
7295
7296 cx.update_window(window, |_, window, _| window.remove_window())
7297 .unwrap();
7298
7299 assert!(*cx.test_platform().did_quit.lock());
7300 }
7301
7302 #[test]
7303 fn quit_mode_runtime_change_applies_to_the_next_window_close() {
7304 let mut cx = TestAppContext::single();
7305 cx.update(|cx| cx.set_quit_mode(QuitMode::Explicit));
7306 let window = AnyWindowHandle::from(cx.add_window(|_, _| BorderOnlyQuadView));
7307
7308 cx.update(|cx| cx.set_quit_mode(QuitMode::LastWindowClosed));
7309 assert_eq!(
7310 *cx.test_platform().last_quit_mode.lock(),
7311 Some(QuitMode::LastWindowClosed)
7312 );
7313 cx.update_window(window, |_, window, _| window.remove_window())
7314 .unwrap();
7315
7316 assert!(*cx.test_platform().did_quit.lock());
7317 }
7318
7319 #[test]
7320 fn quit_mode_last_window_closed_waits_for_every_window() {
7321 let mut cx = TestAppContext::single();
7322 cx.update(|cx| cx.set_quit_mode(QuitMode::LastWindowClosed));
7323 let first = AnyWindowHandle::from(cx.add_window(|_, _| BorderOnlyQuadView));
7324 let second = AnyWindowHandle::from(cx.add_window(|_, _| BorderOnlyQuadView));
7325
7326 cx.update_window(first, |_, window, _| window.remove_window())
7327 .unwrap();
7328 assert!(!*cx.test_platform().did_quit.lock());
7329
7330 cx.update_window(second, |_, window, _| window.remove_window())
7331 .unwrap();
7332 assert!(*cx.test_platform().did_quit.lock());
7333 }
7334
7335 #[test]
7336 fn quit_mode_default_follows_platform_convention() {
7337 let mut cx = TestAppContext::single();
7338 let window = cx.add_window(|_, _| BorderOnlyQuadView);
7340 let window = AnyWindowHandle::from(window);
7341
7342 cx.update_window(window, |_, window, _| window.remove_window())
7343 .unwrap();
7344
7345 let expected = cfg!(not(target_os = "macos"));
7348 assert_eq!(*cx.test_platform().did_quit.lock(), expected);
7349 }
7350}