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, IsZero, KeyBinding, KeyContext, KeyDownEvent, KeyEvent, Keystroke,
10 KeystrokeEvent, LayoutId, LineLayoutIndex, Modifiers, ModifiersChangedEvent, MonochromeSprite,
11 MouseButton, MouseEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels, PlatformAtlas,
12 PlatformDisplay, PlatformInput, PlatformInputHandler, PlatformWindow, Point, PolychromeSprite,
13 ProgressBarState, PromptButton, PromptLevel, Quad, Render, RenderGlyphParams, RenderImage,
14 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, point, prelude::*, px, rems, size,
21 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::FutureExt;
29use futures::channel::oneshot;
30#[cfg(feature = "input-latency-histogram")]
31use hdrhistogram::Histogram;
32use itertools::FoldWhile::{Continue, Done};
33use itertools::Itertools;
34use parking_lot::RwLock;
35use raw_window_handle::{HandleError, HasDisplayHandle, HasWindowHandle};
36use refineable::Refineable;
37use slotmap::SlotMap;
38use smallvec::SmallVec;
39use std::{
40 any::{Any, TypeId},
41 borrow::Cow,
42 cell::{Cell, RefCell},
43 cmp,
44 fmt::{Debug, Display},
45 hash::{Hash, Hasher},
46 marker::PhantomData,
47 mem,
48 ops::{DerefMut, Range},
49 rc::Rc,
50 sync::{
51 Arc, Weak,
52 atomic::{AtomicBool, AtomicUsize, Ordering::SeqCst},
53 },
54 time::{Duration, Instant},
55};
56use util::post_inc;
57use util::{ResultExt, measure};
58use uuid::Uuid;
59
60pub(crate) mod a11y;
61mod prompts;
62
63use crate::util::{
64 atomic_incr_if_not_zero, ceil_to_device_pixel, floor_to_device_pixel, round_half_toward_zero,
65 round_half_toward_zero_f64, round_stroke_to_device_pixel, round_to_device_pixel,
66};
67use a11y::{A11y, ROOT_NODE_ID};
68pub use prompts::*;
69
70#[doc(hidden)]
71pub const DEFAULT_WINDOW_SIZE: Size<Pixels> = size(px(1536.), px(864.));
72
73#[derive(Default, Copy, Clone, Debug, Eq, PartialEq)]
75pub enum DispatchPhase {
76 #[default]
81 Bubble,
82 Capture,
88}
89
90impl DispatchPhase {
91 #[inline]
93 pub fn bubble(self) -> bool {
94 self == DispatchPhase::Bubble
95 }
96
97 #[inline]
99 pub fn capture(self) -> bool {
100 self == DispatchPhase::Capture
101 }
102}
103
104struct WindowInvalidatorInner {
105 pub dirty: bool,
106 pub draw_phase: DrawPhase,
107 pub dirty_views: FxHashSet<EntityId>,
108 pub update_count: usize,
109}
110
111#[derive(Clone)]
112pub(crate) struct WindowInvalidator {
113 inner: Rc<RefCell<WindowInvalidatorInner>>,
114}
115
116impl WindowInvalidator {
117 pub fn new() -> Self {
118 WindowInvalidator {
119 inner: Rc::new(RefCell::new(WindowInvalidatorInner {
120 dirty: true,
121 draw_phase: DrawPhase::None,
122 dirty_views: FxHashSet::default(),
123 update_count: 0,
124 })),
125 }
126 }
127
128 pub fn invalidate_view(&self, entity: EntityId, cx: &mut App) -> bool {
129 let mut inner = self.inner.borrow_mut();
130 inner.update_count += 1;
131 inner.dirty_views.insert(entity);
132 if inner.draw_phase == DrawPhase::None {
133 inner.dirty = true;
134 cx.push_effect(Effect::Notify { emitter: entity });
135 true
136 } else {
137 false
138 }
139 }
140
141 pub fn is_dirty(&self) -> bool {
142 self.inner.borrow().dirty
143 }
144
145 pub fn set_dirty(&self, dirty: bool) {
146 let mut inner = self.inner.borrow_mut();
147 inner.dirty = dirty;
148 if dirty {
149 inner.update_count += 1;
150 }
151 }
152
153 pub fn set_phase(&self, phase: DrawPhase) {
154 self.inner.borrow_mut().draw_phase = phase
155 }
156
157 pub fn update_count(&self) -> usize {
158 self.inner.borrow().update_count
159 }
160
161 pub fn take_views(&self) -> FxHashSet<EntityId> {
162 mem::take(&mut self.inner.borrow_mut().dirty_views)
163 }
164
165 pub fn replace_views(&self, views: FxHashSet<EntityId>) {
166 self.inner.borrow_mut().dirty_views = views;
167 }
168
169 pub fn not_drawing(&self) -> bool {
170 self.inner.borrow().draw_phase == DrawPhase::None
171 }
172
173 #[track_caller]
174 pub fn debug_assert_paint(&self) {
175 debug_assert!(
176 matches!(self.inner.borrow().draw_phase, DrawPhase::Paint),
177 "this method can only be called during paint"
178 );
179 }
180
181 #[track_caller]
182 pub fn debug_assert_prepaint(&self) {
183 debug_assert!(
184 matches!(self.inner.borrow().draw_phase, DrawPhase::Prepaint),
185 "this method can only be called during request_layout, or prepaint"
186 );
187 }
188
189 #[track_caller]
190 pub fn debug_assert_paint_or_prepaint(&self) {
191 debug_assert!(
192 matches!(
193 self.inner.borrow().draw_phase,
194 DrawPhase::Paint | DrawPhase::Prepaint
195 ),
196 "this method can only be called during request_layout, prepaint, or paint"
197 );
198 }
199}
200
201type AnyObserver = Box<dyn FnMut(&mut Window, &mut App) -> bool + 'static>;
202
203pub(crate) type AnyWindowFocusListener =
204 Box<dyn FnMut(&WindowFocusEvent, &mut Window, &mut App) -> bool + 'static>;
205
206pub(crate) struct WindowFocusEvent {
207 pub(crate) previous_focus_path: SmallVec<[FocusId; 8]>,
208 pub(crate) current_focus_path: SmallVec<[FocusId; 8]>,
209}
210
211impl WindowFocusEvent {
212 pub fn is_focus_in(&self, focus_id: FocusId) -> bool {
213 !self.previous_focus_path.contains(&focus_id) && self.current_focus_path.contains(&focus_id)
214 }
215
216 pub fn is_focus_out(&self, focus_id: FocusId) -> bool {
217 self.previous_focus_path.contains(&focus_id) && !self.current_focus_path.contains(&focus_id)
218 }
219}
220
221pub struct FocusOutEvent {
223 pub blurred: WeakFocusHandle,
225}
226
227slotmap::new_key_type! {
228 pub struct FocusId;
230}
231
232pub(crate) static ELEMENT_ARENA_SIZE: std::sync::atomic::AtomicUsize =
235 std::sync::atomic::AtomicUsize::new(1024 * 1024);
236
237thread_local! {
238 pub(crate) static ELEMENT_ARENA: RefCell<Arena> = RefCell::new(
239 Arena::new(ELEMENT_ARENA_SIZE.load(std::sync::atomic::Ordering::Relaxed))
240 );
241}
242
243struct ElementArenaScope;
245
246impl ElementArenaScope {
247 fn enter() -> Self {
248 ELEMENT_ARENA.with_borrow_mut(Arena::begin_scope);
249 Self
250 }
251}
252
253impl Drop for ElementArenaScope {
254 fn drop(&mut self) {
255 ELEMENT_ARENA.with_borrow_mut(Arena::end_scope);
256 }
257}
258
259fn draw_in_progress() -> bool {
268 ELEMENT_ARENA.with(|arena| {
269 arena
270 .try_borrow()
271 .map(|arena| arena.has_active_scope())
272 .unwrap_or(true)
273 })
274}
275
276#[must_use]
278pub struct ArenaClearNeeded;
279
280impl ArenaClearNeeded {
281 pub fn clear(self) {
283 ELEMENT_ARENA.with_borrow_mut(|element_arena| {
284 element_arena.clear();
285 });
286 }
287}
288
289pub(crate) type FocusMap = RwLock<SlotMap<FocusId, FocusRef>>;
290pub(crate) struct FocusRef {
291 pub(crate) ref_count: AtomicUsize,
292 pub(crate) tab_index: isize,
293 pub(crate) tab_stop: bool,
294}
295
296impl FocusId {
297 pub fn is_focused(&self, window: &Window) -> bool {
299 window.focus == Some(*self)
300 }
301
302 pub fn contains_focused(&self, window: &Window, cx: &App) -> bool {
305 window
306 .focused(cx)
307 .is_some_and(|focused| self.contains(focused.id, window))
308 }
309
310 pub fn within_focused(&self, window: &Window, cx: &App) -> bool {
313 let focused = window.focused(cx);
314 focused.is_some_and(|focused| focused.id.contains(*self, window))
315 }
316
317 pub(crate) fn contains(&self, other: Self, window: &Window) -> bool {
319 window
320 .rendered_frame
321 .dispatch_tree
322 .focus_contains(*self, other)
323 }
324}
325
326pub struct FocusHandle {
328 pub(crate) id: FocusId,
329 handles: Arc<FocusMap>,
330 pub tab_index: isize,
332 pub tab_stop: bool,
334}
335
336impl std::fmt::Debug for FocusHandle {
337 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
338 f.write_fmt(format_args!("FocusHandle({:?})", self.id))
339 }
340}
341
342impl FocusHandle {
343 pub(crate) fn new(handles: &Arc<FocusMap>) -> Self {
344 let id = handles.write().insert(FocusRef {
345 ref_count: AtomicUsize::new(1),
346 tab_index: 0,
347 tab_stop: false,
348 });
349
350 Self {
351 id,
352 tab_index: 0,
353 tab_stop: false,
354 handles: handles.clone(),
355 }
356 }
357
358 pub(crate) fn for_id(id: FocusId, handles: &Arc<FocusMap>) -> Option<Self> {
359 let lock = handles.read();
360 let focus = lock.get(id)?;
361 if atomic_incr_if_not_zero(&focus.ref_count) == 0 {
362 return None;
363 }
364 Some(Self {
365 id,
366 tab_index: focus.tab_index,
367 tab_stop: focus.tab_stop,
368 handles: handles.clone(),
369 })
370 }
371
372 pub fn tab_index(mut self, index: isize) -> Self {
374 self.tab_index = index;
375 if let Some(focus) = self.handles.write().get_mut(self.id) {
376 focus.tab_index = index;
377 }
378 self
379 }
380
381 pub fn tab_stop(mut self, tab_stop: bool) -> Self {
385 self.tab_stop = tab_stop;
386 if let Some(focus) = self.handles.write().get_mut(self.id) {
387 focus.tab_stop = tab_stop;
388 }
389 self
390 }
391
392 pub fn downgrade(&self) -> WeakFocusHandle {
394 WeakFocusHandle {
395 id: self.id,
396 handles: Arc::downgrade(&self.handles),
397 }
398 }
399
400 pub fn focus(&self, window: &mut Window) {
402 window.focus(self)
403 }
404
405 pub fn is_focused(&self, window: &Window) -> bool {
407 self.id.is_focused(window)
408 }
409
410 pub fn contains_focused(&self, window: &Window, cx: &App) -> bool {
413 self.id.contains_focused(window, cx)
414 }
415
416 pub fn within_focused(&self, window: &Window, cx: &mut App) -> bool {
419 self.id.within_focused(window, cx)
420 }
421
422 pub fn contains(&self, other: &Self, window: &Window) -> bool {
424 self.id.contains(other.id, window)
425 }
426
427 pub fn dispatch_action(&self, action: &dyn Action, window: &mut Window, cx: &mut App) {
429 if let Some(node_id) = window
430 .rendered_frame
431 .dispatch_tree
432 .focusable_node_id(self.id)
433 {
434 window.dispatch_action_on_node(node_id, action, cx)
435 }
436 }
437}
438
439impl Clone for FocusHandle {
440 fn clone(&self) -> Self {
441 Self::for_id(self.id, &self.handles).unwrap()
442 }
443}
444
445impl PartialEq for FocusHandle {
446 fn eq(&self, other: &Self) -> bool {
447 self.id == other.id
448 }
449}
450
451impl Eq for FocusHandle {}
452
453impl Drop for FocusHandle {
454 fn drop(&mut self) {
455 self.handles
456 .read()
457 .get(self.id)
458 .unwrap()
459 .ref_count
460 .fetch_sub(1, SeqCst);
461 }
462}
463
464#[derive(Clone, Debug)]
466pub struct WeakFocusHandle {
467 pub(crate) id: FocusId,
468 pub(crate) handles: Weak<FocusMap>,
469}
470
471impl WeakFocusHandle {
472 pub fn upgrade(&self) -> Option<FocusHandle> {
474 let handles = self.handles.upgrade()?;
475 FocusHandle::for_id(self.id, &handles)
476 }
477}
478
479impl PartialEq for WeakFocusHandle {
480 fn eq(&self, other: &WeakFocusHandle) -> bool {
481 self.id == other.id
482 }
483}
484
485impl Eq for WeakFocusHandle {}
486
487impl PartialEq<FocusHandle> for WeakFocusHandle {
488 fn eq(&self, other: &FocusHandle) -> bool {
489 self.id == other.id
490 }
491}
492
493impl PartialEq<WeakFocusHandle> for FocusHandle {
494 fn eq(&self, other: &WeakFocusHandle) -> bool {
495 self.id == other.id
496 }
497}
498
499pub trait Focusable: 'static {
502 fn focus_handle(&self, cx: &App) -> FocusHandle;
504}
505
506impl<V: Focusable> Focusable for Entity<V> {
507 fn focus_handle(&self, cx: &App) -> FocusHandle {
508 self.read(cx).focus_handle(cx)
509 }
510}
511
512pub trait ManagedView: Focusable + EventEmitter<DismissEvent> + Render {}
515
516impl<M: Focusable + EventEmitter<DismissEvent> + Render> ManagedView for M {}
517
518pub struct DismissEvent;
520
521type FrameCallback = Box<dyn FnOnce(&mut Window, &mut App)>;
522
523pub(crate) type AnyMouseListener =
524 Box<dyn FnMut(&dyn Any, DispatchPhase, &mut Window, &mut App) + 'static>;
525
526#[derive(Clone)]
527pub(crate) struct CursorStyleRequest {
528 pub(crate) hitbox_id: Option<HitboxId>,
529 pub(crate) style: CursorStyle,
530}
531
532#[derive(Default, Eq, PartialEq)]
533pub(crate) struct HitTest {
534 pub(crate) ids: SmallVec<[HitboxId; 8]>,
535 pub(crate) hover_hitbox_count: usize,
536}
537
538#[derive(Clone, Copy, Debug, Eq, PartialEq)]
540pub enum WindowControlArea {
541 Drag,
543 Close,
545 Max,
547 Min,
549}
550
551#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
553pub struct HitboxId(u64);
554
555impl HitboxId {
556 pub fn is_hovered(self, window: &Window) -> bool {
562 if window.captured_hitbox == Some(self) {
564 return true;
565 }
566 if window.last_input_was_keyboard() {
567 return false;
568 }
569 self.hit_test(window)
570 }
571
572 pub(crate) fn is_hovered_ignoring_last_input(self, window: &Window) -> bool {
577 if window.captured_hitbox == Some(self) {
579 return true;
580 }
581 self.hit_test(window)
582 }
583
584 fn hit_test(self, window: &Window) -> bool {
585 let hit_test = &window.mouse_hit_test;
586 for id in hit_test.ids.iter().take(hit_test.hover_hitbox_count) {
587 if self == *id {
588 return true;
589 }
590 }
591 false
592 }
593
594 pub fn should_handle_scroll(self, window: &Window) -> bool {
599 window.mouse_hit_test.ids.contains(&self)
600 }
601
602 fn next(mut self) -> HitboxId {
603 HitboxId(self.0.wrapping_add(1))
604 }
605}
606
607#[derive(Clone, Debug, Deref)]
610pub struct Hitbox {
611 pub id: HitboxId,
613 #[deref]
615 pub bounds: Bounds<Pixels>,
616 pub content_mask: ContentMask<Pixels>,
618 pub behavior: HitboxBehavior,
620}
621
622impl Hitbox {
623 pub fn is_hovered(&self, window: &Window) -> bool {
638 self.id.is_hovered(window)
639 }
640
641 pub fn should_handle_scroll(&self, window: &Window) -> bool {
648 self.id.should_handle_scroll(window)
649 }
650}
651
652#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
654pub enum HitboxBehavior {
655 #[default]
657 Normal,
658
659 BlockMouse,
681
682 BlockMouseExceptScroll,
709}
710
711#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
713pub struct TooltipId(usize);
714
715impl TooltipId {
716 pub fn is_hovered(&self, window: &Window) -> bool {
718 window
719 .tooltip_bounds
720 .as_ref()
721 .is_some_and(|tooltip_bounds| {
722 tooltip_bounds.id == *self
723 && tooltip_bounds.bounds.contains(&window.mouse_position())
724 })
725 }
726}
727
728pub(crate) struct TooltipBounds {
729 id: TooltipId,
730 bounds: Bounds<Pixels>,
731}
732
733#[derive(Clone)]
734pub(crate) struct TooltipRequest {
735 id: TooltipId,
736 tooltip: AnyTooltip,
737}
738
739pub(crate) struct DeferredDraw {
740 current_view: EntityId,
741 priority: usize,
742 parent_node: DispatchNodeId,
743 element_id_stack: SmallVec<[ElementId; 32]>,
744 text_style_stack: SmallVec<[TextStyleRefinement; 4]>,
745 element: Option<AnyElement>,
746 absolute_offset: Point<Pixels>,
747 prepaint_range: Range<PrepaintStateIndex>,
748 paint_range: Range<PaintIndex>,
749}
750
751pub(crate) struct Frame {
752 pub(crate) focus: Option<FocusId>,
753 pub(crate) window_active: bool,
754 pub(crate) element_states: FxHashMap<(GlobalElementId, TypeId), ElementStateBox>,
755 accessed_element_states: Vec<(GlobalElementId, TypeId)>,
756 pub(crate) mouse_listeners: Vec<Option<AnyMouseListener>>,
757 pub(crate) dispatch_tree: DispatchTree,
758 pub(crate) scene: Scene,
759 pub(crate) hitboxes: Vec<Hitbox>,
760 pub(crate) window_control_hitboxes: Vec<(WindowControlArea, Hitbox)>,
761 pub(crate) deferred_draws: Vec<DeferredDraw>,
762 pub(crate) input_handlers: Vec<Option<PlatformInputHandler>>,
763 pub(crate) tooltip_requests: Vec<Option<TooltipRequest>>,
764 pub(crate) cursor_styles: Vec<CursorStyleRequest>,
765 #[cfg(any(test, feature = "test-support"))]
766 pub(crate) debug_bounds: FxHashMap<String, Bounds<Pixels>>,
767 #[cfg(any(feature = "inspector", debug_assertions))]
768 pub(crate) next_inspector_instance_ids: FxHashMap<Rc<crate::InspectorElementPath>, usize>,
769 #[cfg(any(feature = "inspector", debug_assertions))]
770 pub(crate) inspector_hitboxes: FxHashMap<HitboxId, crate::InspectorElementId>,
771 pub(crate) tab_stops: TabStopMap,
772}
773
774#[derive(Clone, Default)]
775pub(crate) struct PrepaintStateIndex {
776 hitboxes_index: usize,
777 tooltips_index: usize,
778 deferred_draws_index: usize,
779 dispatch_tree_index: usize,
780 accessed_element_states_index: usize,
781 line_layout_index: LineLayoutIndex,
782}
783
784#[derive(Clone, Default)]
785pub(crate) struct PaintIndex {
786 scene_index: usize,
787 mouse_listeners_index: usize,
788 input_handlers_index: usize,
789 cursor_styles_index: usize,
790 accessed_element_states_index: usize,
791 tab_handle_index: usize,
792 line_layout_index: LineLayoutIndex,
793}
794
795impl Frame {
796 pub(crate) fn new(dispatch_tree: DispatchTree) -> Self {
797 Frame {
798 focus: None,
799 window_active: false,
800 element_states: FxHashMap::default(),
801 accessed_element_states: Vec::new(),
802 mouse_listeners: Vec::new(),
803 dispatch_tree,
804 scene: Scene::default(),
805 hitboxes: Vec::new(),
806 window_control_hitboxes: Vec::new(),
807 deferred_draws: Vec::new(),
808 input_handlers: Vec::new(),
809 tooltip_requests: Vec::new(),
810 cursor_styles: Vec::new(),
811
812 #[cfg(any(test, feature = "test-support"))]
813 debug_bounds: FxHashMap::default(),
814
815 #[cfg(any(feature = "inspector", debug_assertions))]
816 next_inspector_instance_ids: FxHashMap::default(),
817
818 #[cfg(any(feature = "inspector", debug_assertions))]
819 inspector_hitboxes: FxHashMap::default(),
820 tab_stops: TabStopMap::default(),
821 }
822 }
823
824 pub(crate) fn clear(&mut self) {
825 self.element_states.clear();
826 self.accessed_element_states.clear();
827 self.mouse_listeners.clear();
828 self.dispatch_tree.clear();
829 self.scene.clear();
830 self.input_handlers.clear();
831 self.tooltip_requests.clear();
832 self.cursor_styles.clear();
833 self.hitboxes.clear();
834 self.window_control_hitboxes.clear();
835 self.deferred_draws.clear();
836 self.tab_stops.clear();
837 self.focus = None;
838
839 #[cfg(any(feature = "inspector", debug_assertions))]
840 {
841 self.next_inspector_instance_ids.clear();
842 self.inspector_hitboxes.clear();
843 }
844 }
845
846 pub(crate) fn cursor_style(&self, window: &Window) -> Option<CursorStyle> {
847 self.cursor_styles
848 .iter()
849 .rev()
850 .fold_while(None, |style, request| match request.hitbox_id {
851 None => Done(Some(request.style)),
852 Some(hitbox_id) => Continue(style.or_else(|| {
853 hitbox_id
854 .is_hovered_ignoring_last_input(window)
855 .then_some(request.style)
856 })),
857 })
858 .into_inner()
859 }
860
861 pub(crate) fn hit_test(&self, position: Point<Pixels>) -> HitTest {
862 let mut set_hover_hitbox_count = false;
863 let mut hit_test = HitTest::default();
864 for hitbox in self.hitboxes.iter().rev() {
865 let bounds = hitbox.bounds.intersect(&hitbox.content_mask.bounds);
866 if bounds.contains(&position) {
867 hit_test.ids.push(hitbox.id);
868 if !set_hover_hitbox_count
869 && hitbox.behavior == HitboxBehavior::BlockMouseExceptScroll
870 {
871 hit_test.hover_hitbox_count = hit_test.ids.len();
872 set_hover_hitbox_count = true;
873 }
874 if hitbox.behavior == HitboxBehavior::BlockMouse {
875 break;
876 }
877 }
878 }
879 if !set_hover_hitbox_count {
880 hit_test.hover_hitbox_count = hit_test.ids.len();
881 }
882 hit_test
883 }
884
885 pub(crate) fn focus_path(&self) -> SmallVec<[FocusId; 8]> {
886 self.focus
887 .map(|focus_id| self.dispatch_tree.focus_path(focus_id))
888 .unwrap_or_default()
889 }
890
891 pub(crate) fn finish(&mut self, prev_frame: &mut Self) {
892 for element_state_key in &self.accessed_element_states {
893 if let Some((element_state_key, element_state)) =
894 prev_frame.element_states.remove_entry(element_state_key)
895 {
896 self.element_states.insert(element_state_key, element_state);
897 }
898 }
899
900 self.scene.finish();
901 }
902}
903
904#[derive(Clone, Debug)]
907pub(crate) struct InputRateTracker {
908 timestamps: Vec<Instant>,
909 window: Duration,
910 inputs_per_second: u32,
911 sustain_until: Instant,
912 sustain_duration: Duration,
913}
914
915impl Default for InputRateTracker {
916 fn default() -> Self {
917 Self {
918 timestamps: Vec::new(),
919 window: Duration::from_millis(100),
920 inputs_per_second: 60,
921 sustain_until: Instant::now(),
922 sustain_duration: Duration::from_secs(1),
923 }
924 }
925}
926
927impl InputRateTracker {
928 pub fn record_input(&mut self) {
929 let now = Instant::now();
930 self.timestamps.push(now);
931 self.timestamps
932 .retain(|&t| now.duration_since(t) <= self.window);
933 let min_events = self.inputs_per_second as u128 * self.window.as_millis() / 1000;
934 if self.timestamps.len() as u128 >= min_events {
935 self.sustain_until = now + self.sustain_duration;
936 }
937 }
938
939 pub fn is_high_rate(&self) -> bool {
940 Instant::now() < self.sustain_until
941 }
942}
943
944fn frame_throttle_interval(
945 force_render: bool,
946 require_presentation: bool,
947 has_next_frame_callbacks: bool,
948 is_active: bool,
949 has_high_rate_input: bool,
950 is_thermally_constrained: bool,
951 inactive_frame_interval: Option<Duration>,
952) -> Option<Duration> {
953 if require_presentation || (!force_render && !has_next_frame_callbacks) {
954 None
955 } else if !is_active && !has_high_rate_input {
956 inactive_frame_interval
957 } else if is_thermally_constrained {
958 Some(Duration::from_micros(16667))
959 } else {
960 None
961 }
962}
963
964#[cfg(feature = "input-latency-histogram")]
966pub struct InputLatencySnapshot {
967 pub latency_histogram: Histogram<u64>,
969 pub events_per_frame_histogram: Histogram<u64>,
971 pub mid_draw_events_dropped: u64,
973}
974
975#[cfg(feature = "input-latency-histogram")]
976struct InputLatencyTracker {
977 first_input_at: Option<Instant>,
978 pending_input_count: u64,
979 latency_histogram: Histogram<u64>,
980 events_per_frame_histogram: Histogram<u64>,
981 mid_draw_events_dropped: u64,
982}
983
984#[cfg(feature = "input-latency-histogram")]
985impl InputLatencyTracker {
986 fn new() -> Result<Self> {
987 Ok(Self {
988 first_input_at: None,
989 pending_input_count: 0,
990 latency_histogram: Histogram::new(3)
991 .map_err(|error| anyhow!("failed to create input latency histogram: {error}"))?,
992 events_per_frame_histogram: Histogram::new(3)
993 .map_err(|error| anyhow!("failed to create events per frame histogram: {error}"))?,
994 mid_draw_events_dropped: 0,
995 })
996 }
997
998 fn record_input(&mut self, dispatch_time: Instant) {
999 self.first_input_at.get_or_insert(dispatch_time);
1000 self.pending_input_count += 1;
1001 }
1002
1003 fn record_mid_draw_input(&mut self) {
1004 self.mid_draw_events_dropped += 1;
1005 }
1006
1007 fn record_frame_presented(&mut self) {
1008 if let Some(first_input_at) = self.first_input_at.take() {
1009 self.latency_histogram
1010 .record(first_input_at.elapsed().as_nanos() as u64)
1011 .ok();
1012 }
1013
1014 if self.pending_input_count > 0 {
1015 self.events_per_frame_histogram
1016 .record(self.pending_input_count)
1017 .ok();
1018 self.pending_input_count = 0;
1019 }
1020 }
1021
1022 fn snapshot(&self) -> InputLatencySnapshot {
1023 InputLatencySnapshot {
1024 latency_histogram: self.latency_histogram.clone(),
1025 events_per_frame_histogram: self.events_per_frame_histogram.clone(),
1026 mid_draw_events_dropped: self.mid_draw_events_dropped,
1027 }
1028 }
1029}
1030
1031pub struct Window {
1033 pub(crate) handle: AnyWindowHandle,
1034 pub(crate) invalidator: WindowInvalidator,
1035 pub(crate) removed: bool,
1036 pub(crate) platform_window: Box<dyn PlatformWindow>,
1037 pub(crate) a11y: A11y,
1038 display_id: Option<DisplayId>,
1039 sprite_atlas: Arc<dyn PlatformAtlas>,
1040 text_system: Arc<WindowTextSystem>,
1041 rem_size: Pixels,
1042 rem_size_override_stack: SmallVec<[Pixels; 8]>,
1047 pub(crate) viewport_size: Size<Pixels>,
1048 layout_engine: Option<TaffyLayoutEngine>,
1049 pub(crate) root: Option<AnyView>,
1050 pub(crate) element_id_stack: SmallVec<[ElementId; 32]>,
1051 pub(crate) text_style_stack: SmallVec<[TextStyleRefinement; 4]>,
1052 pub(crate) rendered_entity_stack: SmallVec<[EntityId; 16]>,
1053 pub(crate) element_offset_stack: SmallVec<[Point<Pixels>; 16]>,
1054 pub(crate) element_opacity: f32,
1055 pub(crate) content_mask_stack: SmallVec<[ContentMask<Pixels>; 16]>,
1056 pub(crate) requested_autoscroll: Option<Bounds<Pixels>>,
1057 pub(crate) image_cache_stack: SmallVec<[AnyImageCache; 4]>,
1058 pub(crate) rendered_frame: Frame,
1059 pub(crate) next_frame: Frame,
1060 next_hitbox_id: HitboxId,
1061 pub(crate) next_tooltip_id: TooltipId,
1062 pub(crate) tooltip_bounds: Option<TooltipBounds>,
1063 pub(crate) next_frame_callbacks: Rc<RefCell<Vec<FrameCallback>>>,
1064 pub(crate) dirty_views: FxHashSet<EntityId>,
1065 focus_listeners: SubscriberSet<(), AnyWindowFocusListener>,
1066 pub(crate) focus_lost_listeners: SubscriberSet<(), AnyObserver>,
1067 default_prevented: bool,
1068 mouse_position: Point<Pixels>,
1069 mouse_hit_test: HitTest,
1070 modifiers: Modifiers,
1071 capslock: Capslock,
1072 scale_factor: f32,
1073 pub(crate) bounds_observers: SubscriberSet<(), AnyObserver>,
1074 appearance: WindowAppearance,
1075 pub(crate) appearance_observers: SubscriberSet<(), AnyObserver>,
1076 active: Rc<Cell<bool>>,
1077 hovered: Rc<Cell<bool>>,
1078 pub(crate) needs_present: Rc<Cell<bool>>,
1079 pub(crate) input_rate_tracker: Rc<RefCell<InputRateTracker>>,
1080 #[cfg(feature = "input-latency-histogram")]
1081 input_latency_tracker: InputLatencyTracker,
1082 #[allow(dead_code)]
1083 pub(crate) last_frame_time: Rc<Cell<Option<Instant>>>,
1084 pub(crate) last_input_was_keyboard: Cell<bool>,
1085 pub(crate) refreshing: bool,
1086 pub(crate) activation_observers: SubscriberSet<(), AnyObserver>,
1087 pub(crate) focus: Option<FocusId>,
1088 focus_enabled: bool,
1089 pending_input: Option<PendingInput>,
1090 pending_modifier: ModifierState,
1091 pub(crate) pending_input_observers: SubscriberSet<(), AnyObserver>,
1092 prompt: Option<RenderablePromptHandle>,
1093 pub(crate) client_inset: Option<Pixels>,
1094 captured_hitbox: Option<HitboxId>,
1097 #[cfg(any(feature = "inspector", debug_assertions))]
1098 inspector: Option<Entity<Inspector>>,
1099}
1100
1101#[derive(Clone, Debug, Default)]
1102struct ModifierState {
1103 modifiers: Modifiers,
1104 saw_other_input: bool,
1105}
1106
1107#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1108pub(crate) enum DrawPhase {
1109 None,
1110 Prepaint,
1111 Paint,
1112 Focus,
1113}
1114
1115#[derive(Default, Debug)]
1116struct PendingInput {
1117 keystrokes: SmallVec<[Keystroke; 1]>,
1118 focus: Option<FocusId>,
1119 timer: Option<Task<()>>,
1120}
1121
1122pub(crate) struct ElementStateBox {
1123 pub(crate) inner: Box<dyn Any>,
1124 #[cfg(debug_assertions)]
1125 pub(crate) type_name: &'static str,
1126}
1127
1128fn default_bounds(display_id: Option<DisplayId>, cx: &mut App) -> Bounds<Pixels> {
1129 const DEFAULT_WINDOW_OFFSET: Point<Pixels> = point(px(0.), px(35.));
1130
1131 cx.active_window()
1135 .and_then(|w| w.update(cx, |_, window, _| window.bounds()).ok())
1136 .map(|mut bounds| {
1137 bounds.origin += DEFAULT_WINDOW_OFFSET;
1138 bounds
1139 })
1140 .unwrap_or_else(|| {
1141 let display = display_id
1142 .map(|id| cx.find_display(id))
1143 .unwrap_or_else(|| cx.primary_display());
1144
1145 display
1146 .map(|display| display.default_bounds())
1147 .unwrap_or_else(|| Bounds::new(point(px(0.), px(0.)), DEFAULT_WINDOW_SIZE))
1148 })
1149}
1150
1151fn border_only_quad_strips(
1152 outer_bounds: Bounds<ScaledPixels>,
1153 widths: Edges<ScaledPixels>,
1154 radii: Corners<ScaledPixels>,
1155) -> Option<[Bounds<ScaledPixels>; 4]> {
1156 let antialias_slack = point(ScaledPixels(1.0), ScaledPixels(1.0));
1157 let top_left_inset = point(
1158 widths.left,
1159 widths.top.max(radii.top_left).max(radii.top_right),
1160 ) + antialias_slack;
1161 let bottom_right_inset = point(
1162 widths.right,
1163 widths.bottom.max(radii.bottom_left).max(radii.bottom_right),
1164 ) + antialias_slack;
1165 let inner_bounds = Bounds::from_corners(
1166 outer_bounds.origin + top_left_inset,
1167 outer_bounds.bottom_right() - bottom_right_inset,
1168 );
1169 if inner_bounds.is_empty() {
1170 return None;
1171 }
1172
1173 Some([
1174 Bounds::from_corners(
1175 outer_bounds.origin,
1176 point(outer_bounds.right(), inner_bounds.top()),
1177 ),
1178 Bounds::from_corners(
1179 point(outer_bounds.left(), inner_bounds.bottom()),
1180 outer_bounds.bottom_right(),
1181 ),
1182 Bounds::from_corners(
1183 point(outer_bounds.left(), inner_bounds.top()),
1184 inner_bounds.bottom_left(),
1185 ),
1186 Bounds::from_corners(
1187 inner_bounds.top_right(),
1188 point(outer_bounds.right(), inner_bounds.bottom()),
1189 ),
1190 ])
1191}
1192
1193impl Window {
1194 pub(crate) fn new(
1195 handle: AnyWindowHandle,
1196 options: WindowOptions,
1197 cx: &mut App,
1198 ) -> Result<Self> {
1199 let WindowOptions {
1200 window_bounds,
1201 titlebar,
1202 focus,
1203 show,
1204 kind,
1205 is_movable,
1206 app_owns_titlebar_drag,
1207 inactive_frame_interval,
1208 is_resizable,
1209 is_minimizable,
1210 display_id,
1211 window_background,
1212 app_id,
1213 window_min_size,
1214 window_decorations,
1215 #[cfg_attr(not(target_os = "macos"), allow(unused_variables))]
1216 tabbing_identifier,
1217 mouse_passthrough,
1218 icon,
1219 } = options;
1220
1221 let bounds = window_bounds
1222 .map(|bounds| bounds.get_bounds())
1223 .unwrap_or_else(|| default_bounds(display_id, cx));
1224 let mut platform_window = cx.platform.open_window(
1225 handle,
1226 WindowParams {
1227 bounds,
1228 titlebar,
1229 kind,
1230 is_movable,
1231 app_owns_titlebar_drag,
1232 is_resizable,
1233 is_minimizable,
1234 focus,
1235 app_id: app_id.clone(),
1236 show,
1237 display_id,
1238 window_min_size,
1239 #[cfg(target_os = "macos")]
1240 tabbing_identifier,
1241 mouse_passthrough,
1242 icon,
1243 },
1244 )?;
1245
1246 let tab_bar_visible = platform_window.tab_bar_visible();
1247 SystemWindowTabController::init_visible(cx, tab_bar_visible);
1248 if let Some(tabs) = platform_window.tabbed_windows() {
1249 SystemWindowTabController::add_tab(cx, handle.window_id(), tabs);
1250 }
1251
1252 let display_id = platform_window.display().map(|display| display.id());
1253 let sprite_atlas = platform_window.sprite_atlas();
1254 let mouse_position = platform_window.mouse_position();
1255 let modifiers = platform_window.modifiers();
1256 let capslock = platform_window.capslock();
1257 let content_size = platform_window.content_size();
1258 let scale_factor = platform_window.scale_factor();
1259 let appearance = platform_window.appearance();
1260 let text_system = Arc::new(WindowTextSystem::new(cx.text_system().clone()));
1261 let invalidator = WindowInvalidator::new();
1262 let active = Rc::new(Cell::new(platform_window.is_active()));
1263 let hovered = Rc::new(Cell::new(platform_window.is_hovered()));
1264 let needs_present = Rc::new(Cell::new(false));
1265 let next_frame_callbacks: Rc<RefCell<Vec<FrameCallback>>> = Default::default();
1266 let input_rate_tracker = Rc::new(RefCell::new(InputRateTracker::default()));
1267 let last_frame_time = Rc::new(Cell::new(None::<Instant>));
1268
1269 platform_window
1270 .request_decorations(window_decorations.unwrap_or(WindowDecorations::Server));
1271 platform_window.set_background_appearance(window_background);
1272
1273 if let Some(ref window_open_state) = window_bounds {
1274 match window_open_state {
1275 WindowBounds::Fullscreen(_) => platform_window.toggle_fullscreen(),
1276 WindowBounds::Maximized(_) => platform_window.zoom(),
1277 WindowBounds::Windowed(_) => {}
1278 }
1279 }
1280
1281 let accessibility_force_disabled =
1282 cx.accessibility_force_disabled || !cfg!(feature = "accessibility");
1283 let a11y_active_flag = Arc::new(AtomicBool::new(false));
1284
1285 #[cfg(not(target_family = "wasm"))]
1286 if !accessibility_force_disabled {
1287 let initial_tree = accesskit::TreeUpdate {
1288 nodes: vec![(ROOT_NODE_ID, accesskit::Node::new(accesskit::Role::Window))],
1289 tree: Some(accesskit::Tree::new(ROOT_NODE_ID)),
1290 tree_id: accesskit::TreeId::ROOT,
1291 focus: ROOT_NODE_ID,
1292 };
1293 let (activation_sender, activation_receiver) = async_channel::unbounded::<()>();
1294 let (deactivation_sender, deactivation_receiver) = async_channel::unbounded::<()>();
1295 let (action_sender, action_receiver) =
1296 async_channel::unbounded::<accesskit::ActionRequest>();
1297
1298 platform_window.a11y_init(crate::A11yCallbacks {
1299 activation: {
1300 let active_flag = a11y_active_flag.clone();
1301 Box::new(move || {
1302 log::info!("Accessibility activated");
1303 active_flag.store(true, SeqCst);
1304 activation_sender.send_blocking(()).log_err();
1305 Some(initial_tree.clone())
1306 })
1307 },
1308 action: Box::new(move |request| {
1309 action_sender.send_blocking(request).log_err();
1310 }),
1311 deactivation: {
1312 let active_flag = a11y_active_flag.clone();
1313 Box::new(move || {
1314 log::info!("Accessibility deactivated");
1315 active_flag.store(false, SeqCst);
1316 deactivation_sender.send_blocking(()).log_err();
1317 })
1318 },
1319 });
1320
1321 let mut async_cx = cx.to_async();
1322 cx.foreground_executor()
1323 .spawn(async move {
1324 while activation_receiver.recv().await.is_ok() {
1325 handle
1326 .update(&mut async_cx, |_, window, _| window.refresh())
1327 .log_err();
1328 }
1329 })
1330 .detach();
1331
1332 let mut async_cx = cx.to_async();
1333 cx.foreground_executor()
1334 .spawn(async move {
1335 while deactivation_receiver.recv().await.is_ok() {
1336 handle
1337 .update(&mut async_cx, |_, window, _| window.refresh())
1338 .log_err();
1339 }
1340 })
1341 .detach();
1342
1343 let mut async_cx = cx.to_async();
1344 cx.foreground_executor()
1345 .spawn(async move {
1346 while let Ok(request) = action_receiver.recv().await {
1347 handle
1348 .update(&mut async_cx, |_, window, cx| {
1349 window.handle_a11y_action(request, cx);
1350 })
1351 .log_err();
1352 }
1353 })
1354 .detach();
1355 }
1356
1357 platform_window.on_close(Box::new({
1358 let window_id = handle.window_id();
1359 let mut cx = cx.to_async();
1360 move || {
1361 let _ = handle.update(&mut cx, |_, window, _| window.remove_window());
1362 let _ = cx.update(|cx| {
1363 SystemWindowTabController::remove_tab(cx, window_id);
1364 });
1365 }
1366 }));
1367 platform_window.on_request_frame(Box::new({
1368 let mut cx = cx.to_async();
1369 let invalidator = invalidator.clone();
1370 let active = active.clone();
1371 let needs_present = needs_present.clone();
1372 let next_frame_callbacks = next_frame_callbacks.clone();
1373 let input_rate_tracker = input_rate_tracker.clone();
1374 let last_frame_time = last_frame_time.clone();
1375 let mut deferred_force_render = false;
1376 move |request_frame_options| {
1377 if draw_in_progress() {
1393 log::debug!("deferring re-entrant window draw request");
1394 deferred_force_render |= request_frame_options.force_render;
1395 return;
1396 }
1397 let force_render =
1401 mem::take(&mut deferred_force_render) || request_frame_options.force_render;
1402
1403 let thermal_state = handle
1404 .update(&mut cx, |_, _, cx| cx.thermal_state())
1405 .log_err();
1406
1407 let has_high_rate_input = input_rate_tracker.borrow().is_high_rate();
1412 let min_frame_interval = frame_throttle_interval(
1413 force_render,
1414 request_frame_options.require_presentation,
1415 !next_frame_callbacks.borrow().is_empty(),
1416 active.get(),
1417 has_high_rate_input,
1418 matches!(
1419 thermal_state,
1420 Some(ThermalState::Critical | ThermalState::Serious)
1421 ),
1422 inactive_frame_interval,
1423 );
1424
1425 let now = Instant::now();
1426 if let Some(min_interval) = min_frame_interval {
1427 if let Some(last_frame) = last_frame_time.get() {
1428 if now.duration_since(last_frame) < min_interval {
1429 deferred_force_render |= force_render;
1431 handle
1433 .update(&mut cx, |_, window, _| {
1434 window.platform_window.schedule_frame();
1435 })
1436 .log_err();
1437 return;
1438 }
1439 }
1440 }
1441 last_frame_time.set(Some(now));
1442
1443 let next_frame_callbacks = next_frame_callbacks.take();
1444 if !next_frame_callbacks.is_empty() {
1445 handle
1446 .update(&mut cx, |_, window, cx| {
1447 for callback in next_frame_callbacks {
1448 callback(window, cx);
1449 }
1450 })
1451 .log_err();
1452 }
1453
1454 let needs_present = request_frame_options.require_presentation
1457 || needs_present.get()
1458 || has_high_rate_input;
1459
1460 if invalidator.is_dirty() || force_render {
1461 measure("frame duration", || {
1462 handle
1463 .update(&mut cx, |_, window, cx| {
1464 if force_render {
1465 window.refresh();
1466 }
1467 let arena_clear_needed = window.draw(cx);
1468 window.present();
1469 arena_clear_needed.clear();
1471 })
1472 .log_err();
1473 })
1474 } else if needs_present {
1475 handle
1476 .update(&mut cx, |_, window, _| window.present())
1477 .log_err();
1478 }
1479
1480 handle
1481 .update(&mut cx, |_, window, _| {
1482 if window.invalidator.is_dirty()
1483 || !window.next_frame_callbacks.borrow().is_empty()
1484 {
1485 window.platform_window.schedule_frame();
1486 }
1487 })
1488 .log_err();
1489 }
1490 }));
1491 platform_window.on_resize(Box::new({
1492 let mut cx = cx.to_async();
1493 move |_, _| {
1494 handle
1495 .update(&mut cx, |_, window, cx| window.bounds_changed(cx))
1496 .log_err();
1497 }
1498 }));
1499 platform_window.on_moved(Box::new({
1500 let mut cx = cx.to_async();
1501 move || {
1502 handle
1503 .update(&mut cx, |_, window, cx| window.bounds_changed(cx))
1504 .log_err();
1505 }
1506 }));
1507 platform_window.on_appearance_changed(Box::new({
1508 let cx = cx.to_async();
1509 let foreground_executor = cx.foreground_executor().clone();
1510 move || {
1511 let mut cx = cx.clone();
1512 foreground_executor
1515 .spawn(async move {
1516 handle
1517 .update(&mut cx, |_, window, cx| window.appearance_changed(cx))
1518 .log_err();
1519 })
1520 .detach();
1521 }
1522 }));
1523 platform_window.on_active_status_change(Box::new({
1524 let mut cx = cx.to_async();
1525 move |active| {
1526 handle
1527 .update(&mut cx, |_, window, cx| {
1528 if !active {
1529 window.platform_window.set_cursor_style(CursorStyle::Arrow);
1532 cx.platform.set_cursor_style(CursorStyle::Arrow);
1533 }
1534
1535 window.active.set(active);
1536 window.modifiers = window.platform_window.modifiers();
1537 window.capslock = window.platform_window.capslock();
1538 window
1539 .activation_observers
1540 .clone()
1541 .retain(&(), |callback| callback(window, cx));
1542
1543 window.bounds_changed(cx);
1544 window.refresh();
1545
1546 SystemWindowTabController::update_last_active(cx, window.handle.id);
1547 })
1548 .log_err();
1549 }
1550 }));
1551 platform_window.on_hover_status_change(Box::new({
1552 let mut cx = cx.to_async();
1553 move |active| {
1554 handle
1555 .update(&mut cx, |_, window, _| {
1556 window.hovered.set(active);
1557 window.refresh();
1558 })
1559 .log_err();
1560 }
1561 }));
1562 platform_window.on_input({
1563 let mut cx = cx.to_async();
1564 Box::new(move |event| {
1565 handle
1566 .update(&mut cx, |_, window, cx| window.dispatch_event(event, cx))
1567 .log_err()
1568 .unwrap_or(DispatchEventResult::default())
1569 })
1570 });
1571 platform_window.on_hit_test_window_control({
1572 let mut cx = cx.to_async();
1573 Box::new(move || {
1574 handle
1575 .update(&mut cx, |_, window, _cx| {
1576 for (area, hitbox) in &window.rendered_frame.window_control_hitboxes {
1577 if window.mouse_hit_test.ids.contains(&hitbox.id) {
1578 return Some(*area);
1579 }
1580 }
1581 None
1582 })
1583 .log_err()
1584 .unwrap_or(None)
1585 })
1586 });
1587 platform_window.on_move_tab_to_new_window({
1588 let mut cx = cx.to_async();
1589 Box::new(move || {
1590 handle
1591 .update(&mut cx, |_, _window, cx| {
1592 SystemWindowTabController::move_tab_to_new_window(cx, handle.window_id());
1593 })
1594 .log_err();
1595 })
1596 });
1597 platform_window.on_merge_all_windows({
1598 let mut cx = cx.to_async();
1599 Box::new(move || {
1600 handle
1601 .update(&mut cx, |_, _window, cx| {
1602 SystemWindowTabController::merge_all_windows(cx, handle.window_id());
1603 })
1604 .log_err();
1605 })
1606 });
1607 platform_window.on_select_next_tab({
1608 let mut cx = cx.to_async();
1609 Box::new(move || {
1610 handle
1611 .update(&mut cx, |_, _window, cx| {
1612 SystemWindowTabController::select_next_tab(cx, handle.window_id());
1613 })
1614 .log_err();
1615 })
1616 });
1617 platform_window.on_select_previous_tab({
1618 let mut cx = cx.to_async();
1619 Box::new(move || {
1620 handle
1621 .update(&mut cx, |_, _window, cx| {
1622 SystemWindowTabController::select_previous_tab(cx, handle.window_id())
1623 })
1624 .log_err();
1625 })
1626 });
1627 platform_window.on_toggle_tab_bar({
1628 let mut cx = cx.to_async();
1629 Box::new(move || {
1630 handle
1631 .update(&mut cx, |_, window, cx| {
1632 let tab_bar_visible = window.platform_window.tab_bar_visible();
1633 SystemWindowTabController::set_visible(cx, tab_bar_visible);
1634 })
1635 .log_err();
1636 })
1637 });
1638
1639 if let Some(app_id) = app_id {
1640 platform_window.set_app_id(&app_id);
1641 }
1642
1643 platform_window.map_window()?;
1644
1645 Ok(Window {
1646 handle,
1647 invalidator,
1648 removed: false,
1649 platform_window,
1650 a11y: A11y::new(a11y_active_flag, accessibility_force_disabled),
1651 display_id,
1652 sprite_atlas,
1653 text_system,
1654 rem_size: px(16.),
1655 rem_size_override_stack: SmallVec::new(),
1656 viewport_size: content_size,
1657 layout_engine: Some(TaffyLayoutEngine::new()),
1658 root: None,
1659 element_id_stack: SmallVec::default(),
1660 text_style_stack: SmallVec::new(),
1661 rendered_entity_stack: SmallVec::new(),
1662 element_offset_stack: SmallVec::new(),
1663 content_mask_stack: SmallVec::new(),
1664 element_opacity: 1.0,
1665 requested_autoscroll: None,
1666 rendered_frame: Frame::new(DispatchTree::new(cx.keymap.clone(), cx.actions.clone())),
1667 next_frame: Frame::new(DispatchTree::new(cx.keymap.clone(), cx.actions.clone())),
1668 next_frame_callbacks,
1669 next_hitbox_id: HitboxId(0),
1670 next_tooltip_id: TooltipId::default(),
1671 tooltip_bounds: None,
1672 dirty_views: FxHashSet::default(),
1673 focus_listeners: SubscriberSet::new(),
1674 focus_lost_listeners: SubscriberSet::new(),
1675 default_prevented: true,
1676 mouse_position,
1677 mouse_hit_test: HitTest::default(),
1678 modifiers,
1679 capslock,
1680 scale_factor,
1681 bounds_observers: SubscriberSet::new(),
1682 appearance,
1683 appearance_observers: SubscriberSet::new(),
1684 active,
1685 hovered,
1686 needs_present,
1687 input_rate_tracker,
1688 #[cfg(feature = "input-latency-histogram")]
1689 input_latency_tracker: InputLatencyTracker::new()?,
1690 last_frame_time,
1691 last_input_was_keyboard: Cell::new(false),
1692 refreshing: false,
1693 activation_observers: SubscriberSet::new(),
1694 focus: None,
1695 focus_enabled: true,
1696 pending_input: None,
1697 pending_modifier: ModifierState::default(),
1698 pending_input_observers: SubscriberSet::new(),
1699 prompt: None,
1700 client_inset: None,
1701 image_cache_stack: SmallVec::new(),
1702 captured_hitbox: None,
1703 #[cfg(any(feature = "inspector", debug_assertions))]
1704 inspector: None,
1705 })
1706 }
1707
1708 pub(crate) fn new_focus_listener(
1709 &self,
1710 value: AnyWindowFocusListener,
1711 ) -> (Subscription, impl FnOnce() + use<>) {
1712 self.focus_listeners.insert((), value)
1713 }
1714}
1715
1716#[derive(Clone, Debug, Default, PartialEq, Eq)]
1717#[allow(missing_docs)]
1718pub struct DispatchEventResult {
1719 pub propagate: bool,
1720 pub default_prevented: bool,
1721}
1722
1723#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
1727#[repr(C)]
1728pub struct ContentMask<P: Clone + Debug + Default + PartialEq> {
1729 pub bounds: Bounds<P>,
1731}
1732
1733impl ContentMask<Pixels> {
1734 pub fn scale(&self, factor: f32) -> ContentMask<ScaledPixels> {
1736 ContentMask {
1737 bounds: self.bounds.scale(factor),
1738 }
1739 }
1740
1741 pub fn intersect(&self, other: &Self) -> Self {
1743 let bounds = self.bounds.intersect(&other.bounds);
1744 ContentMask { bounds }
1745 }
1746}
1747
1748impl Window {
1749 fn mark_view_dirty(&mut self, view_id: EntityId) {
1750 for view_id in self
1753 .rendered_frame
1754 .dispatch_tree
1755 .view_path(view_id)
1756 .into_iter()
1757 .rev()
1758 {
1759 if !self.dirty_views.insert(view_id) {
1760 break;
1761 }
1762 }
1763 }
1764
1765 pub fn observe_window_appearance(
1767 &self,
1768 mut callback: impl FnMut(&mut Window, &mut App) + 'static,
1769 ) -> Subscription {
1770 let (subscription, activate) = self.appearance_observers.insert(
1771 (),
1772 Box::new(move |window, cx| {
1773 callback(window, cx);
1774 true
1775 }),
1776 );
1777 activate();
1778 subscription
1779 }
1780
1781 pub fn replace_root<E>(
1783 &mut self,
1784 cx: &mut App,
1785 build_view: impl FnOnce(&mut Window, &mut Context<E>) -> E,
1786 ) -> Entity<E>
1787 where
1788 E: 'static + Render,
1789 {
1790 let view = cx.new(|cx| build_view(self, cx));
1791 self.root = Some(view.clone().into());
1792 self.refresh();
1793 view
1794 }
1795
1796 pub fn root<E>(&self) -> Option<Option<Entity<E>>>
1798 where
1799 E: 'static + Render,
1800 {
1801 self.root
1802 .as_ref()
1803 .map(|view| view.clone().downcast::<E>().ok())
1804 }
1805
1806 pub fn window_handle(&self) -> AnyWindowHandle {
1808 self.handle
1809 }
1810
1811 pub fn refresh(&mut self) {
1813 if self.invalidator.not_drawing() {
1814 self.refreshing = true;
1815 self.invalidator.set_dirty(true);
1816 }
1817 }
1818
1819 pub fn remove_window(&mut self) {
1821 self.removed = true;
1822 }
1823
1824 pub fn focused(&self, cx: &App) -> Option<FocusHandle> {
1826 self.focus
1827 .and_then(|id| FocusHandle::for_id(id, &cx.focus_handles))
1828 }
1829
1830 pub fn focus(&mut self, handle: &FocusHandle) {
1832 if !self.focus_enabled || self.focus == Some(handle.id) {
1833 return;
1834 }
1835
1836 self.focus = Some(handle.id);
1837 self.pending_input.take();
1838 self.refresh();
1839 }
1840
1841 pub fn blur(&mut self, cx: &mut App) {
1843 self.clear_pending_keystrokes(cx);
1844
1845 if !self.focus_enabled {
1846 return;
1847 }
1848
1849 self.focus = None;
1850 self.refresh();
1851 }
1852
1853 pub fn disable_focus(&mut self, cx: &mut App) {
1855 self.blur(cx);
1856 self.focus_enabled = false;
1857 }
1858
1859 pub fn focus_next(&mut self) {
1861 if !self.focus_enabled {
1862 return;
1863 }
1864
1865 if let Some(handle) = self.rendered_frame.tab_stops.next(self.focus.as_ref()) {
1866 self.focus(&handle)
1867 }
1868 }
1869
1870 pub fn focus_prev(&mut self) {
1872 if !self.focus_enabled {
1873 return;
1874 }
1875
1876 if let Some(handle) = self.rendered_frame.tab_stops.prev(self.focus.as_ref()) {
1877 self.focus(&handle)
1878 }
1879 }
1880
1881 pub fn text_system(&self) -> &Arc<WindowTextSystem> {
1883 &self.text_system
1884 }
1885
1886 pub fn text_style(&self) -> TextStyle {
1888 let mut style = TextStyle::default();
1889 for refinement in &self.text_style_stack {
1890 style.refine(refinement);
1891 }
1892 style
1893 }
1894
1895 pub fn is_maximized(&self) -> bool {
1898 self.platform_window.is_maximized()
1899 }
1900
1901 pub fn request_decorations(&self, decorations: WindowDecorations) {
1903 self.platform_window.request_decorations(decorations);
1904 }
1905
1906 pub fn set_exclusive_zone(&self, zone: Pixels) {
1908 self.platform_window.set_exclusive_zone(zone);
1909 }
1910
1911 #[cfg(all(any(target_os = "linux", target_os = "freebsd"), feature = "wayland"))]
1914 pub fn set_exclusive_edge(&self, edge: crate::layer_shell::Anchor) {
1915 self.platform_window.set_exclusive_edge(edge);
1916 }
1917
1918 pub fn start_window_resize(&self, edge: ResizeEdge) {
1920 self.platform_window.start_window_resize(edge);
1921 }
1922
1923 pub fn window_bounds(&self) -> WindowBounds {
1926 self.platform_window.window_bounds()
1927 }
1928
1929 pub fn inner_window_bounds(&self) -> WindowBounds {
1931 self.platform_window.inner_window_bounds()
1932 }
1933
1934 pub fn dispatch_action(&mut self, action: Box<dyn Action>, cx: &mut App) {
1936 let focus_id = self.focused(cx).map(|handle| handle.id);
1937
1938 let window = self.handle;
1939 cx.defer(move |cx| {
1940 window
1941 .update(cx, |_, window, cx| {
1942 let node_id = window.focus_node_id_in_rendered_frame(focus_id);
1943 window.dispatch_action_on_node(node_id, action.as_ref(), cx);
1944 })
1945 .log_err();
1946 })
1947 }
1948
1949 pub(crate) fn dispatch_keystroke_observers(
1950 &mut self,
1951 event: &dyn Any,
1952 action: Option<Box<dyn Action>>,
1953 context_stack: Vec<KeyContext>,
1954 cx: &mut App,
1955 ) {
1956 let Some(key_down_event) = event.downcast_ref::<KeyDownEvent>() else {
1957 return;
1958 };
1959
1960 cx.keystroke_observers.clone().retain(&(), move |callback| {
1961 (callback)(
1962 &KeystrokeEvent {
1963 keystroke: key_down_event.keystroke.clone(),
1964 action: action.as_ref().map(|action| action.boxed_clone()),
1965 context_stack: context_stack.clone(),
1966 },
1967 self,
1968 cx,
1969 )
1970 });
1971 }
1972
1973 pub(crate) fn dispatch_keystroke_interceptors(
1974 &mut self,
1975 event: &dyn Any,
1976 context_stack: Vec<KeyContext>,
1977 cx: &mut App,
1978 ) {
1979 let Some(key_down_event) = event.downcast_ref::<KeyDownEvent>() else {
1980 return;
1981 };
1982
1983 cx.keystroke_interceptors
1984 .clone()
1985 .retain(&(), move |callback| {
1986 (callback)(
1987 &KeystrokeEvent {
1988 keystroke: key_down_event.keystroke.clone(),
1989 action: None,
1990 context_stack: context_stack.clone(),
1991 },
1992 self,
1993 cx,
1994 )
1995 });
1996 }
1997
1998 pub fn defer(&self, cx: &mut App, f: impl FnOnce(&mut Window, &mut App) + 'static) {
2001 let handle = self.handle;
2002 cx.defer(move |cx| {
2003 handle.update(cx, |_, window, cx| f(window, cx)).ok();
2004 });
2005 }
2006
2007 pub fn observe<T: 'static>(
2011 &mut self,
2012 observed: &Entity<T>,
2013 cx: &mut App,
2014 mut on_notify: impl FnMut(Entity<T>, &mut Window, &mut App) + 'static,
2015 ) -> Subscription {
2016 let entity_id = observed.entity_id();
2017 let observed = observed.downgrade();
2018 let window_handle = self.handle;
2019 cx.new_observer(
2020 entity_id,
2021 Box::new(move |cx| {
2022 window_handle
2023 .update(cx, |_, window, cx| {
2024 if let Some(handle) = observed.upgrade() {
2025 on_notify(handle, window, cx);
2026 true
2027 } else {
2028 false
2029 }
2030 })
2031 .unwrap_or(false)
2032 }),
2033 )
2034 }
2035
2036 pub fn subscribe<Emitter, Evt>(
2040 &mut self,
2041 entity: &Entity<Emitter>,
2042 cx: &mut App,
2043 mut on_event: impl FnMut(Entity<Emitter>, &Evt, &mut Window, &mut App) + 'static,
2044 ) -> Subscription
2045 where
2046 Emitter: EventEmitter<Evt>,
2047 Evt: 'static,
2048 {
2049 let entity_id = entity.entity_id();
2050 let handle = entity.downgrade();
2051 let window_handle = self.handle;
2052 cx.new_subscription(
2053 entity_id,
2054 (
2055 TypeId::of::<Evt>(),
2056 Box::new(move |event, cx| {
2057 window_handle
2058 .update(cx, |_, window, cx| {
2059 if let Some(entity) = handle.upgrade() {
2060 let event = event.downcast_ref().expect("invalid event type");
2061 on_event(entity, event, window, cx);
2062 true
2063 } else {
2064 false
2065 }
2066 })
2067 .unwrap_or(false)
2068 }),
2069 ),
2070 )
2071 }
2072
2073 pub fn observe_release<T>(
2075 &self,
2076 entity: &Entity<T>,
2077 cx: &mut App,
2078 mut on_release: impl FnOnce(&mut T, &mut Window, &mut App) + 'static,
2079 ) -> Subscription
2080 where
2081 T: 'static,
2082 {
2083 let entity_id = entity.entity_id();
2084 let window_handle = self.handle;
2085 let (subscription, activate) = cx.release_listeners.insert(
2086 entity_id,
2087 Box::new(move |entity, cx| {
2088 let entity = entity.downcast_mut().expect("invalid entity type");
2089 let _ = window_handle.update(cx, |_, window, cx| on_release(entity, window, cx));
2090 }),
2091 );
2092 activate();
2093 subscription
2094 }
2095
2096 pub fn to_async(&self, cx: &App) -> AsyncWindowContext {
2099 AsyncWindowContext::new_context(cx.to_async(), self.handle)
2100 }
2101
2102 pub fn on_next_frame(&self, callback: impl FnOnce(&mut Window, &mut App) + 'static) {
2104 RefCell::borrow_mut(&self.next_frame_callbacks).push(Box::new(callback));
2105 self.platform_window.schedule_frame();
2106 }
2107
2108 pub fn request_animation_frame(&self) {
2115 let entity = self.current_view();
2116 self.on_next_frame(move |_, cx| cx.notify(entity));
2117 }
2118
2119 #[track_caller]
2123 pub fn spawn<AsyncFn, R>(&self, cx: &App, f: AsyncFn) -> Task<R>
2124 where
2125 R: 'static,
2126 AsyncFn: AsyncFnOnce(&mut AsyncWindowContext) -> R + 'static,
2127 {
2128 let handle = self.handle;
2129 cx.spawn(async move |app| {
2130 let mut async_window_cx = AsyncWindowContext::new_context(app.clone(), handle);
2131 f(&mut async_window_cx).await
2132 })
2133 }
2134
2135 fn bounds_changed(&mut self, cx: &mut App) {
2136 self.scale_factor = self.platform_window.scale_factor();
2137 self.viewport_size = self.platform_window.content_size();
2138 self.display_id = self.platform_window.display().map(|display| display.id());
2139 self.mouse_position = self.platform_window.mouse_position();
2140 self.platform_window.a11y_update_window_bounds();
2141
2142 self.refresh();
2143
2144 self.bounds_observers
2145 .clone()
2146 .retain(&(), |callback| callback(self, cx));
2147 }
2148
2149 pub fn bounds(&self) -> Bounds<Pixels> {
2151 self.platform_window.bounds()
2152 }
2153
2154 pub fn resize(&mut self, size: Size<Pixels>) {
2156 self.platform_window.resize(size);
2157 }
2158
2159 pub fn is_fullscreen(&self) -> bool {
2161 self.platform_window.is_fullscreen()
2162 }
2163
2164 pub(crate) fn appearance_changed(&mut self, cx: &mut App) {
2165 self.appearance = self.platform_window.appearance();
2166
2167 self.appearance_observers
2168 .clone()
2169 .retain(&(), |callback| callback(self, cx));
2170 }
2171
2172 pub fn appearance(&self) -> WindowAppearance {
2174 self.appearance
2175 }
2176
2177 pub fn viewport_size(&self) -> Size<Pixels> {
2179 self.viewport_size
2180 }
2181
2182 pub fn is_window_active(&self) -> bool {
2184 self.active.get()
2185 }
2186
2187 pub fn is_window_hovered(&self) -> bool {
2191 if cfg!(any(
2192 target_os = "windows",
2193 target_os = "linux",
2194 target_os = "freebsd"
2195 )) {
2196 self.hovered.get()
2197 } else {
2198 self.is_window_active()
2199 }
2200 }
2201
2202 pub fn last_input_was_keyboard(&self) -> bool {
2205 self.last_input_was_keyboard.get()
2206 }
2207
2208 pub fn zoom_window(&self) {
2210 self.platform_window.zoom();
2211 }
2212
2213 pub fn show_window_menu(&self, position: Point<Pixels>) {
2215 self.platform_window.show_window_menu(position)
2216 }
2217
2218 pub fn start_window_move(&self) {
2222 self.platform_window.start_window_move()
2223 }
2224
2225 pub fn set_client_inset(&mut self, inset: Pixels) {
2227 self.client_inset = Some(inset);
2228 self.platform_window.set_client_inset(inset);
2229 }
2230
2231 pub fn client_inset(&self) -> Option<Pixels> {
2233 self.client_inset
2234 }
2235
2236 pub fn window_decorations(&self) -> Decorations {
2238 self.platform_window.window_decorations()
2239 }
2240
2241 pub fn window_controls(&self) -> WindowControls {
2243 self.platform_window.window_controls()
2244 }
2245
2246 pub fn set_window_title(&mut self, title: &str) {
2248 self.platform_window.set_title(title);
2249 }
2250
2251 pub fn set_app_id(&mut self, app_id: &str) {
2253 self.platform_window.set_app_id(app_id);
2254 }
2255
2256 pub fn set_background_appearance(&self, background_appearance: WindowBackgroundAppearance) {
2258 self.platform_window
2259 .set_background_appearance(background_appearance);
2260 }
2261
2262 pub fn set_window_edited(&mut self, edited: bool) {
2264 self.platform_window.set_edited(edited);
2265 }
2266
2267 pub fn display(&self, cx: &App) -> Option<Rc<dyn PlatformDisplay>> {
2269 cx.platform
2270 .displays()
2271 .into_iter()
2272 .find(|display| Some(display.id()) == self.display_id)
2273 }
2274
2275 pub fn show_character_palette(&self) {
2277 self.platform_window.show_character_palette();
2278 }
2279
2280 pub fn scale_factor(&self) -> f32 {
2284 self.scale_factor
2285 }
2286
2287 pub fn rem_size(&self) -> Pixels {
2290 self.rem_size_override_stack
2291 .last()
2292 .copied()
2293 .unwrap_or(self.rem_size)
2294 }
2295
2296 pub fn set_rem_size(&mut self, rem_size: impl Into<Pixels>) {
2299 self.rem_size = rem_size.into();
2300 }
2301
2302 pub fn with_global_id<R>(
2305 &mut self,
2306 element_id: ElementId,
2307 f: impl FnOnce(&GlobalElementId, &mut Self) -> R,
2308 ) -> R {
2309 self.element_id_stack.push(element_id);
2310 let global_id = GlobalElementId(self.element_id_stack.clone());
2311 let result = f(&global_id, self);
2312 self.element_id_stack.pop();
2313 result
2314 }
2315
2316 pub fn with_rem_size<F, R>(&mut self, rem_size: Option<impl Into<Pixels>>, f: F) -> R
2320 where
2321 F: FnOnce(&mut Self) -> R,
2322 {
2323 self.invalidator.debug_assert_paint_or_prepaint();
2324
2325 if let Some(rem_size) = rem_size {
2326 self.rem_size_override_stack.push(rem_size.into());
2327 let result = f(self);
2328 self.rem_size_override_stack.pop();
2329 result
2330 } else {
2331 f(self)
2332 }
2333 }
2334
2335 pub fn line_height(&self) -> Pixels {
2337 self.text_style().line_height_in_pixels(self.rem_size())
2338 }
2339
2340 #[inline]
2342 pub fn pixel_snap(&self, value: Pixels) -> Pixels {
2343 px(round_to_device_pixel(value.0, self.scale_factor()) / self.scale_factor())
2344 }
2345
2346 #[inline]
2348 pub fn pixel_snap_f64(&self, value: f64) -> f64 {
2349 let scale_factor = f64::from(self.scale_factor());
2350 round_half_toward_zero_f64(value * scale_factor) / scale_factor
2351 }
2352
2353 #[inline]
2355 pub fn pixel_snap_bounds(&self, bounds: Bounds<Pixels>) -> Bounds<Pixels> {
2356 bounds.map(|c| self.pixel_snap(c))
2357 }
2358
2359 #[inline]
2361 pub fn pixel_snap_point(&self, position: Point<Pixels>) -> Point<Pixels> {
2362 position.map(|c| self.pixel_snap(c))
2363 }
2364
2365 #[inline]
2366 fn snap_bounds(&self, bounds: Bounds<Pixels>) -> Bounds<ScaledPixels> {
2367 let scale_factor = self.scale_factor();
2368 let left = round_to_device_pixel(bounds.left().0, scale_factor);
2369 let top = round_to_device_pixel(bounds.top().0, scale_factor);
2370 let right = round_to_device_pixel(bounds.right().0, scale_factor).max(left);
2371 let bottom = round_to_device_pixel(bounds.bottom().0, scale_factor).max(top);
2372 Bounds::from_corners(
2373 point(ScaledPixels(left), ScaledPixels(top)),
2374 point(ScaledPixels(right), ScaledPixels(bottom)),
2375 )
2376 }
2377
2378 #[inline]
2379 fn snap_stroke(&self, value: Pixels) -> ScaledPixels {
2380 ScaledPixels(round_stroke_to_device_pixel(value.0, self.scale_factor()))
2381 }
2382
2383 #[inline]
2384 fn snap_border_widths(&self, edges: Edges<Pixels>) -> Edges<ScaledPixels> {
2385 edges.map(|e| self.snap_stroke(*e))
2386 }
2387
2388 #[inline]
2389 fn cover_bounds(&self, bounds: Bounds<Pixels>) -> Bounds<ScaledPixels> {
2390 let scale_factor = self.scale_factor();
2391 let left = floor_to_device_pixel(bounds.left().0, scale_factor);
2392 let top = floor_to_device_pixel(bounds.top().0, scale_factor);
2393 let right = ceil_to_device_pixel(bounds.right().0, scale_factor).max(left);
2394 let bottom = ceil_to_device_pixel(bounds.bottom().0, scale_factor).max(top);
2395 Bounds::from_corners(
2396 point(ScaledPixels(left), ScaledPixels(top)),
2397 point(ScaledPixels(right), ScaledPixels(bottom)),
2398 )
2399 }
2400
2401 #[inline]
2402 fn snapped_content_mask(&self) -> ContentMask<ScaledPixels> {
2403 ContentMask {
2404 bounds: self.cover_bounds(self.content_mask().bounds),
2405 }
2406 }
2407
2408 pub fn prevent_default(&mut self) {
2411 self.default_prevented = true;
2412 }
2413
2414 pub fn default_prevented(&self) -> bool {
2416 self.default_prevented
2417 }
2418
2419 pub fn is_action_available(&self, action: &dyn Action, cx: &mut App) -> bool {
2421 let node_id =
2422 self.focus_node_id_in_rendered_frame(self.focused(cx).map(|handle| handle.id));
2423 self.rendered_frame
2424 .dispatch_tree
2425 .is_action_available(action, node_id)
2426 }
2427
2428 pub fn mouse_position(&self) -> Point<Pixels> {
2430 self.mouse_position
2431 }
2432
2433 pub fn capture_pointer(&mut self, hitbox_id: HitboxId) {
2440 self.captured_hitbox = Some(hitbox_id);
2441 }
2442
2443 pub fn release_pointer(&mut self) {
2445 self.captured_hitbox = None;
2446 }
2447
2448 pub fn captured_hitbox(&self) -> Option<HitboxId> {
2450 self.captured_hitbox
2451 }
2452
2453 pub fn modifiers(&self) -> Modifiers {
2455 self.modifiers
2456 }
2457
2458 pub fn capslock(&self) -> Capslock {
2460 self.capslock
2461 }
2462
2463 #[profiling::function]
2466 pub fn draw(&mut self, cx: &mut App) -> ArenaClearNeeded {
2467 let arena_scope = ElementArenaScope::enter();
2468 self.invalidate_entities();
2469 cx.entities.clear_accessed();
2470 debug_assert!(self.rendered_entity_stack.is_empty());
2471 self.invalidator.set_dirty(false);
2472 self.requested_autoscroll = None;
2473
2474 if let Some(input_handler) = self.platform_window.take_input_handler() {
2476 if let Some(slot) = self
2477 .rendered_frame
2478 .input_handlers
2479 .iter_mut()
2480 .rev()
2481 .find(|handler| handler.is_none())
2482 {
2483 *slot = Some(input_handler);
2484 } else {
2485 self.rendered_frame.input_handlers.push(Some(input_handler));
2486 }
2487 }
2488 self.draw_roots(cx);
2489 self.dirty_views.clear();
2490 self.next_frame.window_active = self.active.get();
2491
2492 if let Some(input_handler) = self
2494 .next_frame
2495 .input_handlers
2496 .iter_mut()
2497 .rev()
2498 .find_map(|handler| handler.take())
2499 {
2500 self.platform_window.set_input_handler(input_handler);
2501 }
2502
2503 self.layout_engine.as_mut().unwrap().clear();
2504 self.text_system().finish_frame();
2505 self.next_frame.finish(&mut self.rendered_frame);
2506
2507 self.invalidator.set_phase(DrawPhase::Focus);
2508 let previous_focus_path = self.rendered_frame.focus_path();
2509 let previous_window_active = self.rendered_frame.window_active;
2510 mem::swap(&mut self.rendered_frame, &mut self.next_frame);
2511 self.next_frame.clear();
2512 let current_focus_path = self.rendered_frame.focus_path();
2513 let current_window_active = self.rendered_frame.window_active;
2514
2515 if previous_focus_path != current_focus_path
2516 || previous_window_active != current_window_active
2517 {
2518 if !previous_focus_path.is_empty() && current_focus_path.is_empty() {
2519 self.focus_lost_listeners
2520 .clone()
2521 .retain(&(), |listener| listener(self, cx));
2522 }
2523
2524 let event = WindowFocusEvent {
2525 previous_focus_path: if previous_window_active {
2526 previous_focus_path
2527 } else {
2528 Default::default()
2529 },
2530 current_focus_path: if current_window_active {
2531 current_focus_path
2532 } else {
2533 Default::default()
2534 },
2535 };
2536 self.focus_listeners
2537 .clone()
2538 .retain(&(), |listener| listener(&event, self, cx));
2539 }
2540
2541 debug_assert!(self.rendered_entity_stack.is_empty());
2542 self.record_entities_accessed(cx);
2543 self.reset_cursor_style(cx);
2544 self.refreshing = false;
2545 self.invalidator.set_phase(DrawPhase::None);
2546 self.needs_present.set(true);
2547
2548 drop(arena_scope);
2549 ArenaClearNeeded
2550 }
2551
2552 #[cfg(any(test, feature = "test-support"))]
2554 pub fn visual_render_artifact(&self) -> crate::VisualRenderArtifact {
2555 crate::VisualRenderArtifact::from_scene(&self.rendered_frame.scene)
2556 }
2557
2558 #[cfg(any(test, feature = "test-support"))]
2560 pub fn present_for_visual_test(&mut self) {
2561 self.present();
2562 }
2563
2564 #[cfg(any(test, feature = "test-support"))]
2566 pub fn render_to_image(&self) -> anyhow::Result<image::RgbaImage> {
2567 self.platform_window
2568 .render_to_image(&self.rendered_frame.scene)
2569 }
2570
2571 fn record_entities_accessed(&mut self, cx: &mut App) {
2572 let mut entities_ref = cx.entities.accessed_entities.borrow_mut();
2573 let mut entities = mem::take(entities_ref.deref_mut());
2574 drop(entities_ref);
2575 let handle = self.handle;
2576 cx.record_entities_accessed(
2577 handle,
2578 self.invalidator.clone(),
2580 &entities,
2581 );
2582 let mut entities_ref = cx.entities.accessed_entities.borrow_mut();
2583 mem::swap(&mut entities, entities_ref.deref_mut());
2584 }
2585
2586 fn invalidate_entities(&mut self) {
2587 let mut views = self.invalidator.take_views();
2588 for entity in views.drain() {
2589 self.mark_view_dirty(entity);
2590 }
2591 self.invalidator.replace_views(views);
2592 }
2593
2594 #[profiling::function]
2595 fn present(&mut self) {
2596 self.platform_window.draw(&self.rendered_frame.scene);
2597 #[cfg(feature = "input-latency-histogram")]
2598 self.input_latency_tracker.record_frame_presented();
2599 self.needs_present.set(false);
2600 profiling::finish_frame!();
2601 }
2602
2603 #[cfg(feature = "input-latency-histogram")]
2605 pub fn input_latency_snapshot(&self) -> InputLatencySnapshot {
2606 self.input_latency_tracker.snapshot()
2607 }
2608
2609 fn draw_roots(&mut self, cx: &mut App) {
2610 self.invalidator.set_phase(DrawPhase::Prepaint);
2611 self.tooltip_bounds.take();
2612
2613 self.a11y.sync_active_flag();
2614 if self.a11y.is_active() {
2615 self.a11y.begin_frame();
2616 }
2617
2618 let _inspector_width: Pixels = rems(30.0).to_pixels(self.rem_size());
2619 let root_size = {
2620 #[cfg(any(feature = "inspector", debug_assertions))]
2621 {
2622 if self.inspector.is_some() {
2623 let mut size = self.viewport_size;
2624 size.width = (size.width - _inspector_width).max(px(0.0));
2625 size
2626 } else {
2627 self.viewport_size
2628 }
2629 }
2630 #[cfg(not(any(feature = "inspector", debug_assertions)))]
2631 {
2632 self.viewport_size
2633 }
2634 };
2635
2636 let scale_factor = self.scale_factor();
2638 let mut root_element = self.root.as_ref().unwrap().clone().into_any();
2639 let root_layout_id = root_element.request_layout(self, cx);
2640 self.layout_engine
2641 .as_mut()
2642 .unwrap()
2643 .stretch_auto_size_to_fill(root_layout_id, root_size, scale_factor);
2644 root_element.prepaint_as_root(Point::default(), root_size.into(), self, cx);
2645
2646 #[cfg(any(feature = "inspector", debug_assertions))]
2647 let inspector_element = self.prepaint_inspector(_inspector_width, cx);
2648
2649 self.prepaint_deferred_draws(cx);
2650
2651 let mut prompt_element = None;
2652 let mut active_drag_element = None;
2653 let mut tooltip_element = None;
2654 if let Some(prompt) = self.prompt.take() {
2655 let mut element = prompt.view.any_view().into_any();
2656 let prompt_layout_id = element.request_layout(self, cx);
2657 self.layout_engine
2658 .as_mut()
2659 .unwrap()
2660 .stretch_auto_size_to_fill(prompt_layout_id, root_size, scale_factor);
2661 element.prepaint_as_root(Point::default(), root_size.into(), self, cx);
2662 prompt_element = Some(element);
2663 self.prompt = Some(prompt);
2664 } else if let Some(active_drag) = cx.active_drag.take() {
2665 let mut element = active_drag.view.clone().into_any();
2666 let offset = self.mouse_position() - active_drag.cursor_offset;
2667 element.prepaint_as_root(offset, AvailableSpace::min_size(), self, cx);
2668 active_drag_element = Some(element);
2669 cx.active_drag = Some(active_drag);
2670 } else {
2671 tooltip_element = self.prepaint_tooltip(cx);
2672 }
2673
2674 self.mouse_hit_test = self.next_frame.hit_test(self.mouse_position);
2675
2676 self.invalidator.set_phase(DrawPhase::Paint);
2678 root_element.paint(self, cx);
2679
2680 #[cfg(any(feature = "inspector", debug_assertions))]
2681 self.paint_inspector(inspector_element, cx);
2682
2683 let mut sorted_deferred_draws =
2684 (0..self.next_frame.deferred_draws.len()).collect::<SmallVec<[_; 8]>>();
2685 sorted_deferred_draws.sort_by_key(|ix| self.next_frame.deferred_draws[*ix].priority);
2686 self.paint_deferred_draws(&sorted_deferred_draws, cx);
2687
2688 if let Some(mut prompt_element) = prompt_element {
2689 prompt_element.paint(self, cx);
2690 } else if let Some(mut drag_element) = active_drag_element {
2691 drag_element.paint(self, cx);
2692 } else if let Some(mut tooltip_element) = tooltip_element {
2693 tooltip_element.paint(self, cx);
2694 }
2695
2696 #[cfg(any(feature = "inspector", debug_assertions))]
2697 self.paint_inspector_hitbox(cx);
2698
2699 let a11y_active_start_of_frame = self.a11y.is_active();
2700 self.a11y.sync_active_flag();
2701 let a11y_active_end_of_frame = self.a11y.is_active();
2702
2703 if a11y_active_start_of_frame {
2704 let tree_update = self.a11y.end_frame();
2705 if a11y_active_end_of_frame {
2706 log::debug!(
2707 "Sending a11y tree update: {} nodes",
2708 tree_update.nodes.len()
2709 );
2710 self.platform_window.a11y_tree_update(tree_update);
2711 }
2712 }
2713 }
2714
2715 fn prepaint_tooltip(&mut self, cx: &mut App) -> Option<AnyElement> {
2716 for tooltip_request_index in (0..self.next_frame.tooltip_requests.len()).rev() {
2718 let Some(Some(tooltip_request)) = self
2719 .next_frame
2720 .tooltip_requests
2721 .get(tooltip_request_index)
2722 .cloned()
2723 else {
2724 log::error!("Unexpectedly absent TooltipRequest");
2725 continue;
2726 };
2727 let mut element = tooltip_request.tooltip.view.clone().into_any();
2728 let mouse_position = tooltip_request.tooltip.mouse_position;
2729 let tooltip_size = element.layout_as_root(AvailableSpace::min_size(), self, cx);
2730
2731 let mut tooltip_bounds =
2732 Bounds::new(mouse_position + point(px(1.), px(1.)), tooltip_size);
2733 let window_bounds = Bounds {
2734 origin: Point::default(),
2735 size: self.viewport_size(),
2736 };
2737
2738 if tooltip_bounds.right() > window_bounds.right() {
2739 let new_x = mouse_position.x - tooltip_bounds.size.width - px(1.);
2740 if new_x >= Pixels::ZERO {
2741 tooltip_bounds.origin.x = new_x;
2742 } else {
2743 tooltip_bounds.origin.x = cmp::max(
2744 Pixels::ZERO,
2745 tooltip_bounds.origin.x - tooltip_bounds.right() - window_bounds.right(),
2746 );
2747 }
2748 }
2749
2750 if tooltip_bounds.bottom() > window_bounds.bottom() {
2751 let new_y = mouse_position.y - tooltip_bounds.size.height - px(1.);
2752 if new_y >= Pixels::ZERO {
2753 tooltip_bounds.origin.y = new_y;
2754 } else {
2755 tooltip_bounds.origin.y = cmp::max(
2756 Pixels::ZERO,
2757 tooltip_bounds.origin.y - tooltip_bounds.bottom() - window_bounds.bottom(),
2758 );
2759 }
2760 }
2761
2762 let is_visible =
2766 (tooltip_request.tooltip.check_visible_and_update)(tooltip_bounds, self, cx);
2767 if !is_visible {
2768 continue;
2769 }
2770
2771 self.with_absolute_element_offset(tooltip_bounds.origin, |window| {
2772 element.prepaint(window, cx)
2773 });
2774
2775 self.tooltip_bounds = Some(TooltipBounds {
2776 id: tooltip_request.id,
2777 bounds: tooltip_bounds,
2778 });
2779 return Some(element);
2780 }
2781 None
2782 }
2783
2784 fn prepaint_deferred_draws(&mut self, cx: &mut App) {
2785 assert_eq!(self.element_id_stack.len(), 0);
2786
2787 let mut round_start = 0;
2790 let mut depth = 0;
2791 loop {
2792 let round_end = self.next_frame.deferred_draws.len();
2793 if round_start == round_end {
2794 break;
2795 }
2796
2797 assert!(depth < 10, "Exceeded maximum (10) deferred depth");
2798 depth += 1;
2799
2800 let mut traversal_order = (round_start..round_end).collect::<SmallVec<[usize; 8]>>();
2801 traversal_order.sort_by_key(|ix| self.next_frame.deferred_draws[*ix].priority);
2802
2803 for deferred_draw_ix in traversal_order {
2804 let (element, parent_node, current_view, absolute_offset, prepaint_range) = {
2805 let deferred_draw = &mut self.next_frame.deferred_draws[deferred_draw_ix];
2806 self.element_id_stack
2807 .clone_from(&deferred_draw.element_id_stack);
2808 self.text_style_stack
2809 .clone_from(&deferred_draw.text_style_stack);
2810 (
2811 deferred_draw.element.take(),
2812 deferred_draw.parent_node,
2813 deferred_draw.current_view,
2814 deferred_draw.absolute_offset,
2815 deferred_draw.prepaint_range.clone(),
2816 )
2817 };
2818 self.next_frame.dispatch_tree.set_active_node(parent_node);
2819
2820 let prepaint_start = self.prepaint_index();
2821 if let Some(mut element) = element {
2822 self.with_rendered_view(current_view, |window| {
2823 window.with_absolute_element_offset(absolute_offset, |window| {
2824 element.prepaint(window, cx)
2825 });
2826 });
2827 self.next_frame.deferred_draws[deferred_draw_ix].element = Some(element);
2828 } else {
2829 self.reuse_prepaint(prepaint_range);
2830 }
2831 let prepaint_end = self.prepaint_index();
2832 self.next_frame.deferred_draws[deferred_draw_ix].prepaint_range =
2833 prepaint_start..prepaint_end;
2834 }
2835
2836 self.element_id_stack.clear();
2837 self.text_style_stack.clear();
2838 round_start = round_end;
2839 }
2840 }
2841
2842 fn paint_deferred_draws(&mut self, deferred_draw_indices: &[usize], cx: &mut App) {
2843 assert_eq!(self.element_id_stack.len(), 0);
2844
2845 let mut deferred_draws = mem::take(&mut self.next_frame.deferred_draws);
2846 for deferred_draw_ix in deferred_draw_indices {
2847 let mut deferred_draw = &mut deferred_draws[*deferred_draw_ix];
2848 self.element_id_stack
2849 .clone_from(&deferred_draw.element_id_stack);
2850 self.next_frame
2851 .dispatch_tree
2852 .set_active_node(deferred_draw.parent_node);
2853
2854 let paint_start = self.paint_index();
2855 if let Some(element) = deferred_draw.element.as_mut() {
2856 self.with_rendered_view(deferred_draw.current_view, |window| {
2857 element.paint(window, cx);
2858 })
2859 } else {
2860 self.reuse_paint(deferred_draw.paint_range.clone());
2861 }
2862 let paint_end = self.paint_index();
2863 deferred_draw.paint_range = paint_start..paint_end;
2864 }
2865 self.next_frame.deferred_draws = deferred_draws;
2866 self.element_id_stack.clear();
2867 }
2868
2869 pub(crate) fn prepaint_index(&self) -> PrepaintStateIndex {
2870 PrepaintStateIndex {
2871 hitboxes_index: self.next_frame.hitboxes.len(),
2872 tooltips_index: self.next_frame.tooltip_requests.len(),
2873 deferred_draws_index: self.next_frame.deferred_draws.len(),
2874 dispatch_tree_index: self.next_frame.dispatch_tree.len(),
2875 accessed_element_states_index: self.next_frame.accessed_element_states.len(),
2876 line_layout_index: self.text_system.layout_index(),
2877 }
2878 }
2879
2880 pub(crate) fn reuse_prepaint(&mut self, range: Range<PrepaintStateIndex>) {
2881 self.next_frame.hitboxes.extend(
2882 self.rendered_frame.hitboxes[range.start.hitboxes_index..range.end.hitboxes_index]
2883 .iter()
2884 .cloned(),
2885 );
2886 self.next_frame.tooltip_requests.extend(
2887 self.rendered_frame.tooltip_requests
2888 [range.start.tooltips_index..range.end.tooltips_index]
2889 .iter_mut()
2890 .map(|request| request.take()),
2891 );
2892 self.next_frame.accessed_element_states.extend(
2893 self.rendered_frame.accessed_element_states[range.start.accessed_element_states_index
2894 ..range.end.accessed_element_states_index]
2895 .iter()
2896 .map(|(id, type_id)| (GlobalElementId(id.0.clone()), *type_id)),
2897 );
2898 self.text_system
2899 .reuse_layouts(range.start.line_layout_index..range.end.line_layout_index);
2900
2901 let reused_subtree = self.next_frame.dispatch_tree.reuse_subtree(
2902 range.start.dispatch_tree_index..range.end.dispatch_tree_index,
2903 &mut self.rendered_frame.dispatch_tree,
2904 self.focus,
2905 );
2906
2907 if reused_subtree.contains_focus() {
2908 self.next_frame.focus = self.focus;
2909 }
2910
2911 self.next_frame.deferred_draws.extend(
2912 self.rendered_frame.deferred_draws
2913 [range.start.deferred_draws_index..range.end.deferred_draws_index]
2914 .iter()
2915 .map(|deferred_draw| DeferredDraw {
2916 current_view: deferred_draw.current_view,
2917 parent_node: reused_subtree.refresh_node_id(deferred_draw.parent_node),
2918 element_id_stack: deferred_draw.element_id_stack.clone(),
2919 text_style_stack: deferred_draw.text_style_stack.clone(),
2920 priority: deferred_draw.priority,
2921 element: None,
2922 absolute_offset: deferred_draw.absolute_offset,
2923 prepaint_range: deferred_draw.prepaint_range.clone(),
2924 paint_range: deferred_draw.paint_range.clone(),
2925 }),
2926 );
2927 }
2928
2929 pub(crate) fn paint_index(&self) -> PaintIndex {
2930 PaintIndex {
2931 scene_index: self.next_frame.scene.len(),
2932 mouse_listeners_index: self.next_frame.mouse_listeners.len(),
2933 input_handlers_index: self.next_frame.input_handlers.len(),
2934 cursor_styles_index: self.next_frame.cursor_styles.len(),
2935 accessed_element_states_index: self.next_frame.accessed_element_states.len(),
2936 tab_handle_index: self.next_frame.tab_stops.paint_index(),
2937 line_layout_index: self.text_system.layout_index(),
2938 }
2939 }
2940
2941 pub(crate) fn reuse_paint(&mut self, range: Range<PaintIndex>) {
2942 self.next_frame.cursor_styles.extend(
2943 self.rendered_frame.cursor_styles
2944 [range.start.cursor_styles_index..range.end.cursor_styles_index]
2945 .iter()
2946 .cloned(),
2947 );
2948 self.next_frame.input_handlers.extend(
2949 self.rendered_frame.input_handlers
2950 [range.start.input_handlers_index..range.end.input_handlers_index]
2951 .iter_mut()
2952 .map(|handler| handler.take()),
2953 );
2954 self.next_frame.mouse_listeners.extend(
2955 self.rendered_frame.mouse_listeners
2956 [range.start.mouse_listeners_index..range.end.mouse_listeners_index]
2957 .iter_mut()
2958 .map(|listener| listener.take()),
2959 );
2960 self.next_frame.accessed_element_states.extend(
2961 self.rendered_frame.accessed_element_states[range.start.accessed_element_states_index
2962 ..range.end.accessed_element_states_index]
2963 .iter()
2964 .map(|(id, type_id)| (GlobalElementId(id.0.clone()), *type_id)),
2965 );
2966 self.next_frame.tab_stops.replay(
2967 &self.rendered_frame.tab_stops.insertion_history
2968 [range.start.tab_handle_index..range.end.tab_handle_index],
2969 );
2970
2971 self.text_system
2972 .reuse_layouts(range.start.line_layout_index..range.end.line_layout_index);
2973 self.next_frame.scene.replay(
2974 range.start.scene_index..range.end.scene_index,
2975 &self.rendered_frame.scene,
2976 );
2977 }
2978
2979 pub fn with_text_style<F, R>(&mut self, style: Option<TextStyleRefinement>, f: F) -> R
2983 where
2984 F: FnOnce(&mut Self) -> R,
2985 {
2986 self.invalidator.debug_assert_paint_or_prepaint();
2987 if let Some(style) = style {
2988 self.text_style_stack.push(style);
2989 let result = f(self);
2990 self.text_style_stack.pop();
2991 result
2992 } else {
2993 f(self)
2994 }
2995 }
2996
2997 pub fn set_cursor_style(&mut self, style: CursorStyle, hitbox: &Hitbox) {
3000 self.invalidator.debug_assert_paint();
3001 self.next_frame.cursor_styles.push(CursorStyleRequest {
3002 hitbox_id: Some(hitbox.id),
3003 style,
3004 });
3005 }
3006
3007 pub fn set_window_cursor_style(&mut self, style: CursorStyle) {
3012 self.invalidator.debug_assert_paint();
3013 self.next_frame.cursor_styles.push(CursorStyleRequest {
3014 hitbox_id: None,
3015 style,
3016 })
3017 }
3018
3019 pub fn set_tooltip(&mut self, tooltip: AnyTooltip) -> TooltipId {
3022 self.invalidator.debug_assert_prepaint();
3023 let id = TooltipId(post_inc(&mut self.next_tooltip_id.0));
3024 self.next_frame
3025 .tooltip_requests
3026 .push(Some(TooltipRequest { id, tooltip }));
3027 id
3028 }
3029
3030 pub fn with_content_mask<R>(
3033 &mut self,
3034 mask: Option<ContentMask<Pixels>>,
3035 f: impl FnOnce(&mut Self) -> R,
3036 ) -> R {
3037 self.invalidator.debug_assert_paint_or_prepaint();
3038 if let Some(mask) = mask {
3039 let mask = mask.intersect(&self.content_mask());
3040 self.content_mask_stack.push(mask);
3041 let result = f(self);
3042 self.content_mask_stack.pop();
3043 result
3044 } else {
3045 f(self)
3046 }
3047 }
3048
3049 pub fn with_element_offset<R>(
3052 &mut self,
3053 offset: Point<Pixels>,
3054 f: impl FnOnce(&mut Self) -> R,
3055 ) -> R {
3056 self.invalidator.debug_assert_prepaint();
3057
3058 if offset.is_zero() {
3059 return f(self);
3060 };
3061
3062 let abs_offset = self.element_offset() + offset;
3063 self.with_absolute_element_offset(abs_offset, f)
3064 }
3065
3066 pub fn with_absolute_element_offset<R>(
3070 &mut self,
3071 offset: Point<Pixels>,
3072 f: impl FnOnce(&mut Self) -> R,
3073 ) -> R {
3074 self.invalidator.debug_assert_prepaint();
3075 self.element_offset_stack.push(offset);
3076 let result = f(self);
3077 self.element_offset_stack.pop();
3078 result
3079 }
3080
3081 pub(crate) fn with_element_opacity<R>(
3082 &mut self,
3083 opacity: Option<f32>,
3084 f: impl FnOnce(&mut Self) -> R,
3085 ) -> R {
3086 self.invalidator.debug_assert_paint_or_prepaint();
3087
3088 let Some(opacity) = opacity else {
3089 return f(self);
3090 };
3091
3092 let previous_opacity = self.element_opacity;
3093 self.element_opacity = previous_opacity * opacity;
3094 let result = f(self);
3095 self.element_opacity = previous_opacity;
3096 result
3097 }
3098
3099 pub fn transact<T, U>(&mut self, f: impl FnOnce(&mut Self) -> Result<T, U>) -> Result<T, U> {
3105 self.invalidator.debug_assert_prepaint();
3106 let index = self.prepaint_index();
3107 let result = f(self);
3108 if result.is_err() {
3109 self.next_frame.hitboxes.truncate(index.hitboxes_index);
3110 self.next_frame
3111 .tooltip_requests
3112 .truncate(index.tooltips_index);
3113 self.next_frame
3114 .deferred_draws
3115 .truncate(index.deferred_draws_index);
3116 self.next_frame
3117 .dispatch_tree
3118 .truncate(index.dispatch_tree_index);
3119 self.next_frame
3120 .accessed_element_states
3121 .truncate(index.accessed_element_states_index);
3122 self.text_system.truncate_layouts(index.line_layout_index);
3123 }
3124 result
3125 }
3126
3127 pub fn request_autoscroll(&mut self, bounds: Bounds<Pixels>) {
3133 self.invalidator.debug_assert_prepaint();
3134 self.requested_autoscroll = Some(bounds);
3135 }
3136
3137 pub fn take_autoscroll(&mut self) -> Option<Bounds<Pixels>> {
3140 self.invalidator.debug_assert_prepaint();
3141 self.requested_autoscroll.take()
3142 }
3143
3144 pub fn use_asset<A: Asset>(&mut self, source: &A::Source, cx: &mut App) -> Option<A::Output> {
3150 let (task, is_first) = cx.fetch_asset::<A>(source);
3151 task.clone().now_or_never().or_else(|| {
3152 if is_first {
3153 let entity_id = self.current_view();
3154 self.spawn(cx, {
3155 let task = task.clone();
3156 async move |cx| {
3157 task.await;
3158
3159 cx.on_next_frame(move |_, cx| {
3160 cx.notify(entity_id);
3161 });
3162 }
3163 })
3164 .detach();
3165 }
3166
3167 None
3168 })
3169 }
3170
3171 pub fn get_asset<A: Asset>(&mut self, source: &A::Source, cx: &mut App) -> Option<A::Output> {
3177 let (task, _) = cx.fetch_asset::<A>(source);
3178 task.now_or_never()
3179 }
3180 pub fn element_offset(&self) -> Point<Pixels> {
3183 self.invalidator.debug_assert_prepaint();
3184 self.element_offset_stack
3185 .last()
3186 .copied()
3187 .unwrap_or_default()
3188 }
3189
3190 #[inline]
3193 pub(crate) fn element_opacity(&self) -> f32 {
3194 self.invalidator.debug_assert_paint_or_prepaint();
3195 self.element_opacity
3196 }
3197
3198 pub fn content_mask(&self) -> ContentMask<Pixels> {
3200 self.invalidator.debug_assert_paint_or_prepaint();
3201 self.content_mask_stack
3202 .last()
3203 .cloned()
3204 .unwrap_or_else(|| ContentMask {
3205 bounds: Bounds {
3206 origin: Point::default(),
3207 size: self.viewport_size,
3208 },
3209 })
3210 }
3211
3212 pub fn with_element_namespace<R>(
3215 &mut self,
3216 element_id: impl Into<ElementId>,
3217 f: impl FnOnce(&mut Self) -> R,
3218 ) -> R {
3219 self.element_id_stack.push(element_id.into());
3220 let result = f(self);
3221 self.element_id_stack.pop();
3222 result
3223 }
3224
3225 pub fn use_keyed_state<S: 'static>(
3227 &mut self,
3228 key: impl Into<ElementId>,
3229 cx: &mut App,
3230 init: impl FnOnce(&mut Self, &mut Context<S>) -> S,
3231 ) -> Entity<S> {
3232 let current_view = self.current_view();
3233 self.with_global_id(key.into(), |global_id, window| {
3234 window.with_element_state(global_id, |state: Option<Entity<S>>, window| {
3235 if let Some(state) = state {
3236 (state.clone(), state)
3237 } else {
3238 let new_state = cx.new(|cx| init(window, cx));
3239 cx.observe(&new_state, move |_, cx| {
3240 cx.notify(current_view);
3241 })
3242 .detach();
3243 (new_state.clone(), new_state)
3244 }
3245 })
3246 })
3247 }
3248
3249 pub fn with_id<R>(&mut self, id: impl Into<ElementId>, f: impl FnOnce(&mut Self) -> R) -> R {
3251 self.with_global_id(id.into(), |_, window| f(window))
3252 }
3253
3254 #[track_caller]
3260 pub fn use_state<S: 'static>(
3261 &mut self,
3262 cx: &mut App,
3263 init: impl FnOnce(&mut Self, &mut Context<S>) -> S,
3264 ) -> Entity<S> {
3265 self.use_keyed_state(
3266 ElementId::CodeLocation(*core::panic::Location::caller()),
3267 cx,
3268 init,
3269 )
3270 }
3271
3272 pub fn with_element_state<S, R>(
3277 &mut self,
3278 global_id: &GlobalElementId,
3279 f: impl FnOnce(Option<S>, &mut Self) -> (R, S),
3280 ) -> R
3281 where
3282 S: 'static,
3283 {
3284 self.invalidator.debug_assert_paint_or_prepaint();
3285
3286 let key = (GlobalElementId(global_id.0.clone()), TypeId::of::<S>());
3287 self.next_frame
3288 .accessed_element_states
3289 .push((GlobalElementId(key.0.clone()), TypeId::of::<S>()));
3290
3291 if let Some(any) = self
3292 .next_frame
3293 .element_states
3294 .remove(&key)
3295 .or_else(|| self.rendered_frame.element_states.remove(&key))
3296 {
3297 let ElementStateBox {
3298 inner,
3299 #[cfg(debug_assertions)]
3300 type_name,
3301 } = any;
3302 let mut state_box = inner
3304 .downcast::<Option<S>>()
3305 .map_err(|_| {
3306 #[cfg(debug_assertions)]
3307 {
3308 anyhow::anyhow!(
3309 "invalid element state type for id, requested {:?}, actual: {:?}",
3310 std::any::type_name::<S>(),
3311 type_name
3312 )
3313 }
3314
3315 #[cfg(not(debug_assertions))]
3316 {
3317 anyhow::anyhow!(
3318 "invalid element state type for id, requested {:?}",
3319 std::any::type_name::<S>(),
3320 )
3321 }
3322 })
3323 .unwrap();
3324
3325 let state = state_box.take().expect(
3326 "reentrant call to with_element_state for the same state type and element id",
3327 );
3328 let (result, state) = f(Some(state), self);
3329 state_box.replace(state);
3330 self.next_frame.element_states.insert(
3331 key,
3332 ElementStateBox {
3333 inner: state_box,
3334 #[cfg(debug_assertions)]
3335 type_name,
3336 },
3337 );
3338 result
3339 } else {
3340 let (result, state) = f(None, self);
3341 self.next_frame.element_states.insert(
3342 key,
3343 ElementStateBox {
3344 inner: Box::new(Some(state)),
3345 #[cfg(debug_assertions)]
3346 type_name: std::any::type_name::<S>(),
3347 },
3348 );
3349 result
3350 }
3351 }
3352
3353 pub fn with_optional_element_state<S, R>(
3360 &mut self,
3361 global_id: Option<&GlobalElementId>,
3362 f: impl FnOnce(Option<Option<S>>, &mut Self) -> (R, Option<S>),
3363 ) -> R
3364 where
3365 S: 'static,
3366 {
3367 self.invalidator.debug_assert_paint_or_prepaint();
3368
3369 if let Some(global_id) = global_id {
3370 self.with_element_state(global_id, |state, cx| {
3371 let (result, state) = f(Some(state), cx);
3372 let state =
3373 state.expect("you must return some state when you pass some element id");
3374 (result, state)
3375 })
3376 } else {
3377 let (result, state) = f(None, self);
3378 debug_assert!(
3379 state.is_none(),
3380 "you must not return an element state when passing None for the global id"
3381 );
3382 result
3383 }
3384 }
3385
3386 #[inline]
3388 pub fn with_tab_group<R>(&mut self, index: Option<isize>, f: impl FnOnce(&mut Self) -> R) -> R {
3389 if let Some(index) = index {
3390 self.next_frame.tab_stops.begin_group(index);
3391 let result = f(self);
3392 self.next_frame.tab_stops.end_group();
3393 result
3394 } else {
3395 f(self)
3396 }
3397 }
3398
3399 pub fn defer_draw(
3405 &mut self,
3406 element: AnyElement,
3407 absolute_offset: Point<Pixels>,
3408 priority: usize,
3409 ) {
3410 self.invalidator.debug_assert_prepaint();
3411 let parent_node = self.next_frame.dispatch_tree.active_node_id().unwrap();
3412 self.next_frame.deferred_draws.push(DeferredDraw {
3413 current_view: self.current_view(),
3414 parent_node,
3415 element_id_stack: self.element_id_stack.clone(),
3416 text_style_stack: self.text_style_stack.clone(),
3417 priority,
3418 element: Some(element),
3419 absolute_offset,
3420 prepaint_range: PrepaintStateIndex::default()..PrepaintStateIndex::default(),
3421 paint_range: PaintIndex::default()..PaintIndex::default(),
3422 });
3423 }
3424
3425 pub fn paint_layer<R>(&mut self, bounds: Bounds<Pixels>, f: impl FnOnce(&mut Self) -> R) -> R {
3431 self.invalidator.debug_assert_paint();
3432
3433 let content_mask = self.content_mask();
3434 let clipped_bounds = bounds.intersect(&content_mask.bounds);
3435 if !clipped_bounds.is_empty() {
3436 self.next_frame
3437 .scene
3438 .push_layer(self.cover_bounds(clipped_bounds));
3439 }
3440
3441 let result = f(self);
3442
3443 if !clipped_bounds.is_empty() {
3444 self.next_frame.scene.pop_layer();
3445 }
3446
3447 result
3448 }
3449
3450 pub fn paint_shadows(
3454 &mut self,
3455 bounds: Bounds<Pixels>,
3456 corner_radii: Corners<Pixels>,
3457 shadows: &[BoxShadow],
3458 ) {
3459 self.invalidator.debug_assert_paint();
3460
3461 let scale_factor = self.scale_factor();
3462 let content_mask = self.snapped_content_mask();
3463 let opacity = self.element_opacity();
3464 for shadow in shadows {
3465 let shadow_bounds = if shadow.inset {
3466 bounds.contract(shadow.spread_radius)
3467 } else {
3468 (bounds + shadow.offset).dilate(shadow.spread_radius)
3469 };
3470 self.next_frame.scene.insert_primitive(Shadow {
3471 order: 0,
3472 blur_radius: shadow.blur_radius.scale(scale_factor),
3473 bounds: if shadow.inset {
3474 self.snap_bounds(shadow_bounds)
3475 } else {
3476 self.cover_bounds(shadow_bounds)
3477 },
3478 content_mask: if shadow.inset {
3479 ContentMask {
3480 bounds: self.snap_bounds(bounds),
3481 }
3482 } else {
3483 content_mask
3484 },
3485 corner_radii: corner_radii.scale(scale_factor),
3486 color: shadow.color.opacity(opacity),
3487 inset: if shadow.inset { 1 } else { 0 },
3488 _pad_end: 0,
3489 });
3490 }
3491 }
3492
3493 pub fn paint_quad(&mut self, quad: PaintQuad) {
3503 self.invalidator.debug_assert_paint();
3504
3505 let opacity = self.element_opacity();
3506 let snapped_bounds = self.snap_bounds(quad.bounds);
3507 let snapped_border_widths = self.snap_border_widths(quad.border_widths);
3508 let quad = Quad {
3509 order: 0,
3510 bounds: snapped_bounds,
3511 content_mask: self.snapped_content_mask(),
3512 background: quad.background.opacity(opacity),
3513 border_color: quad.border_color.opacity(opacity),
3514 corner_radii: quad.corner_radii.scale(self.scale_factor()),
3515 border_widths: snapped_border_widths,
3516 border_style: quad.border_style,
3517 continuous_corners: if quad.continuous_corners { 1 } else { 0 },
3518 _pad_before_transform: 0,
3519 transform: quad.transform,
3520 blend_mode: quad.blend_mode as u32,
3521 _pad_end: 0,
3522 };
3523
3524 if !quad.background.is_transparent() {
3525 self.next_frame.scene.insert_primitive(quad);
3526 return;
3527 }
3528
3529 let Some(strips) =
3530 border_only_quad_strips(quad.bounds, quad.border_widths, quad.corner_radii)
3531 else {
3532 self.next_frame.scene.insert_primitive(quad);
3533 return;
3534 };
3535
3536 for strip in strips {
3537 let mask_bounds = quad.content_mask.bounds.intersect(&strip);
3538 if !mask_bounds.is_empty() {
3539 self.next_frame.scene.insert_primitive(Quad {
3540 content_mask: ContentMask {
3541 bounds: mask_bounds,
3542 },
3543 ..quad
3544 });
3545 }
3546 }
3547 }
3548
3549 pub fn paint_path(&mut self, mut path: Path<Pixels>, color: impl Into<Background>) {
3553 self.invalidator.debug_assert_paint();
3554
3555 let scale_factor = self.scale_factor();
3556 let content_mask = self.content_mask();
3557 let opacity = self.element_opacity();
3558 path.content_mask = content_mask;
3559 let color: Background = color.into();
3560 path.color = color.opacity(opacity);
3561 self.next_frame
3562 .scene
3563 .insert_primitive(path.scale(scale_factor));
3564 }
3565
3566 pub fn paint_underline(
3570 &mut self,
3571 origin: Point<Pixels>,
3572 width: Pixels,
3573 style: &UnderlineStyle,
3574 ) {
3575 self.invalidator.debug_assert_paint();
3576
3577 let scale_factor = self.scale_factor();
3578 let thickness = self.snap_stroke(style.thickness);
3579 let height = if style.wavy {
3580 ScaledPixels(thickness.0 * 3.)
3581 } else {
3582 thickness
3583 };
3584 let bounds = Bounds {
3585 origin: origin.map(|c| ScaledPixels(round_to_device_pixel(c.0, scale_factor))),
3586 size: size(self.snap_stroke(width), height),
3587 };
3588 let element_opacity = self.element_opacity();
3589
3590 self.next_frame.scene.insert_primitive(Underline {
3591 order: 0,
3592 pad: 0,
3593 bounds,
3594 content_mask: self.snapped_content_mask(),
3595 color: style.color.unwrap_or_default().opacity(element_opacity),
3596 thickness,
3597 wavy: style.wavy.into(),
3598 });
3599 }
3600
3601 pub fn paint_strikethrough(
3605 &mut self,
3606 origin: Point<Pixels>,
3607 width: Pixels,
3608 style: &StrikethroughStyle,
3609 ) {
3610 self.invalidator.debug_assert_paint();
3611
3612 let scale_factor = self.scale_factor();
3613 let height = style.thickness;
3614 let bounds = Bounds {
3615 origin: origin.map(|c| ScaledPixels(round_to_device_pixel(c.0, scale_factor))),
3616 size: size(self.snap_stroke(width), self.snap_stroke(height)),
3617 };
3618 let opacity = self.element_opacity();
3619
3620 self.next_frame.scene.insert_primitive(Underline {
3621 order: 0,
3622 pad: 0,
3623 bounds,
3624 content_mask: self.snapped_content_mask(),
3625 thickness: self.snap_stroke(style.thickness),
3626 color: style.color.unwrap_or_default().opacity(opacity),
3627 wavy: false.into(),
3628 });
3629 }
3630
3631 pub fn paint_glyph(
3640 &mut self,
3641 origin: Point<Pixels>,
3642 font_id: FontId,
3643 glyph_id: GlyphId,
3644 font_size: Pixels,
3645 color: Hsla,
3646 ) -> Result<()> {
3647 self.invalidator.debug_assert_paint();
3648
3649 let element_opacity = self.element_opacity();
3650 let scale_factor = self.scale_factor();
3651 let glyph_origin = origin.scale(scale_factor);
3652
3653 let quantized_origin = Point::new(
3654 round_half_toward_zero(glyph_origin.x.0 * SUBPIXEL_VARIANTS_X as f32)
3655 / SUBPIXEL_VARIANTS_X as f32,
3656 round_half_toward_zero(glyph_origin.y.0 * SUBPIXEL_VARIANTS_Y as f32)
3657 / SUBPIXEL_VARIANTS_Y as f32,
3658 );
3659 let subpixel_variant = Point::new(
3660 (quantized_origin.x.fract() * SUBPIXEL_VARIANTS_X as f32) as u8,
3661 (quantized_origin.y.fract() * SUBPIXEL_VARIANTS_Y as f32) as u8,
3662 );
3663 let integer_origin = quantized_origin.map(|c| ScaledPixels(c.trunc()));
3664 let dilation = self.text_system().glyph_dilation_for_color(color);
3665 let params = RenderGlyphParams {
3666 font_id,
3667 glyph_id,
3668 font_size,
3669 subpixel_variant,
3670 scale_factor,
3671 is_emoji: false,
3672 dilation,
3673 };
3674
3675 let raster_bounds = self.text_system().raster_bounds(¶ms)?;
3676 if !raster_bounds.is_zero() {
3677 let tile = self
3678 .sprite_atlas
3679 .get_or_insert_with(¶ms.clone().into(), &mut || {
3680 let (size, bytes) = self.text_system().rasterize_glyph(¶ms)?;
3681 Ok(Some((size, Cow::Owned(bytes))))
3682 })?
3683 .expect("Callback above only errors or returns Some");
3684 let bounds = Bounds {
3685 origin: integer_origin + raster_bounds.origin.map(Into::into),
3686 size: tile.bounds.size.map(Into::into),
3687 };
3688 let content_mask = self.snapped_content_mask();
3689 self.next_frame.scene.insert_primitive(MonochromeSprite {
3690 order: 0,
3691 pad: 0,
3692 bounds,
3693 content_mask,
3694 color: color.opacity(element_opacity),
3695 tile,
3696 transformation: TransformationMatrix::unit(),
3697 });
3698 }
3699 Ok(())
3700 }
3701
3702 pub fn paint_emoji(
3711 &mut self,
3712 origin: Point<Pixels>,
3713 font_id: FontId,
3714 glyph_id: GlyphId,
3715 font_size: Pixels,
3716 ) -> Result<()> {
3717 self.invalidator.debug_assert_paint();
3718
3719 let scale_factor = self.scale_factor();
3720 let glyph_origin = origin.scale(scale_factor);
3721 let integer_origin = glyph_origin.map(|c| ScaledPixels(round_half_toward_zero(c.0)));
3722 let params = RenderGlyphParams {
3723 font_id,
3724 glyph_id,
3725 font_size,
3726 subpixel_variant: Default::default(),
3727 scale_factor,
3728 is_emoji: true,
3729 dilation: 0, };
3731
3732 let raster_bounds = self.text_system().raster_bounds(¶ms)?;
3733 if !raster_bounds.is_zero() {
3734 let tile = self
3735 .sprite_atlas
3736 .get_or_insert_with(¶ms.clone().into(), &mut || {
3737 let (size, bytes) = self.text_system().rasterize_glyph(¶ms)?;
3738 Ok(Some((size, Cow::Owned(bytes))))
3739 })?
3740 .expect("Callback above only errors or returns Some");
3741
3742 let bounds = Bounds {
3743 origin: integer_origin + raster_bounds.origin.map(Into::into),
3744 size: tile.bounds.size.map(Into::into),
3745 };
3746 let content_mask = self.snapped_content_mask();
3747 let opacity = self.element_opacity();
3748
3749 self.next_frame.scene.insert_primitive(PolychromeSprite {
3750 order: 0,
3751 pad: 0,
3752 grayscale: false.into(),
3753 bounds,
3754 corner_radii: Default::default(),
3755 content_mask,
3756 tile,
3757 opacity,
3758 });
3759 }
3760 Ok(())
3761 }
3762
3763 pub fn paint_svg(
3767 &mut self,
3768 bounds: Bounds<Pixels>,
3769 path: SharedString,
3770 transformation: TransformationMatrix,
3771 color: Hsla,
3772 cx: &App,
3773 ) -> Result<()> {
3774 self.invalidator.debug_assert_paint();
3775
3776 let element_opacity = self.element_opacity();
3777 let bounds = self.snap_bounds(bounds);
3778 let params = RenderSvgParams {
3779 path,
3780 size: bounds.size.map(|pixels| {
3781 DevicePixels::from((pixels.0 * SMOOTH_SVG_SCALE_FACTOR).ceil() as i32)
3782 }),
3783 };
3784
3785 let Some(tile) =
3786 self.sprite_atlas
3787 .get_or_insert_with(¶ms.clone().into(), &mut || {
3788 let Some((size, bytes)) = cx.svg_renderer.render(¶ms)? else {
3789 return Ok(None);
3790 };
3791 Ok(Some((size, Cow::Owned(bytes))))
3792 })?
3793 else {
3794 return Ok(());
3795 };
3796 let content_mask = self.snapped_content_mask();
3797 let svg_bounds = Bounds {
3798 origin: bounds.center()
3799 - Point::new(
3800 ScaledPixels(tile.bounds.size.width.0 as f32 / SMOOTH_SVG_SCALE_FACTOR / 2.),
3801 ScaledPixels(tile.bounds.size.height.0 as f32 / SMOOTH_SVG_SCALE_FACTOR / 2.),
3802 ),
3803 size: tile
3804 .bounds
3805 .size
3806 .map(|value| ScaledPixels(value.0 as f32 / SMOOTH_SVG_SCALE_FACTOR)),
3807 };
3808 let final_bounds = svg_bounds
3809 .map_origin(|origin| ScaledPixels(round_half_toward_zero(origin.0)))
3810 .map_size(|size| size.ceil());
3811
3812 self.next_frame.scene.insert_primitive(MonochromeSprite {
3813 order: 0,
3814 pad: 0,
3815 bounds: final_bounds,
3816 content_mask,
3817 color: color.opacity(element_opacity),
3818 tile,
3819 transformation,
3820 });
3821
3822 Ok(())
3823 }
3824
3825 pub fn paint_image(
3830 &mut self,
3831 bounds: Bounds<Pixels>,
3832 image_bounds: Bounds<Pixels>,
3833 corner_radii: Corners<Pixels>,
3834 data: Arc<RenderImage>,
3835 frame_index: usize,
3836 grayscale: bool,
3837 ) -> Result<()> {
3838 self.invalidator.debug_assert_paint();
3839
3840 let visible_bounds = bounds.intersect(&image_bounds);
3841 if visible_bounds.size.width <= Pixels::ZERO || visible_bounds.size.height <= Pixels::ZERO {
3842 return Ok(());
3843 }
3844 if image_bounds.size.width <= Pixels::ZERO || image_bounds.size.height <= Pixels::ZERO {
3845 return Ok(());
3846 }
3847
3848 let params = RenderImageParams {
3849 image_id: data.id,
3850 frame_index,
3851 };
3852 let Some(bytes) = data.as_bytes(frame_index) else {
3853 return Ok(());
3854 };
3855 let image_size = data.size(frame_index);
3856
3857 let tile = self
3858 .sprite_atlas
3859 .get_or_insert_with(¶ms.into(), &mut || {
3860 Ok(Some((image_size, Cow::Borrowed(bytes))))
3861 })?
3862 .expect("Callback above only returns Some");
3863
3864 let visible_bounds_snapped = self.snap_bounds(visible_bounds);
3865 let sub_tile = if visible_bounds == image_bounds {
3866 tile
3867 } else {
3868 let x_offset_ratio =
3869 (visible_bounds.origin.x - image_bounds.origin.x) / image_bounds.size.width;
3870 let y_offset_ratio =
3871 (visible_bounds.origin.y - image_bounds.origin.y) / image_bounds.size.height;
3872 let width_ratio = visible_bounds.size.width / image_bounds.size.width;
3873 let height_ratio = visible_bounds.size.height / image_bounds.size.height;
3874
3875 let tile_origin_x = tile.bounds.origin.x.0;
3876 let tile_origin_y = tile.bounds.origin.y.0;
3877 let tile_width = tile.bounds.size.width.0;
3878 let tile_height = tile.bounds.size.height.0;
3879
3880 let sub_origin_x = tile_origin_x + (x_offset_ratio * tile_width as f32).round() as i32;
3881 let sub_origin_y = tile_origin_y + (y_offset_ratio * tile_height as f32).round() as i32;
3882 let sub_width = (width_ratio * tile_width as f32).round() as i32;
3883 let sub_height = (height_ratio * tile_height as f32).round() as i32;
3884
3885 let max_x = tile_origin_x + tile_width;
3886 let max_y = tile_origin_y + tile_height;
3887 let clamped_origin_x = sub_origin_x.clamp(tile_origin_x, max_x);
3888 let clamped_origin_y = sub_origin_y.clamp(tile_origin_y, max_y);
3889 let clamped_width = sub_width.min(max_x - clamped_origin_x).max(0);
3890 let clamped_height = sub_height.min(max_y - clamped_origin_y).max(0);
3891
3892 AtlasTile {
3893 bounds: Bounds {
3894 origin: point(
3895 DevicePixels(clamped_origin_x),
3896 DevicePixels(clamped_origin_y),
3897 ),
3898 size: size(DevicePixels(clamped_width), DevicePixels(clamped_height)),
3899 },
3900 ..tile
3901 }
3902 };
3903
3904 let content_mask = self.snapped_content_mask();
3905 let corner_radii = corner_radii
3906 .clamp_radii_for_quad_size(visible_bounds.size)
3907 .scale(self.scale_factor());
3908 let opacity = self.element_opacity();
3909
3910 self.next_frame.scene.insert_primitive(PolychromeSprite {
3911 order: 0,
3912 pad: 0,
3913 grayscale: grayscale.into(),
3914 bounds: visible_bounds_snapped,
3915 content_mask,
3916 corner_radii,
3917 tile: sub_tile,
3918 opacity,
3919 });
3920 Ok(())
3921 }
3922
3923 #[cfg(target_os = "macos")]
3927 pub fn paint_surface(&mut self, bounds: Bounds<Pixels>, image_buffer: CVPixelBuffer) {
3928 use crate::PaintSurface;
3929
3930 self.invalidator.debug_assert_paint();
3931
3932 let bounds = self.snap_bounds(bounds);
3933 let content_mask = self.snapped_content_mask();
3934 self.next_frame.scene.insert_primitive(PaintSurface {
3935 order: 0,
3936 bounds,
3937 content_mask,
3938 image_buffer,
3939 });
3940 }
3941
3942 pub fn drop_image(&mut self, data: Arc<RenderImage>) -> Result<()> {
3944 for frame_index in 0..data.frame_count() {
3945 let params = RenderImageParams {
3946 image_id: data.id,
3947 frame_index,
3948 };
3949
3950 self.sprite_atlas.remove(¶ms.clone().into());
3951 }
3952
3953 Ok(())
3954 }
3955
3956 #[must_use]
3962 pub fn request_layout(
3963 &mut self,
3964 style: Style,
3965 children: impl IntoIterator<Item = LayoutId>,
3966 cx: &mut App,
3967 ) -> LayoutId {
3968 self.invalidator.debug_assert_prepaint();
3969
3970 cx.layout_id_buffer.clear();
3971 cx.layout_id_buffer.extend(children);
3972 let rem_size = self.rem_size();
3973 let scale_factor = self.scale_factor();
3974
3975 self.layout_engine.as_mut().unwrap().request_layout(
3976 style,
3977 rem_size,
3978 scale_factor,
3979 &cx.layout_id_buffer,
3980 )
3981 }
3982
3983 pub fn request_measured_layout<
3992 F: FnMut(Size<Option<Pixels>>, Size<AvailableSpace>, &mut Window, &mut App) -> Size<Pixels>
3993 + 'static,
3994 >(
3995 &mut self,
3996 style: Style,
3997 measure: F,
3998 ) -> LayoutId {
3999 self.invalidator.debug_assert_prepaint();
4000
4001 let rem_size = self.rem_size();
4002 let scale_factor = self.scale_factor();
4003 self.layout_engine
4004 .as_mut()
4005 .unwrap()
4006 .request_measured_layout(style, rem_size, scale_factor, measure)
4007 }
4008
4009 pub fn compute_layout(
4015 &mut self,
4016 layout_id: LayoutId,
4017 available_space: Size<AvailableSpace>,
4018 cx: &mut App,
4019 ) {
4020 self.invalidator.debug_assert_prepaint();
4021
4022 let mut layout_engine = self.layout_engine.take().unwrap();
4023 layout_engine.compute_layout(layout_id, available_space, self, cx);
4024 self.layout_engine = Some(layout_engine);
4025 }
4026
4027 pub fn layout_bounds(&mut self, layout_id: LayoutId) -> Bounds<Pixels> {
4032 self.invalidator.debug_assert_prepaint();
4033
4034 let scale_factor = self.scale_factor();
4035 let mut bounds = self
4036 .layout_engine
4037 .as_mut()
4038 .unwrap()
4039 .layout_bounds(layout_id, scale_factor)
4040 .map(Into::into);
4041 bounds.origin += self.pixel_snap_point(self.element_offset());
4042 bounds
4043 }
4044
4045 pub fn insert_hitbox(&mut self, bounds: Bounds<Pixels>, behavior: HitboxBehavior) -> Hitbox {
4051 self.invalidator.debug_assert_prepaint();
4052
4053 let content_mask = self.content_mask();
4054 let mut id = self.next_hitbox_id;
4055 self.next_hitbox_id = self.next_hitbox_id.next();
4056 let hitbox = Hitbox {
4057 id,
4058 bounds,
4059 content_mask,
4060 behavior,
4061 };
4062 self.next_frame.hitboxes.push(hitbox.clone());
4063 hitbox
4064 }
4065
4066 pub fn insert_window_control_hitbox(&mut self, area: WindowControlArea, hitbox: Hitbox) {
4070 self.invalidator.debug_assert_paint();
4071 self.next_frame.window_control_hitboxes.push((area, hitbox));
4072 }
4073
4074 pub fn set_key_context(&mut self, context: KeyContext) {
4079 self.invalidator.debug_assert_paint();
4080 self.next_frame.dispatch_tree.set_key_context(context);
4081 }
4082
4083 pub fn set_focus_handle(&mut self, focus_handle: &FocusHandle, _: &App) {
4088 self.invalidator.debug_assert_prepaint();
4089 if focus_handle.is_focused(self) {
4090 self.next_frame.focus = Some(focus_handle.id);
4091 }
4092 self.next_frame.dispatch_tree.set_focus_id(focus_handle.id);
4093 }
4094
4095 pub fn set_view_id(&mut self, view_id: EntityId) {
4101 self.invalidator.debug_assert_prepaint();
4102 self.next_frame.dispatch_tree.set_view_id(view_id);
4103 }
4104
4105 pub fn current_view(&self) -> EntityId {
4107 self.invalidator.debug_assert_paint_or_prepaint();
4108 self.rendered_entity_stack.last().copied().unwrap()
4109 }
4110
4111 pub(crate) fn with_rendered_view<R>(
4112 &mut self,
4113 id: EntityId,
4114 f: impl FnOnce(&mut Self) -> R,
4115 ) -> R {
4116 self.rendered_entity_stack.push(id);
4117 let result = f(self);
4118 self.rendered_entity_stack.pop();
4119 result
4120 }
4121
4122 pub fn with_image_cache<F, R>(&mut self, image_cache: Option<AnyImageCache>, f: F) -> R
4124 where
4125 F: FnOnce(&mut Self) -> R,
4126 {
4127 if let Some(image_cache) = image_cache {
4128 self.image_cache_stack.push(image_cache);
4129 let result = f(self);
4130 self.image_cache_stack.pop();
4131 result
4132 } else {
4133 f(self)
4134 }
4135 }
4136
4137 pub fn handle_input(
4146 &mut self,
4147 focus_handle: &FocusHandle,
4148 input_handler: impl InputHandler,
4149 cx: &App,
4150 ) {
4151 self.invalidator.debug_assert_paint();
4152
4153 if focus_handle.is_focused(self) {
4154 let cx = self.to_async(cx);
4155 self.next_frame
4156 .input_handlers
4157 .push(Some(PlatformInputHandler::new(cx, Box::new(input_handler))));
4158 }
4159 }
4160
4161 pub fn on_mouse_event<Event: MouseEvent>(
4167 &mut self,
4168 mut handler: impl FnMut(&Event, DispatchPhase, &mut Window, &mut App) + 'static,
4169 ) {
4170 self.invalidator.debug_assert_paint();
4171
4172 self.next_frame.mouse_listeners.push(Some(Box::new(
4173 move |event: &dyn Any, phase: DispatchPhase, window: &mut Window, cx: &mut App| {
4174 if let Some(event) = event.downcast_ref() {
4175 handler(event, phase, window, cx)
4176 }
4177 },
4178 )));
4179 }
4180
4181 pub fn on_key_event<Event: KeyEvent>(
4190 &mut self,
4191 listener: impl Fn(&Event, DispatchPhase, &mut Window, &mut App) + 'static,
4192 ) {
4193 self.invalidator.debug_assert_paint();
4194
4195 self.next_frame.dispatch_tree.on_key_event(Rc::new(
4196 move |event: &dyn Any, phase, window: &mut Window, cx: &mut App| {
4197 if let Some(event) = event.downcast_ref::<Event>() {
4198 listener(event, phase, window, cx)
4199 }
4200 },
4201 ));
4202 }
4203
4204 pub fn on_modifiers_changed(
4211 &mut self,
4212 listener: impl Fn(&ModifiersChangedEvent, &mut Window, &mut App) + 'static,
4213 ) {
4214 self.invalidator.debug_assert_paint();
4215
4216 self.next_frame.dispatch_tree.on_modifiers_changed(Rc::new(
4217 move |event: &ModifiersChangedEvent, window: &mut Window, cx: &mut App| {
4218 listener(event, window, cx)
4219 },
4220 ));
4221 }
4222
4223 pub fn on_focus_in(
4227 &mut self,
4228 handle: &FocusHandle,
4229 cx: &mut App,
4230 mut listener: impl FnMut(&mut Window, &mut App) + 'static,
4231 ) -> Subscription {
4232 let focus_id = handle.id;
4233 let (subscription, activate) =
4234 self.new_focus_listener(Box::new(move |event, window, cx| {
4235 if event.is_focus_in(focus_id) {
4236 listener(window, cx);
4237 }
4238 true
4239 }));
4240 cx.defer(move |_| activate());
4241 subscription
4242 }
4243
4244 pub fn on_focus_out(
4247 &mut self,
4248 handle: &FocusHandle,
4249 cx: &mut App,
4250 mut listener: impl FnMut(FocusOutEvent, &mut Window, &mut App) + 'static,
4251 ) -> Subscription {
4252 let focus_id = handle.id;
4253 let (subscription, activate) =
4254 self.new_focus_listener(Box::new(move |event, window, cx| {
4255 if let Some(blurred_id) = event.previous_focus_path.last().copied()
4256 && event.is_focus_out(focus_id)
4257 {
4258 let event = FocusOutEvent {
4259 blurred: WeakFocusHandle {
4260 id: blurred_id,
4261 handles: Arc::downgrade(&cx.focus_handles),
4262 },
4263 };
4264 listener(event, window, cx)
4265 }
4266 true
4267 }));
4268 cx.defer(move |_| activate());
4269 subscription
4270 }
4271
4272 fn reset_cursor_style(&self, cx: &mut App) {
4273 if self.is_window_hovered() {
4275 let style = self
4276 .rendered_frame
4277 .cursor_style(self)
4278 .unwrap_or(CursorStyle::Arrow);
4279 self.platform_window.set_cursor_style(style);
4285 cx.platform.set_cursor_style(style);
4286 }
4287 }
4288
4289 pub fn dispatch_keystroke(&mut self, keystroke: Keystroke, cx: &mut App) -> bool {
4292 let keystroke = keystroke.with_simulated_ime();
4293 let result = self.dispatch_event(
4294 PlatformInput::KeyDown(KeyDownEvent {
4295 keystroke: keystroke.clone(),
4296 is_held: false,
4297 }),
4298 cx,
4299 );
4300 if !result.propagate {
4301 return true;
4302 }
4303
4304 if let Some(input) = keystroke.key_char
4305 && let Some(mut input_handler) = self.platform_window.take_input_handler()
4306 {
4307 input_handler.dispatch_input(&input, self, cx);
4308 self.platform_window.set_input_handler(input_handler);
4309 return true;
4310 }
4311
4312 false
4313 }
4314
4315 pub fn keystroke_text_for(&self, action: &dyn Action) -> String {
4318 self.highest_precedence_binding_for_action(action)
4319 .map(|binding| {
4320 binding
4321 .keystrokes()
4322 .iter()
4323 .map(ToString::to_string)
4324 .collect::<Vec<_>>()
4325 .join(" ")
4326 })
4327 .unwrap_or_else(|| action.name().to_string())
4328 }
4329
4330 #[profiling::function]
4332 pub fn dispatch_event(&mut self, event: PlatformInput, cx: &mut App) -> DispatchEventResult {
4333 #[cfg(feature = "input-latency-histogram")]
4334 let dispatch_time = Instant::now();
4335 let update_count_before = self.invalidator.update_count();
4336
4337 cx.propagate_event = true;
4339 self.default_prevented = false;
4341
4342 let event = match event {
4343 PlatformInput::MouseMove(mouse_move) => {
4346 self.mouse_position = mouse_move.position;
4347 self.modifiers = mouse_move.modifiers;
4348 PlatformInput::MouseMove(mouse_move)
4349 }
4350 PlatformInput::MouseDown(mouse_down) => {
4351 self.mouse_position = mouse_down.position;
4352 self.modifiers = mouse_down.modifiers;
4353 PlatformInput::MouseDown(mouse_down)
4354 }
4355 PlatformInput::MouseUp(mouse_up) => {
4356 self.mouse_position = mouse_up.position;
4357 self.modifiers = mouse_up.modifiers;
4358 PlatformInput::MouseUp(mouse_up)
4359 }
4360 PlatformInput::MouseExited(mouse_exited) => {
4361 self.modifiers = mouse_exited.modifiers;
4362 PlatformInput::MouseExited(mouse_exited)
4363 }
4364 PlatformInput::ModifiersChanged(modifiers_changed) => {
4365 self.modifiers = modifiers_changed.modifiers;
4366 self.capslock = modifiers_changed.capslock;
4367 PlatformInput::ModifiersChanged(modifiers_changed)
4368 }
4369 PlatformInput::ScrollWheel(scroll_wheel) => {
4370 self.mouse_position = scroll_wheel.position;
4371 self.modifiers = scroll_wheel.modifiers;
4372 PlatformInput::ScrollWheel(scroll_wheel)
4373 }
4374 PlatformInput::Pinch(pinch) => {
4375 self.mouse_position = pinch.position;
4376 self.modifiers = pinch.modifiers;
4377 PlatformInput::Pinch(pinch)
4378 }
4379 PlatformInput::FileDrop(file_drop) => match file_drop {
4382 FileDropEvent::Entered { position, paths } => {
4383 self.mouse_position = position;
4384 if cx.active_drag.is_none() {
4385 cx.active_drag = Some(AnyDrag {
4386 value: Arc::new(paths.clone()),
4387 view: cx.new(|_| paths).into(),
4388 cursor_offset: position,
4389 cursor_style: None,
4390 });
4391 }
4392 PlatformInput::MouseMove(MouseMoveEvent {
4393 position,
4394 pressed_button: Some(MouseButton::Left),
4395 modifiers: Modifiers::default(),
4396 })
4397 }
4398 FileDropEvent::Pending { position } => {
4399 self.mouse_position = position;
4400 PlatformInput::MouseMove(MouseMoveEvent {
4401 position,
4402 pressed_button: Some(MouseButton::Left),
4403 modifiers: Modifiers::default(),
4404 })
4405 }
4406 FileDropEvent::Submit { position } => {
4407 cx.activate(true);
4408 self.mouse_position = position;
4409 PlatformInput::MouseUp(MouseUpEvent {
4410 button: MouseButton::Left,
4411 position,
4412 modifiers: Modifiers::default(),
4413 click_count: 1,
4414 })
4415 }
4416 FileDropEvent::Exited => {
4417 cx.active_drag.take();
4418 PlatformInput::FileDrop(FileDropEvent::Exited)
4419 }
4420 },
4421 PlatformInput::KeyDown(_) | PlatformInput::KeyUp(_) => event,
4422 };
4423
4424 if let Some(any_mouse_event) = event.mouse_event() {
4425 self.dispatch_mouse_event(any_mouse_event, cx);
4426 } else if let Some(any_key_event) = event.keyboard_event() {
4427 self.dispatch_key_event(any_key_event, cx);
4428 }
4429
4430 if self.invalidator.update_count() > update_count_before {
4431 self.input_rate_tracker.borrow_mut().record_input();
4432 #[cfg(feature = "input-latency-histogram")]
4433 if self.invalidator.not_drawing() {
4434 self.input_latency_tracker.record_input(dispatch_time);
4435 } else {
4436 self.input_latency_tracker.record_mid_draw_input();
4437 }
4438 }
4439
4440 DispatchEventResult {
4441 propagate: cx.propagate_event,
4442 default_prevented: self.default_prevented,
4443 }
4444 }
4445
4446 fn dispatch_mouse_event(&mut self, event: &dyn Any, cx: &mut App) {
4447 self.last_input_was_keyboard.set(false);
4448
4449 let hit_test = self.rendered_frame.hit_test(self.mouse_position());
4450 if hit_test != self.mouse_hit_test {
4451 self.mouse_hit_test = hit_test;
4452 self.reset_cursor_style(cx);
4453 }
4454
4455 #[cfg(any(feature = "inspector", debug_assertions))]
4456 if self.is_inspector_picking(cx) {
4457 self.handle_inspector_mouse_event(event, cx);
4458 return;
4460 }
4461
4462 let mut mouse_listeners = mem::take(&mut self.rendered_frame.mouse_listeners);
4463
4464 for listener in &mut mouse_listeners {
4467 let listener = listener.as_mut().unwrap();
4468 listener(event, DispatchPhase::Capture, self, cx);
4469 if !cx.propagate_event {
4470 break;
4471 }
4472 }
4473
4474 if cx.propagate_event {
4476 for listener in mouse_listeners.iter_mut().rev() {
4477 let listener = listener.as_mut().unwrap();
4478 listener(event, DispatchPhase::Bubble, self, cx);
4479 if !cx.propagate_event {
4480 break;
4481 }
4482 }
4483 }
4484
4485 self.rendered_frame.mouse_listeners = mouse_listeners;
4486
4487 if cx.has_active_drag() {
4488 if event.is::<MouseMoveEvent>() {
4489 self.refresh();
4492 } else if event.is::<MouseUpEvent>() {
4493 cx.active_drag = None;
4496 self.refresh();
4497 }
4498 }
4499
4500 if event.is::<MouseUpEvent>() && self.captured_hitbox.is_some() {
4501 self.captured_hitbox = None;
4502 }
4503 }
4504
4505 fn dispatch_key_event(&mut self, event: &dyn Any, cx: &mut App) {
4506 self.last_input_was_keyboard.set(true);
4507
4508 if self.invalidator.is_dirty() {
4509 self.draw(cx).clear();
4510 }
4511
4512 let node_id = self.focus_node_id_in_rendered_frame(self.focus);
4513 let dispatch_path = self.rendered_frame.dispatch_tree.dispatch_path(node_id);
4514
4515 let mut keystroke: Option<Keystroke> = None;
4516
4517 if let Some(event) = event.downcast_ref::<ModifiersChangedEvent>() {
4518 if event.modifiers.number_of_modifiers() == 0
4519 && self.pending_modifier.modifiers.number_of_modifiers() == 1
4520 && !self.pending_modifier.saw_other_input
4521 {
4522 let key = match self.pending_modifier.modifiers {
4523 modifiers if modifiers.shift => Some("shift"),
4524 modifiers if modifiers.control => Some("control"),
4525 modifiers if modifiers.alt => Some("alt"),
4526 modifiers if modifiers.platform => Some("platform"),
4527 modifiers if modifiers.function => Some("function"),
4528 _ => None,
4529 };
4530 if let Some(key) = key {
4531 keystroke = Some(Keystroke {
4532 key: key.to_string(),
4533 key_char: None,
4534 modifiers: Modifiers::default(),
4535 });
4536 }
4537 }
4538
4539 if self.pending_modifier.modifiers.number_of_modifiers() == 0
4540 && event.modifiers.number_of_modifiers() == 1
4541 {
4542 self.pending_modifier.saw_other_input = false
4543 } else if event.modifiers.number_of_modifiers() > 1 {
4544 self.pending_modifier.saw_other_input = true
4545 }
4546 self.pending_modifier.modifiers = event.modifiers
4547 } else if let Some(key_down_event) = event.downcast_ref::<KeyDownEvent>() {
4548 self.pending_modifier.saw_other_input = true;
4549 keystroke = Some(key_down_event.keystroke.clone());
4550 }
4551
4552 let Some(keystroke) = keystroke else {
4553 self.finish_dispatch_key_event(event, dispatch_path, self.context_stack(), cx);
4554 return;
4555 };
4556
4557 cx.propagate_event = true;
4558 self.dispatch_keystroke_interceptors(event, self.context_stack(), cx);
4559 if !cx.propagate_event {
4560 self.finish_dispatch_key_event(event, dispatch_path, self.context_stack(), cx);
4561 return;
4562 }
4563
4564 let mut currently_pending = self.pending_input.take().unwrap_or_default();
4565 if currently_pending.focus.is_some() && currently_pending.focus != self.focus {
4566 currently_pending = PendingInput::default();
4567 }
4568
4569 let match_result = self.rendered_frame.dispatch_tree.dispatch_key(
4570 currently_pending.keystrokes,
4571 keystroke,
4572 &dispatch_path,
4573 );
4574
4575 if !match_result.to_replay.is_empty() {
4576 self.replay_pending_input(match_result.to_replay, cx);
4577 cx.propagate_event = true;
4578 }
4579
4580 if !match_result.pending.is_empty() {
4581 currently_pending.keystrokes = match_result.pending;
4582 currently_pending.focus = self.focus;
4583 currently_pending.timer = Some(self.spawn(cx, async move |cx| {
4584 cx.background_executor.timer(Duration::from_secs(1)).await;
4585 cx.update(move |window, cx| {
4586 let Some(currently_pending) = window
4587 .pending_input
4588 .take()
4589 .filter(|pending| pending.focus == window.focus)
4590 else {
4591 return;
4592 };
4593
4594 let node_id = window.focus_node_id_in_rendered_frame(window.focus);
4595 let dispatch_path = window.rendered_frame.dispatch_tree.dispatch_path(node_id);
4596
4597 let to_replay = window
4598 .rendered_frame
4599 .dispatch_tree
4600 .flush_dispatch(currently_pending.keystrokes, &dispatch_path);
4601
4602 window.pending_input_changed(cx);
4603 window.replay_pending_input(to_replay, cx)
4604 })
4605 .log_err();
4606 }));
4607 self.pending_input = Some(currently_pending);
4608 self.pending_input_changed(cx);
4609 cx.propagate_event = false;
4610 return;
4611 }
4612
4613 for binding in match_result.bindings {
4614 self.dispatch_action_on_node(node_id, binding.action.as_ref(), cx);
4615 if !cx.propagate_event {
4616 self.dispatch_keystroke_observers(
4617 event,
4618 Some(binding.action),
4619 match_result.context_stack,
4620 cx,
4621 );
4622 self.pending_input_changed(cx);
4623 return;
4624 }
4625 }
4626
4627 self.finish_dispatch_key_event(event, dispatch_path, match_result.context_stack, cx);
4628 self.pending_input_changed(cx);
4629 }
4630
4631 fn finish_dispatch_key_event(
4632 &mut self,
4633 event: &dyn Any,
4634 dispatch_path: SmallVec<[DispatchNodeId; 32]>,
4635 context_stack: Vec<KeyContext>,
4636 cx: &mut App,
4637 ) {
4638 self.dispatch_key_down_up_event(event, &dispatch_path, cx);
4639 if !cx.propagate_event {
4640 return;
4641 }
4642
4643 self.dispatch_modifiers_changed_event(event, &dispatch_path, cx);
4644 if !cx.propagate_event {
4645 return;
4646 }
4647
4648 self.dispatch_keystroke_observers(event, None, context_stack, cx);
4649 }
4650
4651 fn pending_input_changed(&mut self, cx: &mut App) {
4652 self.pending_input_observers
4653 .clone()
4654 .retain(&(), |callback| callback(self, cx));
4655 }
4656
4657 fn dispatch_key_down_up_event(
4658 &mut self,
4659 event: &dyn Any,
4660 dispatch_path: &SmallVec<[DispatchNodeId; 32]>,
4661 cx: &mut App,
4662 ) {
4663 for node_id in dispatch_path {
4665 let node = self.rendered_frame.dispatch_tree.node(*node_id);
4666
4667 for key_listener in node.key_listeners.clone() {
4668 key_listener(event, DispatchPhase::Capture, self, cx);
4669 if !cx.propagate_event {
4670 return;
4671 }
4672 }
4673 }
4674
4675 for node_id in dispatch_path.iter().rev() {
4677 let node = self.rendered_frame.dispatch_tree.node(*node_id);
4679 for key_listener in node.key_listeners.clone() {
4680 key_listener(event, DispatchPhase::Bubble, self, cx);
4681 if !cx.propagate_event {
4682 return;
4683 }
4684 }
4685 }
4686 }
4687
4688 fn dispatch_modifiers_changed_event(
4689 &mut self,
4690 event: &dyn Any,
4691 dispatch_path: &SmallVec<[DispatchNodeId; 32]>,
4692 cx: &mut App,
4693 ) {
4694 let Some(event) = event.downcast_ref::<ModifiersChangedEvent>() else {
4695 return;
4696 };
4697 for node_id in dispatch_path.iter().rev() {
4698 let node = self.rendered_frame.dispatch_tree.node(*node_id);
4699 for listener in node.modifiers_changed_listeners.clone() {
4700 listener(event, self, cx);
4701 if !cx.propagate_event {
4702 return;
4703 }
4704 }
4705 }
4706 }
4707
4708 pub fn has_pending_keystrokes(&self) -> bool {
4710 self.pending_input.is_some()
4711 }
4712
4713 #[cfg(test)]
4714 pub(crate) fn pending_input_is_none(&self) -> bool {
4715 self.pending_input.is_none()
4716 }
4717
4718 fn defer_pending_input_changed(&self, cx: &mut App) {
4719 self.defer(cx, |window, cx| {
4722 window.pending_input_changed(cx);
4723 });
4724 }
4725
4726 pub(crate) fn clear_pending_keystrokes(&mut self, cx: &mut App) {
4727 if self.pending_input.take().is_some() {
4728 self.defer_pending_input_changed(cx);
4729 }
4730 }
4731
4732 pub fn pending_input_keystrokes(&self) -> Option<&[Keystroke]> {
4734 self.pending_input
4735 .as_ref()
4736 .map(|pending_input| pending_input.keystrokes.as_slice())
4737 }
4738
4739 fn replay_pending_input(&mut self, replays: SmallVec<[Replay; 1]>, cx: &mut App) {
4740 let node_id = self.focus_node_id_in_rendered_frame(self.focus);
4741 let dispatch_path = self.rendered_frame.dispatch_tree.dispatch_path(node_id);
4742
4743 'replay: for replay in replays {
4744 let event = KeyDownEvent {
4745 keystroke: replay.keystroke.clone(),
4746 is_held: false,
4747 };
4748
4749 cx.propagate_event = true;
4750 for binding in replay.bindings {
4751 self.dispatch_action_on_node(node_id, binding.action.as_ref(), cx);
4752 if !cx.propagate_event {
4753 self.dispatch_keystroke_observers(
4754 &event,
4755 Some(binding.action),
4756 Vec::default(),
4757 cx,
4758 );
4759 continue 'replay;
4760 }
4761 }
4762
4763 self.dispatch_key_down_up_event(&event, &dispatch_path, cx);
4764 if !cx.propagate_event {
4765 continue 'replay;
4766 }
4767 if let Some(input) = replay.keystroke.key_char.as_ref().cloned()
4768 && let Some(mut input_handler) = self.platform_window.take_input_handler()
4769 {
4770 input_handler.dispatch_input(&input, self, cx);
4771 self.platform_window.set_input_handler(input_handler)
4772 }
4773 }
4774 }
4775
4776 fn focus_node_id_in_rendered_frame(&self, focus_id: Option<FocusId>) -> DispatchNodeId {
4777 focus_id
4778 .and_then(|focus_id| {
4779 self.rendered_frame
4780 .dispatch_tree
4781 .focusable_node_id(focus_id)
4782 })
4783 .unwrap_or_else(|| self.rendered_frame.dispatch_tree.root_node_id())
4784 }
4785
4786 fn dispatch_action_on_node(
4787 &mut self,
4788 node_id: DispatchNodeId,
4789 action: &dyn Action,
4790 cx: &mut App,
4791 ) {
4792 let dispatch_path = self.rendered_frame.dispatch_tree.dispatch_path(node_id);
4793
4794 cx.propagate_event = true;
4796 if let Some(mut global_listeners) = cx
4797 .global_action_listeners
4798 .remove(&action.as_any().type_id())
4799 {
4800 for listener in &global_listeners {
4801 listener(action.as_any(), DispatchPhase::Capture, cx);
4802 if !cx.propagate_event {
4803 break;
4804 }
4805 }
4806
4807 global_listeners.extend(
4808 cx.global_action_listeners
4809 .remove(&action.as_any().type_id())
4810 .unwrap_or_default(),
4811 );
4812
4813 cx.global_action_listeners
4814 .insert(action.as_any().type_id(), global_listeners);
4815 }
4816
4817 if !cx.propagate_event {
4818 return;
4819 }
4820
4821 for node_id in &dispatch_path {
4823 let node = self.rendered_frame.dispatch_tree.node(*node_id);
4824 for DispatchActionListener {
4825 action_type,
4826 listener,
4827 } in node.action_listeners.clone()
4828 {
4829 let any_action = action.as_any();
4830 if action_type == any_action.type_id() {
4831 listener(any_action, DispatchPhase::Capture, self, cx);
4832
4833 if !cx.propagate_event {
4834 return;
4835 }
4836 }
4837 }
4838 }
4839
4840 for node_id in dispatch_path.iter().rev() {
4842 let node = self.rendered_frame.dispatch_tree.node(*node_id);
4843 for DispatchActionListener {
4844 action_type,
4845 listener,
4846 } in node.action_listeners.clone()
4847 {
4848 let any_action = action.as_any();
4849 if action_type == any_action.type_id() {
4850 cx.propagate_event = false; listener(any_action, DispatchPhase::Bubble, self, cx);
4852
4853 if !cx.propagate_event {
4854 return;
4855 }
4856 }
4857 }
4858 }
4859
4860 if let Some(mut global_listeners) = cx
4862 .global_action_listeners
4863 .remove(&action.as_any().type_id())
4864 {
4865 for listener in global_listeners.iter().rev() {
4866 cx.propagate_event = false; listener(action.as_any(), DispatchPhase::Bubble, cx);
4869 if !cx.propagate_event {
4870 break;
4871 }
4872 }
4873
4874 global_listeners.extend(
4875 cx.global_action_listeners
4876 .remove(&action.as_any().type_id())
4877 .unwrap_or_default(),
4878 );
4879
4880 cx.global_action_listeners
4881 .insert(action.as_any().type_id(), global_listeners);
4882 }
4883 }
4884
4885 pub fn observe_global<G: Global>(
4888 &mut self,
4889 cx: &mut App,
4890 f: impl Fn(&mut Window, &mut App) + 'static,
4891 ) -> Subscription {
4892 let window_handle = self.handle;
4893 let (subscription, activate) = cx.global_observers.insert(
4894 TypeId::of::<G>(),
4895 Box::new(move |cx| {
4896 window_handle
4897 .update(cx, |_, window, cx| f(window, cx))
4898 .is_ok()
4899 }),
4900 );
4901 cx.defer(move |_| activate());
4902 subscription
4903 }
4904
4905 pub fn activate_window(&self) {
4907 self.platform_window.activate();
4908 }
4909
4910 pub fn request_attention(&self) {
4912 self.platform_window.request_attention();
4913 }
4914
4915 pub fn minimize_window(&self) {
4917 self.platform_window.minimize();
4918 }
4919
4920 pub fn show_window(&self) {
4922 self.platform_window.show();
4923 }
4924
4925 pub fn hide_window(&self) {
4927 self.platform_window.hide();
4928 }
4929
4930 pub fn is_window_visible(&self) -> bool {
4932 self.platform_window.is_visible()
4933 }
4934
4935 pub fn set_mouse_passthrough(&self, passthrough: bool) {
4937 self.platform_window.set_mouse_passthrough(passthrough);
4938 }
4939
4940 pub fn set_input_region(&self, region: Option<&[Bounds<Pixels>]>) {
4947 self.platform_window.set_input_region(region);
4948 }
4949
4950 pub fn toggle_fullscreen(&self) {
4952 self.platform_window.toggle_fullscreen();
4953 }
4954
4955 pub fn set_progress_bar(&self, state: ProgressBarState) {
4957 self.platform_window.set_progress_bar(state);
4958 }
4959
4960 pub fn window_state(&self) -> WindowState {
4962 let bounds = self.platform_window.window_bounds();
4963 let display_id = self.platform_window.display().map(|d| d.id());
4964 let fullscreen = self.platform_window.is_fullscreen();
4965 WindowState {
4966 bounds,
4967 display_id,
4968 fullscreen,
4969 }
4970 }
4971
4972 pub fn restore_window_state(&self, state: &WindowState) {
4978 let is_fullscreen = self.platform_window.is_fullscreen();
4979 if state.fullscreen != is_fullscreen {
4980 self.platform_window.toggle_fullscreen();
4981 }
4982 }
4983
4984 pub fn invalidate_character_coordinates(&self) {
4986 self.on_next_frame(|window, cx| {
4987 if let Some(mut input_handler) = window.platform_window.take_input_handler() {
4988 if let Some(bounds) = input_handler.selected_bounds(window, cx) {
4989 window.platform_window.update_ime_position(bounds);
4990 }
4991 window.platform_window.set_input_handler(input_handler);
4992 }
4993 });
4994 }
4995
4996 pub fn prompt<T>(
5000 &mut self,
5001 level: PromptLevel,
5002 message: &str,
5003 detail: Option<&str>,
5004 answers: &[T],
5005 cx: &mut App,
5006 ) -> oneshot::Receiver<usize>
5007 where
5008 T: Clone + Into<PromptButton>,
5009 {
5010 let prompt_builder = cx.prompt_builder.take();
5011 let Some(prompt_builder) = prompt_builder else {
5012 unreachable!("Re-entrant window prompting is not supported by GPUI");
5013 };
5014
5015 let answers = answers
5016 .iter()
5017 .map(|answer| answer.clone().into())
5018 .collect::<Vec<_>>();
5019
5020 let receiver = match &prompt_builder {
5021 PromptBuilder::Default => self
5022 .platform_window
5023 .prompt(level, message, detail, &answers)
5024 .unwrap_or_else(|| {
5025 self.build_custom_prompt(&prompt_builder, level, message, detail, &answers, cx)
5026 }),
5027 PromptBuilder::Custom(_) => {
5028 self.build_custom_prompt(&prompt_builder, level, message, detail, &answers, cx)
5029 }
5030 };
5031
5032 cx.prompt_builder = Some(prompt_builder);
5033
5034 receiver
5035 }
5036
5037 fn build_custom_prompt(
5038 &mut self,
5039 prompt_builder: &PromptBuilder,
5040 level: PromptLevel,
5041 message: &str,
5042 detail: Option<&str>,
5043 answers: &[PromptButton],
5044 cx: &mut App,
5045 ) -> oneshot::Receiver<usize> {
5046 let (sender, receiver) = oneshot::channel();
5047 let handle = PromptHandle::new(sender);
5048 let handle = (prompt_builder)(level, message, detail, answers, handle, self, cx);
5049 self.prompt = Some(handle);
5050 receiver
5051 }
5052
5053 pub fn has_active_prompt(&self) -> bool {
5057 self.prompt.is_some()
5058 }
5059
5060 pub fn context_stack(&self) -> Vec<KeyContext> {
5062 let node_id = self.focus_node_id_in_rendered_frame(self.focus);
5063 let dispatch_tree = &self.rendered_frame.dispatch_tree;
5064 dispatch_tree
5065 .dispatch_path(node_id)
5066 .iter()
5067 .filter_map(move |&node_id| dispatch_tree.node(node_id).context.clone())
5068 .collect()
5069 }
5070
5071 pub fn available_actions(&self, cx: &App) -> Vec<Box<dyn Action>> {
5073 let node_id = self.focus_node_id_in_rendered_frame(self.focus);
5074 let mut actions = self.rendered_frame.dispatch_tree.available_actions(node_id);
5075 for action_type in cx.global_action_listeners.keys() {
5076 if let Err(ix) = actions.binary_search_by_key(action_type, |a| a.as_any().type_id()) {
5077 let action = cx.actions.build_action_type(action_type).ok();
5078 if let Some(action) = action {
5079 actions.insert(ix, action);
5080 }
5081 }
5082 }
5083 actions
5084 }
5085
5086 pub fn bindings_for_action(&self, action: &dyn Action) -> Vec<KeyBinding> {
5089 self.rendered_frame
5090 .dispatch_tree
5091 .bindings_for_action(action, &self.rendered_frame.dispatch_tree.context_stack)
5092 }
5093
5094 pub fn highest_precedence_binding_for_action(&self, action: &dyn Action) -> Option<KeyBinding> {
5097 self.rendered_frame
5098 .dispatch_tree
5099 .highest_precedence_binding_for_action(
5100 action,
5101 &self.rendered_frame.dispatch_tree.context_stack,
5102 )
5103 }
5104
5105 pub fn bindings_for_action_in_context(
5107 &self,
5108 action: &dyn Action,
5109 context: KeyContext,
5110 ) -> Vec<KeyBinding> {
5111 let dispatch_tree = &self.rendered_frame.dispatch_tree;
5112 dispatch_tree.bindings_for_action(action, &[context])
5113 }
5114
5115 pub fn highest_precedence_binding_for_action_in_context(
5118 &self,
5119 action: &dyn Action,
5120 context: KeyContext,
5121 ) -> Option<KeyBinding> {
5122 let dispatch_tree = &self.rendered_frame.dispatch_tree;
5123 dispatch_tree.highest_precedence_binding_for_action(action, &[context])
5124 }
5125
5126 pub fn bindings_for_action_in(
5130 &self,
5131 action: &dyn Action,
5132 focus_handle: &FocusHandle,
5133 ) -> Vec<KeyBinding> {
5134 let dispatch_tree = &self.rendered_frame.dispatch_tree;
5135 let Some(context_stack) = self.context_stack_for_focus_handle(focus_handle) else {
5136 return vec![];
5137 };
5138 dispatch_tree.bindings_for_action(action, &context_stack)
5139 }
5140
5141 pub fn highest_precedence_binding_for_action_in(
5145 &self,
5146 action: &dyn Action,
5147 focus_handle: &FocusHandle,
5148 ) -> Option<KeyBinding> {
5149 let dispatch_tree = &self.rendered_frame.dispatch_tree;
5150 let context_stack = self.context_stack_for_focus_handle(focus_handle)?;
5151 dispatch_tree.highest_precedence_binding_for_action(action, &context_stack)
5152 }
5153
5154 fn context_stack_for_focus_handle(
5155 &self,
5156 focus_handle: &FocusHandle,
5157 ) -> Option<Vec<KeyContext>> {
5158 let dispatch_tree = &self.rendered_frame.dispatch_tree;
5159 let node_id = dispatch_tree.focusable_node_id(focus_handle.id)?;
5160 let context_stack: Vec<_> = dispatch_tree
5161 .dispatch_path(node_id)
5162 .into_iter()
5163 .filter_map(|node_id| dispatch_tree.node(node_id).context.clone())
5164 .collect();
5165 Some(context_stack)
5166 }
5167
5168 pub fn listener_for<V: Render, E>(
5170 &self,
5171 view: &Entity<V>,
5172 f: impl Fn(&mut V, &E, &mut Window, &mut Context<V>) + 'static,
5173 ) -> impl Fn(&E, &mut Window, &mut App) + 'static {
5174 let view = view.downgrade();
5175 move |e: &E, window: &mut Window, cx: &mut App| {
5176 view.update(cx, |view, cx| f(view, e, window, cx)).ok();
5177 }
5178 }
5179
5180 pub fn handler_for<V: Render, Callback: Fn(&mut V, &mut Window, &mut Context<V>) + 'static>(
5182 &self,
5183 view: &Entity<V>,
5184 f: Callback,
5185 ) -> impl Fn(&mut Window, &mut App) + use<V, Callback> {
5186 let view = view.downgrade();
5187 move |window: &mut Window, cx: &mut App| {
5188 view.update(cx, |view, cx| f(view, window, cx)).ok();
5189 }
5190 }
5191
5192 pub fn on_window_should_close(
5195 &self,
5196 cx: &App,
5197 f: impl Fn(&mut Window, &mut App) -> bool + 'static,
5198 ) {
5199 let mut cx = self.to_async(cx);
5200 self.platform_window.on_should_close(Box::new(move || {
5201 cx.update(|window, cx| f(window, cx)).unwrap_or(true)
5202 }))
5203 }
5204
5205 pub fn on_action(
5212 &mut self,
5213 action_type: TypeId,
5214 listener: impl Fn(&dyn Any, DispatchPhase, &mut Window, &mut App) + 'static,
5215 ) {
5216 self.next_frame
5217 .dispatch_tree
5218 .on_action(action_type, Rc::new(listener));
5219 }
5220
5221 pub fn on_action_when(
5228 &mut self,
5229 condition: bool,
5230 action_type: TypeId,
5231 listener: impl Fn(&dyn Any, DispatchPhase, &mut Window, &mut App) + 'static,
5232 ) {
5233 if condition {
5234 self.next_frame
5235 .dispatch_tree
5236 .on_action(action_type, Rc::new(listener));
5237 }
5238 }
5239
5240 pub fn gpu_specs(&self) -> Option<GpuSpecs> {
5243 self.platform_window.gpu_specs()
5244 }
5245
5246 pub fn titlebar_double_click(&self) {
5249 self.platform_window.titlebar_double_click();
5250 }
5251
5252 pub fn window_title(&self) -> String {
5255 self.platform_window.get_title()
5256 }
5257
5258 pub fn tabbed_windows(&self) -> Option<Vec<SystemWindowTab>> {
5261 self.platform_window.tabbed_windows()
5262 }
5263
5264 pub fn tab_bar_visible(&self) -> bool {
5267 self.platform_window.tab_bar_visible()
5268 }
5269
5270 pub fn merge_all_windows(&self) {
5273 self.platform_window.merge_all_windows()
5274 }
5275
5276 pub fn move_tab_to_new_window(&self) {
5279 self.platform_window.move_tab_to_new_window()
5280 }
5281
5282 pub fn toggle_window_tab_overview(&self) {
5285 self.platform_window.toggle_window_tab_overview()
5286 }
5287
5288 pub fn set_tabbing_identifier(&self, tabbing_identifier: Option<String>) {
5291 self.platform_window
5292 .set_tabbing_identifier(tabbing_identifier)
5293 }
5294
5295 pub fn play_system_bell(&self) {
5297 self.platform_window.play_system_bell()
5298 }
5299
5300 pub fn debug_a11y_tree_json(&self) -> Option<String> {
5304 self.a11y.debug_tree_json()
5305 }
5306
5307 pub fn on_a11y_action(
5311 &mut self,
5312 node_id: accesskit::NodeId,
5313 action: accesskit::Action,
5314 listener: impl FnMut(Option<&accesskit::ActionData>, &mut Window, &mut App) + 'static,
5315 ) {
5316 self.a11y
5317 .action_listeners
5318 .entry(node_id)
5319 .or_default()
5320 .push((action, Box::new(listener)));
5321 }
5322
5323 #[cfg(not(target_family = "wasm"))]
5324 pub(crate) fn handle_a11y_action(&mut self, request: accesskit::ActionRequest, cx: &mut App) {
5325 if let Some(mut listeners) = self.a11y.action_listeners.remove(&request.target_node) {
5326 let action_data = request.data.as_ref();
5327 let mut matched = false;
5328 for (action, listener) in &mut listeners {
5329 if *action == request.action {
5330 listener(action_data, self, cx);
5331 matched = true;
5332 }
5333 }
5334 self.a11y
5335 .action_listeners
5336 .insert(request.target_node, listeners);
5337 if matched {
5338 return;
5339 }
5340 }
5341
5342 match request.action {
5343 accesskit::Action::Click => {
5344 if let Some(bounds) = self.a11y.node_bounds.get(&request.target_node).copied() {
5345 let center = bounds.center();
5346 self.dispatch_event(
5347 PlatformInput::MouseDown(crate::MouseDownEvent {
5348 button: MouseButton::Left,
5349 position: center,
5350 modifiers: Modifiers::default(),
5351 click_count: 1,
5352 first_mouse: false,
5353 }),
5354 cx,
5355 );
5356 self.dispatch_event(
5357 PlatformInput::MouseUp(MouseUpEvent {
5358 button: MouseButton::Left,
5359 position: center,
5360 modifiers: Modifiers::default(),
5361 click_count: 1,
5362 }),
5363 cx,
5364 );
5365 }
5366 }
5367 accesskit::Action::Focus => {
5368 if let Some(focus_id) = self.a11y.focus_ids.get(&request.target_node).copied()
5369 && let Some(handle) = FocusHandle::for_id(focus_id, &cx.focus_handles)
5370 {
5371 self.focus(&handle);
5372 }
5373 }
5374 accesskit::Action::Blur => self.blur(cx),
5375 _ => {
5376 log::debug!(
5377 "Unhandled a11y action: {:?} on {:?}",
5378 request.action,
5379 request.target_node
5380 );
5381 }
5382 }
5383 }
5384
5385 #[cfg(any(feature = "inspector", debug_assertions))]
5387 pub fn toggle_inspector(&mut self, cx: &mut App) {
5388 self.inspector = match self.inspector {
5389 None => Some(cx.new(|_| Inspector::new())),
5390 Some(_) => None,
5391 };
5392 self.refresh();
5393 }
5394
5395 pub fn is_inspector_picking(&self, _cx: &App) -> bool {
5397 #[cfg(any(feature = "inspector", debug_assertions))]
5398 {
5399 if let Some(inspector) = &self.inspector {
5400 return inspector.read(_cx).is_picking();
5401 }
5402 }
5403 false
5404 }
5405
5406 #[cfg(any(feature = "inspector", debug_assertions))]
5408 pub fn with_inspector_state<T: 'static, R>(
5409 &mut self,
5410 _inspector_id: Option<&crate::InspectorElementId>,
5411 cx: &mut App,
5412 f: impl FnOnce(&mut Option<T>, &mut Self) -> R,
5413 ) -> R {
5414 if let Some(inspector_id) = _inspector_id
5415 && let Some(inspector) = &self.inspector
5416 {
5417 let inspector = inspector.clone();
5418 let active_element_id = inspector.read(cx).active_element_id();
5419 if Some(inspector_id) == active_element_id {
5420 return inspector.update(cx, |inspector, _cx| {
5421 inspector.with_active_element_state(self, f)
5422 });
5423 }
5424 }
5425 f(&mut None, self)
5426 }
5427
5428 #[cfg(any(feature = "inspector", debug_assertions))]
5429 pub(crate) fn build_inspector_element_id(
5430 &mut self,
5431 path: crate::InspectorElementPath,
5432 ) -> crate::InspectorElementId {
5433 self.invalidator.debug_assert_paint_or_prepaint();
5434 let path = Rc::new(path);
5435 let next_instance_id = self
5436 .next_frame
5437 .next_inspector_instance_ids
5438 .entry(path.clone())
5439 .or_insert(0);
5440 let instance_id = *next_instance_id;
5441 *next_instance_id += 1;
5442 crate::InspectorElementId { path, instance_id }
5443 }
5444
5445 #[cfg(any(feature = "inspector", debug_assertions))]
5446 fn prepaint_inspector(&mut self, inspector_width: Pixels, cx: &mut App) -> Option<AnyElement> {
5447 if let Some(inspector) = self.inspector.take() {
5448 let mut inspector_element = AnyView::from(inspector.clone()).into_any_element();
5449 inspector_element.prepaint_as_root(
5450 point(self.viewport_size.width - inspector_width, px(0.0)),
5451 size(inspector_width, self.viewport_size.height).into(),
5452 self,
5453 cx,
5454 );
5455 self.inspector = Some(inspector);
5456 Some(inspector_element)
5457 } else {
5458 None
5459 }
5460 }
5461
5462 #[cfg(any(feature = "inspector", debug_assertions))]
5463 fn paint_inspector(&mut self, mut inspector_element: Option<AnyElement>, cx: &mut App) {
5464 if let Some(mut inspector_element) = inspector_element {
5465 inspector_element.paint(self, cx);
5466 };
5467 }
5468
5469 #[cfg(any(feature = "inspector", debug_assertions))]
5472 pub fn insert_inspector_hitbox(
5473 &mut self,
5474 hitbox_id: HitboxId,
5475 inspector_id: Option<&crate::InspectorElementId>,
5476 cx: &App,
5477 ) {
5478 self.invalidator.debug_assert_paint_or_prepaint();
5479 if !self.is_inspector_picking(cx) {
5480 return;
5481 }
5482 if let Some(inspector_id) = inspector_id {
5483 self.next_frame
5484 .inspector_hitboxes
5485 .insert(hitbox_id, inspector_id.clone());
5486 }
5487 }
5488
5489 #[cfg(any(feature = "inspector", debug_assertions))]
5490 fn paint_inspector_hitbox(&mut self, cx: &App) {
5491 if let Some(inspector) = self.inspector.as_ref() {
5492 let inspector = inspector.read(cx);
5493 if let Some((hitbox_id, _)) = self.hovered_inspector_hitbox(inspector, &self.next_frame)
5494 && let Some(hitbox) = self
5495 .next_frame
5496 .hitboxes
5497 .iter()
5498 .find(|hitbox| hitbox.id == hitbox_id)
5499 {
5500 self.paint_quad(crate::fill(hitbox.bounds, crate::rgba(0x61afef4d)));
5501 }
5502 }
5503 }
5504
5505 #[cfg(any(feature = "inspector", debug_assertions))]
5506 fn handle_inspector_mouse_event(&mut self, event: &dyn Any, cx: &mut App) {
5507 let Some(inspector) = self.inspector.clone() else {
5508 return;
5509 };
5510 if event.downcast_ref::<MouseMoveEvent>().is_some() {
5511 inspector.update(cx, |inspector, _cx| {
5512 if let Some((_, inspector_id)) =
5513 self.hovered_inspector_hitbox(inspector, &self.rendered_frame)
5514 {
5515 inspector.hover(inspector_id, self);
5516 }
5517 });
5518 } else if event.downcast_ref::<crate::MouseDownEvent>().is_some() {
5519 inspector.update(cx, |inspector, _cx| {
5520 if let Some((_, inspector_id)) =
5521 self.hovered_inspector_hitbox(inspector, &self.rendered_frame)
5522 {
5523 inspector.select(inspector_id, self);
5524 }
5525 });
5526 } else if let Some(event) = event.downcast_ref::<crate::ScrollWheelEvent>() {
5527 const SCROLL_LINES: f32 = 3.0;
5529 const SCROLL_PIXELS_PER_LAYER: f32 = 36.0;
5530 let delta_y = event
5531 .delta
5532 .pixel_delta(px(SCROLL_PIXELS_PER_LAYER / SCROLL_LINES))
5533 .y;
5534 if let Some(inspector) = self.inspector.clone() {
5535 inspector.update(cx, |inspector, _cx| {
5536 if let Some(depth) = inspector.pick_depth.as_mut() {
5537 *depth += f32::from(delta_y) / SCROLL_PIXELS_PER_LAYER;
5538 let max_depth = self.mouse_hit_test.ids.len() as f32 - 0.5;
5539 if *depth < 0.0 {
5540 *depth = 0.0;
5541 } else if *depth > max_depth {
5542 *depth = max_depth;
5543 }
5544 if let Some((_, inspector_id)) =
5545 self.hovered_inspector_hitbox(inspector, &self.rendered_frame)
5546 {
5547 inspector.set_active_element_id(inspector_id, self);
5548 }
5549 }
5550 });
5551 }
5552 }
5553 }
5554
5555 #[cfg(any(feature = "inspector", debug_assertions))]
5556 fn hovered_inspector_hitbox(
5557 &self,
5558 inspector: &Inspector,
5559 frame: &Frame,
5560 ) -> Option<(HitboxId, crate::InspectorElementId)> {
5561 if let Some(pick_depth) = inspector.pick_depth {
5562 let depth = (pick_depth as i64).try_into().unwrap_or(0);
5563 let max_skipped = self.mouse_hit_test.ids.len().saturating_sub(1);
5564 let skip_count = (depth as usize).min(max_skipped);
5565 for hitbox_id in self.mouse_hit_test.ids.iter().skip(skip_count) {
5566 if let Some(inspector_id) = frame.inspector_hitboxes.get(hitbox_id) {
5567 return Some((*hitbox_id, inspector_id.clone()));
5568 }
5569 }
5570 }
5571 None
5572 }
5573
5574 #[cfg(any(test, feature = "test-support"))]
5577 pub fn set_modifiers(&mut self, modifiers: Modifiers) {
5578 self.modifiers = modifiers;
5579 }
5580}
5581
5582slotmap::new_key_type! {
5584 pub struct WindowId;
5586}
5587
5588impl WindowId {
5589 pub fn as_u64(&self) -> u64 {
5591 self.0.as_ffi()
5592 }
5593}
5594
5595impl From<u64> for WindowId {
5596 fn from(value: u64) -> Self {
5597 WindowId(slotmap::KeyData::from_ffi(value))
5598 }
5599}
5600
5601#[derive(Deref, DerefMut)]
5604pub struct WindowHandle<V> {
5605 #[deref]
5606 #[deref_mut]
5607 pub(crate) any_handle: AnyWindowHandle,
5608 state_type: PhantomData<V>,
5609}
5610
5611impl<V> Debug for WindowHandle<V> {
5612 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5613 f.debug_struct("WindowHandle")
5614 .field("any_handle", &self.any_handle.id.as_u64())
5615 .finish()
5616 }
5617}
5618
5619impl<V: 'static + Render> WindowHandle<V> {
5620 pub fn new(id: WindowId) -> Self {
5623 WindowHandle {
5624 any_handle: AnyWindowHandle {
5625 id,
5626 state_type: TypeId::of::<V>(),
5627 },
5628 state_type: PhantomData,
5629 }
5630 }
5631
5632 #[cfg(any(test, feature = "test-support"))]
5636 pub fn root<C>(&self, cx: &mut C) -> Result<Entity<V>>
5637 where
5638 C: AppContext,
5639 {
5640 crate::Flatten::flatten(cx.update_window(self.any_handle, |root_view, _, _| {
5641 root_view
5642 .downcast::<V>()
5643 .map_err(|_| anyhow!("the type of the window's root view has changed"))
5644 }))
5645 }
5646
5647 pub fn update<C, R>(
5651 &self,
5652 cx: &mut C,
5653 update: impl FnOnce(&mut V, &mut Window, &mut Context<V>) -> R,
5654 ) -> Result<R>
5655 where
5656 C: AppContext,
5657 {
5658 cx.update_window(self.any_handle, |root_view, window, cx| {
5659 let view = root_view
5660 .downcast::<V>()
5661 .map_err(|_| anyhow!("the type of the window's root view has changed"))?;
5662
5663 Ok(view.update(cx, |view, cx| update(view, window, cx)))
5664 })?
5665 }
5666
5667 pub fn read<'a>(&self, cx: &'a App) -> Result<&'a V> {
5671 let x = cx
5672 .windows
5673 .get(self.id)
5674 .and_then(|window| {
5675 window
5676 .as_ref()
5677 .and_then(|window| window.root.clone())
5678 .map(|root_view| root_view.downcast::<V>())
5679 })
5680 .context("window not found")?
5681 .map_err(|_| anyhow!("the type of the window's root view has changed"))?;
5682
5683 Ok(x.read(cx))
5684 }
5685
5686 pub fn read_with<C, R>(&self, cx: &C, read_with: impl FnOnce(&V, &App) -> R) -> Result<R>
5690 where
5691 C: AppContext,
5692 {
5693 cx.read_window(self, |root_view, cx| read_with(root_view.read(cx), cx))
5694 }
5695
5696 pub fn entity<C>(&self, cx: &C) -> Result<Entity<V>>
5700 where
5701 C: AppContext,
5702 {
5703 cx.read_window(self, |root_view, _cx| root_view)
5704 }
5705
5706 pub fn is_active(&self, cx: &mut App) -> Option<bool> {
5711 cx.update_window(self.any_handle, |_, window, _| window.is_window_active())
5712 .ok()
5713 }
5714}
5715
5716impl<V> Copy for WindowHandle<V> {}
5717
5718impl<V> Clone for WindowHandle<V> {
5719 fn clone(&self) -> Self {
5720 *self
5721 }
5722}
5723
5724impl<V> PartialEq for WindowHandle<V> {
5725 fn eq(&self, other: &Self) -> bool {
5726 self.any_handle == other.any_handle
5727 }
5728}
5729
5730impl<V> Eq for WindowHandle<V> {}
5731
5732impl<V> Hash for WindowHandle<V> {
5733 fn hash<H: Hasher>(&self, state: &mut H) {
5734 self.any_handle.hash(state);
5735 }
5736}
5737
5738impl<V: 'static> From<WindowHandle<V>> for AnyWindowHandle {
5739 fn from(val: WindowHandle<V>) -> Self {
5740 val.any_handle
5741 }
5742}
5743
5744unsafe impl<V> Send for WindowHandle<V> {}
5745unsafe impl<V> Sync for WindowHandle<V> {}
5746
5747#[derive(Copy, Clone, PartialEq, Eq, Hash)]
5749pub struct AnyWindowHandle {
5750 pub(crate) id: WindowId,
5751 state_type: TypeId,
5752}
5753
5754impl AnyWindowHandle {
5755 pub fn window_id(&self) -> WindowId {
5757 self.id
5758 }
5759
5760 pub fn downcast<T: 'static>(&self) -> Option<WindowHandle<T>> {
5763 if TypeId::of::<T>() == self.state_type {
5764 Some(WindowHandle {
5765 any_handle: *self,
5766 state_type: PhantomData,
5767 })
5768 } else {
5769 None
5770 }
5771 }
5772
5773 pub fn update<C, R>(
5777 self,
5778 cx: &mut C,
5779 update: impl FnOnce(AnyView, &mut Window, &mut App) -> R,
5780 ) -> Result<R>
5781 where
5782 C: AppContext,
5783 {
5784 cx.update_window(self, update)
5785 }
5786
5787 pub fn read<T, C, R>(self, cx: &C, read: impl FnOnce(Entity<T>, &App) -> R) -> Result<R>
5791 where
5792 C: AppContext,
5793 T: 'static,
5794 {
5795 let view = self
5796 .downcast::<T>()
5797 .context("the type of the window's root view has changed")?;
5798
5799 cx.read_window(&view, read)
5800 }
5801}
5802
5803impl HasWindowHandle for Window {
5804 fn window_handle(&self) -> Result<raw_window_handle::WindowHandle<'_>, HandleError> {
5805 self.platform_window.window_handle()
5806 }
5807}
5808
5809impl HasDisplayHandle for Window {
5810 fn display_handle(
5811 &self,
5812 ) -> std::result::Result<raw_window_handle::DisplayHandle<'_>, HandleError> {
5813 self.platform_window.display_handle()
5814 }
5815}
5816
5817#[derive(Clone, Debug, Eq, PartialEq, Hash)]
5822pub enum ElementId {
5823 View(EntityId),
5825 Integer(u64),
5827 Name(SharedString),
5829 Uuid(Uuid),
5831 FocusHandle(FocusId),
5833 NamedInteger(SharedString, u64),
5835 Path(Arc<std::path::Path>),
5837 CodeLocation(core::panic::Location<'static>),
5839 NamedChild(Box<ElementId>, SharedString),
5841 OpaqueId([u8; 20]),
5843}
5844
5845impl ElementId {
5846 pub fn named_usize(name: impl Into<SharedString>, integer: usize) -> ElementId {
5848 Self::NamedInteger(name.into(), integer as u64)
5849 }
5850}
5851
5852impl Display for ElementId {
5853 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5854 match self {
5855 ElementId::View(entity_id) => write!(f, "view-{}", entity_id)?,
5856 ElementId::Integer(ix) => write!(f, "{}", ix)?,
5857 ElementId::Name(name) => write!(f, "{}", name)?,
5858 ElementId::FocusHandle(_) => write!(f, "FocusHandle")?,
5859 ElementId::NamedInteger(s, i) => write!(f, "{}-{}", s, i)?,
5860 ElementId::Uuid(uuid) => write!(f, "{}", uuid)?,
5861 ElementId::Path(path) => write!(f, "{}", path.display())?,
5862 ElementId::CodeLocation(location) => write!(f, "{}", location)?,
5863 ElementId::NamedChild(id, name) => write!(f, "{}-{}", id, name)?,
5864 ElementId::OpaqueId(opaque_id) => write!(f, "{:x?}", opaque_id)?,
5865 }
5866
5867 Ok(())
5868 }
5869}
5870
5871impl TryInto<SharedString> for ElementId {
5872 type Error = anyhow::Error;
5873
5874 fn try_into(self) -> anyhow::Result<SharedString> {
5875 if let ElementId::Name(name) = self {
5876 Ok(name)
5877 } else {
5878 anyhow::bail!("element id is not string")
5879 }
5880 }
5881}
5882
5883impl From<usize> for ElementId {
5884 fn from(id: usize) -> Self {
5885 ElementId::Integer(id as u64)
5886 }
5887}
5888
5889impl From<i32> for ElementId {
5890 fn from(id: i32) -> Self {
5891 Self::Integer(id as u64)
5892 }
5893}
5894
5895impl From<SharedString> for ElementId {
5896 fn from(name: SharedString) -> Self {
5897 ElementId::Name(name)
5898 }
5899}
5900
5901impl From<String> for ElementId {
5902 fn from(name: String) -> Self {
5903 ElementId::Name(name.into())
5904 }
5905}
5906
5907impl From<Arc<str>> for ElementId {
5908 fn from(name: Arc<str>) -> Self {
5909 ElementId::Name(name.into())
5910 }
5911}
5912
5913impl From<Arc<std::path::Path>> for ElementId {
5914 fn from(path: Arc<std::path::Path>) -> Self {
5915 ElementId::Path(path)
5916 }
5917}
5918
5919impl From<&'static str> for ElementId {
5920 fn from(name: &'static str) -> Self {
5921 ElementId::Name(SharedString::new_static(name))
5922 }
5923}
5924
5925impl<'a> From<&'a FocusHandle> for ElementId {
5926 fn from(handle: &'a FocusHandle) -> Self {
5927 ElementId::FocusHandle(handle.id)
5928 }
5929}
5930
5931impl From<(&'static str, EntityId)> for ElementId {
5932 fn from((name, id): (&'static str, EntityId)) -> Self {
5933 ElementId::NamedInteger(SharedString::new_static(name), id.as_u64())
5934 }
5935}
5936
5937impl From<(&'static str, usize)> for ElementId {
5938 fn from((name, id): (&'static str, usize)) -> Self {
5939 ElementId::NamedInteger(SharedString::new_static(name), id as u64)
5940 }
5941}
5942
5943impl From<(SharedString, usize)> for ElementId {
5944 fn from((name, id): (SharedString, usize)) -> Self {
5945 ElementId::NamedInteger(name, id as u64)
5946 }
5947}
5948
5949impl From<(&'static str, u64)> for ElementId {
5950 fn from((name, id): (&'static str, u64)) -> Self {
5951 ElementId::NamedInteger(SharedString::new_static(name), id)
5952 }
5953}
5954
5955impl From<Uuid> for ElementId {
5956 fn from(value: Uuid) -> Self {
5957 Self::Uuid(value)
5958 }
5959}
5960
5961impl From<(&'static str, u32)> for ElementId {
5962 fn from((name, id): (&'static str, u32)) -> Self {
5963 ElementId::NamedInteger(SharedString::new_static(name), id.into())
5964 }
5965}
5966
5967impl<T: Into<SharedString>> From<(ElementId, T)> for ElementId {
5968 fn from((id, name): (ElementId, T)) -> Self {
5969 ElementId::NamedChild(Box::new(id), name.into())
5970 }
5971}
5972
5973impl From<&'static core::panic::Location<'static>> for ElementId {
5974 fn from(location: &'static core::panic::Location<'static>) -> Self {
5975 ElementId::CodeLocation(*location)
5976 }
5977}
5978
5979impl From<[u8; 20]> for ElementId {
5980 fn from(opaque_id: [u8; 20]) -> Self {
5981 ElementId::OpaqueId(opaque_id)
5982 }
5983}
5984
5985#[derive(Clone)]
5988pub struct PaintQuad {
5989 pub bounds: Bounds<Pixels>,
5991 pub corner_radii: Corners<Pixels>,
5993 pub background: Background,
5995 pub border_widths: Edges<Pixels>,
5997 pub border_color: Hsla,
5999 pub border_style: BorderStyle,
6001 pub continuous_corners: bool,
6003 pub transform: TransformationMatrix,
6005 pub blend_mode: BlendMode,
6007}
6008
6009impl PaintQuad {
6010 pub fn corner_radii(self, corner_radii: impl Into<Corners<Pixels>>) -> Self {
6012 PaintQuad {
6013 corner_radii: corner_radii.into(),
6014 ..self
6015 }
6016 }
6017
6018 pub fn border_widths(self, border_widths: impl Into<Edges<Pixels>>) -> Self {
6020 PaintQuad {
6021 border_widths: border_widths.into(),
6022 ..self
6023 }
6024 }
6025
6026 pub fn border_color(self, border_color: impl Into<Hsla>) -> Self {
6028 PaintQuad {
6029 border_color: border_color.into(),
6030 ..self
6031 }
6032 }
6033
6034 pub fn background(self, background: impl Into<Background>) -> Self {
6036 PaintQuad {
6037 background: background.into(),
6038 ..self
6039 }
6040 }
6041}
6042
6043pub fn quad(
6045 bounds: Bounds<Pixels>,
6046 corner_radii: impl Into<Corners<Pixels>>,
6047 background: impl Into<Background>,
6048 border_widths: impl Into<Edges<Pixels>>,
6049 border_color: impl Into<Hsla>,
6050 border_style: BorderStyle,
6051) -> PaintQuad {
6052 PaintQuad {
6053 bounds,
6054 corner_radii: corner_radii.into(),
6055 background: background.into(),
6056 border_widths: border_widths.into(),
6057 border_color: border_color.into(),
6058 border_style,
6059 continuous_corners: false,
6060 transform: TransformationMatrix::unit(),
6061 blend_mode: BlendMode::Normal,
6062 }
6063}
6064
6065pub fn fill(bounds: impl Into<Bounds<Pixels>>, background: impl Into<Background>) -> PaintQuad {
6067 PaintQuad {
6068 bounds: bounds.into(),
6069 corner_radii: (0.).into(),
6070 background: background.into(),
6071 border_widths: (0.).into(),
6072 border_color: transparent_black(),
6073 border_style: BorderStyle::default(),
6074 continuous_corners: false,
6075 transform: TransformationMatrix::unit(),
6076 blend_mode: BlendMode::Normal,
6077 }
6078}
6079
6080pub fn outline(
6082 bounds: impl Into<Bounds<Pixels>>,
6083 border_color: impl Into<Hsla>,
6084 border_style: BorderStyle,
6085) -> PaintQuad {
6086 PaintQuad {
6087 bounds: bounds.into(),
6088 corner_radii: (0.).into(),
6089 background: transparent_black().into(),
6090 border_widths: (1.).into(),
6091 border_color: border_color.into(),
6092 border_style,
6093 continuous_corners: false,
6094 transform: TransformationMatrix::unit(),
6095 blend_mode: BlendMode::Normal,
6096 }
6097}
6098
6099#[cfg(test)]
6100mod tests {
6101 use super::*;
6102 use crate::{
6103 Context, QuitMode, Render, TestAppContext, WindowOptions, canvas, div, hsla, px, size,
6104 };
6105 use std::{cell::Cell, rc::Rc};
6106
6107 #[test]
6108 fn high_rate_input_avoids_inactive_window_throttling() {
6109 let default_inactive = Some(Duration::from_micros(33333));
6110 assert_eq!(
6111 frame_throttle_interval(true, false, false, false, false, false, default_inactive),
6112 default_inactive
6113 );
6114 assert_eq!(
6115 frame_throttle_interval(true, false, false, false, true, false, default_inactive),
6116 None
6117 );
6118 assert_eq!(
6119 frame_throttle_interval(true, false, false, false, true, true, default_inactive),
6120 Some(Duration::from_micros(16667)),
6121 "thermal pressure still caps high-rate input"
6122 );
6123 }
6124
6125 #[test]
6126 fn inactive_frame_interval_is_configurable() {
6127 let custom = Some(Duration::from_millis(16));
6128 assert_eq!(
6129 frame_throttle_interval(true, false, false, false, false, false, custom),
6130 custom
6131 );
6132 assert_eq!(
6133 frame_throttle_interval(true, false, false, false, false, false, None),
6134 None,
6135 "None disables inactive-window throttling"
6136 );
6137 }
6138
6139 #[test]
6143 fn draw_in_progress_tracks_element_arena_scope() {
6144 assert!(!draw_in_progress());
6145
6146 let scope = ElementArenaScope::enter();
6147 assert!(draw_in_progress());
6148
6149 let nested = ElementArenaScope::enter();
6150 assert!(draw_in_progress());
6151 drop(nested);
6152 assert!(draw_in_progress(), "outer draw is still in progress");
6153
6154 drop(scope);
6155 assert!(!draw_in_progress());
6156 }
6157
6158 struct EmptyView;
6159
6160 impl Render for EmptyView {
6161 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
6162 div()
6163 }
6164 }
6165
6166 #[test]
6167 fn open_window_propagates_platform_map_error() {
6168 let cx = TestAppContext::single();
6169 cx.test_platform()
6170 .fail_next_window_map("test window mapping failed");
6171
6172 let result =
6173 cx.update(|cx| cx.open_window(WindowOptions::default(), |_, cx| cx.new(|_| EmptyView)));
6174
6175 let error = match result {
6176 Ok(_) => panic!("window mapping unexpectedly succeeded"),
6177 Err(error) => error,
6178 };
6179 assert_eq!(error.to_string(), "test window mapping failed");
6180 assert!(cx.read(|cx| cx.windows().is_empty()));
6181 }
6182
6183 struct OpensWindowOnPaint {
6184 opened: Rc<Cell<bool>>,
6185 }
6186
6187 impl Render for OpensWindowOnPaint {
6188 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
6189 let opened = self.opened.clone();
6190 div()
6191 .size_full()
6192 .child(canvas(
6193 |_, _, _| {},
6194 move |_, _, _window, cx| {
6195 if !opened.replace(true) {
6196 cx.open_window(WindowOptions::default(), |_, cx| cx.new(|_| EmptyView))
6197 .unwrap();
6198 }
6199 },
6200 ))
6201 .child(div().child("after"))
6202 }
6203 }
6204
6205 #[test]
6209 fn opening_a_window_during_draw_keeps_outer_elements_alive() {
6210 let mut cx = TestAppContext::single();
6211 let opened = Rc::new(Cell::new(false));
6212 let window = cx.add_window({
6213 let opened = opened.clone();
6214 move |_, _| OpensWindowOnPaint { opened }
6215 });
6216
6217 assert!(opened.get());
6218 assert_eq!(cx.windows().len(), 2);
6219
6220 cx.update_window(window.into(), |_, window, cx| window.draw(cx).clear())
6221 .unwrap();
6222 }
6223
6224 #[gpui::test]
6225 fn test_appearance_change_runs_after_app_update(cx: &mut TestAppContext) {
6226 let window = cx.add_window(|_, _| EmptyView);
6227 let observed_appearance = Rc::new(Cell::new(None));
6228 let _subscription = window
6229 .update(cx, {
6230 let observed_appearance = observed_appearance.clone();
6231 move |_, window, _| {
6232 window.observe_window_appearance(move |window, _| {
6233 observed_appearance.set(Some(window.appearance()));
6234 })
6235 }
6236 })
6237 .unwrap();
6238 let test_window = cx.test_window(window.into());
6239
6240 cx.update(|_| {
6241 test_window.simulate_appearance_change(WindowAppearance::Dark);
6242 assert_eq!(observed_appearance.get(), None);
6243 });
6244 cx.run_until_parked();
6245
6246 assert_eq!(observed_appearance.get(), Some(WindowAppearance::Dark));
6247 }
6248
6249 struct RootView {
6250 explicit_size: bool,
6251 child_bounds: Rc<Cell<Bounds<Pixels>>>,
6252 }
6253
6254 impl Render for RootView {
6255 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
6256 let child_bounds = self.child_bounds.clone();
6257 let mut root = div().flex().flex_col().child(
6258 canvas(
6259 move |bounds, _, _| child_bounds.set(bounds),
6260 |_, _, _, _| {},
6261 )
6262 .size_full(),
6263 );
6264 if self.explicit_size {
6265 root = root.w(px(300.)).h(px(200.));
6266 }
6267 root
6268 }
6269 }
6270
6271 #[test]
6272 fn auto_sized_window_root_fills_the_window() {
6273 let mut cx = TestAppContext::single();
6274 let child_bounds = Rc::new(Cell::new(Bounds::default()));
6275 let window = cx.add_window({
6276 let child_bounds = child_bounds.clone();
6277 move |_, _| RootView {
6278 explicit_size: false,
6279 child_bounds,
6280 }
6281 });
6282
6283 let viewport_size = cx
6284 .update_window(window.into(), |_, window, cx| {
6285 window.draw(cx).clear();
6286 window.viewport_size()
6287 })
6288 .unwrap();
6289
6290 assert_eq!(child_bounds.get().size, viewport_size);
6291 }
6292
6293 #[test]
6294 fn explicitly_sized_window_root_keeps_its_size() {
6295 let mut cx = TestAppContext::single();
6296 let child_bounds = Rc::new(Cell::new(Bounds::default()));
6297 let window = cx.add_window({
6298 let child_bounds = child_bounds.clone();
6299 move |_, _| RootView {
6300 explicit_size: true,
6301 child_bounds,
6302 }
6303 });
6304
6305 cx.update_window(window.into(), |_, window, cx| {
6306 window.draw(cx).clear();
6307 })
6308 .unwrap();
6309
6310 assert_eq!(child_bounds.get().size, size(px(300.), px(200.)));
6311 }
6312
6313 fn scaled(value: f32) -> ScaledPixels {
6314 ScaledPixels(value)
6315 }
6316
6317 #[test]
6318 fn border_only_quad_strips_cover_asymmetric_borders_and_corners() {
6319 let bounds = Bounds::new(
6320 point(scaled(0.), scaled(0.)),
6321 size(scaled(100.), scaled(80.)),
6322 );
6323 let widths = Edges {
6324 top: scaled(6.),
6325 right: scaled(4.),
6326 bottom: scaled(8.),
6327 left: scaled(2.),
6328 };
6329 let radii = Corners {
6330 top_left: scaled(10.),
6331 top_right: scaled(12.),
6332 bottom_right: scaled(16.),
6333 bottom_left: scaled(14.),
6334 };
6335
6336 let strips = border_only_quad_strips(bounds, widths, radii).unwrap();
6337 assert_eq!(
6338 strips,
6339 [
6340 Bounds::from_corners(
6341 point(scaled(0.), scaled(0.)),
6342 point(scaled(100.), scaled(13.)),
6343 ),
6344 Bounds::from_corners(
6345 point(scaled(0.), scaled(63.)),
6346 point(scaled(100.), scaled(80.)),
6347 ),
6348 Bounds::from_corners(
6349 point(scaled(0.), scaled(13.)),
6350 point(scaled(3.), scaled(63.)),
6351 ),
6352 Bounds::from_corners(
6353 point(scaled(95.), scaled(13.)),
6354 point(scaled(100.), scaled(63.)),
6355 ),
6356 ]
6357 );
6358 }
6359
6360 #[test]
6361 fn border_only_quad_keeps_one_primitive_when_interior_is_too_small() {
6362 let bounds = Bounds::new(
6363 point(scaled(0.), scaled(0.)),
6364 size(scaled(10.), scaled(10.)),
6365 );
6366 let widths = Edges {
6367 top: scaled(5.),
6368 right: scaled(5.),
6369 bottom: scaled(5.),
6370 left: scaled(5.),
6371 };
6372
6373 assert!(border_only_quad_strips(bounds, widths, Corners::default()).is_none());
6374 }
6375
6376 struct BorderOnlyQuadView;
6377
6378 impl Render for BorderOnlyQuadView {
6379 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
6380 canvas(
6381 |_, _, _| {},
6382 |bounds, _, window, _| {
6383 window.paint_quad(outline(bounds, hsla(0., 0., 1., 1.), BorderStyle::Solid));
6384 },
6385 )
6386 .size(px(100.))
6387 }
6388 }
6389
6390 #[test]
6391 fn border_only_quad_emits_four_clipped_primitives() {
6392 let mut cx = TestAppContext::single();
6393 let window = cx.add_window(|_, _| BorderOnlyQuadView);
6394
6395 let primitive_count = cx
6396 .update_window(window.into(), |_, window, cx| {
6397 window.draw(cx).clear();
6398 window.rendered_frame.scene.quads.len()
6399 })
6400 .unwrap();
6401
6402 assert_eq!(primitive_count, 4);
6403 }
6404
6405 #[test]
6406 fn resource_profile_gpu_budget_reaches_the_platform() {
6407 let cx = TestAppContext::single();
6408
6409 let budget = cx.test_platform().gpu_resource_budget.lock().clone();
6410 assert_eq!(budget.instance_buffer_initial_size, 2 * 1024 * 1024);
6411 assert_eq!(budget.instance_buffer_max_size, 256 * 1024 * 1024);
6412 }
6413
6414 #[test]
6415 fn window_attention_is_forwarded_to_the_platform_window() {
6416 let mut cx = TestAppContext::single();
6417 let window = cx.add_window(|_, _| BorderOnlyQuadView);
6418 let window = AnyWindowHandle::from(window);
6419
6420 cx.update_window(window, |_, window, _| window.request_attention())
6421 .unwrap();
6422
6423 assert_eq!(cx.test_window(window).0.lock().attention_requests, 1);
6424 }
6425
6426 #[test]
6427 fn quit_mode_explicit_keeps_app_alive_after_last_window_closed() {
6428 let mut cx = TestAppContext::single();
6429 cx.update(|cx| cx.set_quit_mode(QuitMode::Explicit));
6430 assert_eq!(
6431 *cx.test_platform().last_quit_mode.lock(),
6432 Some(QuitMode::Explicit)
6433 );
6434 let window = cx.add_window(|_, _| BorderOnlyQuadView);
6435 let window = AnyWindowHandle::from(window);
6436
6437 cx.update_window(window, |_, window, _| window.remove_window())
6438 .unwrap();
6439
6440 assert!(!*cx.test_platform().did_quit.lock());
6441 }
6442
6443 #[test]
6444 fn quit_mode_last_window_closed_quits_after_last_window_closed() {
6445 let mut cx = TestAppContext::single();
6446 cx.update(|cx| cx.set_quit_mode(QuitMode::LastWindowClosed));
6447 let window = cx.add_window(|_, _| BorderOnlyQuadView);
6448 let window = AnyWindowHandle::from(window);
6449
6450 cx.update_window(window, |_, window, _| window.remove_window())
6451 .unwrap();
6452
6453 assert!(*cx.test_platform().did_quit.lock());
6454 }
6455
6456 #[test]
6457 fn quit_mode_runtime_change_applies_to_the_next_window_close() {
6458 let mut cx = TestAppContext::single();
6459 cx.update(|cx| cx.set_quit_mode(QuitMode::Explicit));
6460 let window = AnyWindowHandle::from(cx.add_window(|_, _| BorderOnlyQuadView));
6461
6462 cx.update(|cx| cx.set_quit_mode(QuitMode::LastWindowClosed));
6463 assert_eq!(
6464 *cx.test_platform().last_quit_mode.lock(),
6465 Some(QuitMode::LastWindowClosed)
6466 );
6467 cx.update_window(window, |_, window, _| window.remove_window())
6468 .unwrap();
6469
6470 assert!(*cx.test_platform().did_quit.lock());
6471 }
6472
6473 #[test]
6474 fn quit_mode_last_window_closed_waits_for_every_window() {
6475 let mut cx = TestAppContext::single();
6476 cx.update(|cx| cx.set_quit_mode(QuitMode::LastWindowClosed));
6477 let first = AnyWindowHandle::from(cx.add_window(|_, _| BorderOnlyQuadView));
6478 let second = AnyWindowHandle::from(cx.add_window(|_, _| BorderOnlyQuadView));
6479
6480 cx.update_window(first, |_, window, _| window.remove_window())
6481 .unwrap();
6482 assert!(!*cx.test_platform().did_quit.lock());
6483
6484 cx.update_window(second, |_, window, _| window.remove_window())
6485 .unwrap();
6486 assert!(*cx.test_platform().did_quit.lock());
6487 }
6488
6489 #[test]
6490 fn quit_mode_default_follows_platform_convention() {
6491 let mut cx = TestAppContext::single();
6492 let window = cx.add_window(|_, _| BorderOnlyQuadView);
6494 let window = AnyWindowHandle::from(window);
6495
6496 cx.update_window(window, |_, window, _| window.remove_window())
6497 .unwrap();
6498
6499 let expected = cfg!(not(target_os = "macos"));
6502 assert_eq!(*cx.test_platform().did_quit.lock(), expected);
6503 }
6504}