1#[cfg(feature = "profiler")]
2use crate::DebugFrameOverlayMode;
3#[cfg(any(feature = "inspector", debug_assertions))]
4use crate::Inspector;
5#[cfg(feature = "profiler")]
6use crate::profiler;
7use crate::{
8 Action, AnyDrag, AnyElement, AnyImageCache, AnyTooltip, AnyView, App, AppContext, Arena, Asset,
9 AsyncWindowContext, AtlasTile, AvailableSpace, BackdropBlur, Background, BorderStyle, Bounds,
10 BoxShadow, Capslock, Context, Corners, CursorHideMode, CursorStyle, Decorations, DevicePixels,
11 DispatchActionListener, DispatchNodeId, DispatchTree, DisplayId, Edges, Effect, Entity,
12 EntityId, EventEmitter, FileDropEvent, FontId, Global, GlobalElementId, GlyphId, GpuSpecs,
13 Hsla, InputHandler, IsZero, KeyBinding, KeyContext, KeyDownEvent, KeyEvent, Keystroke,
14 KeystrokeEvent, LayoutId, LineLayoutIndex, Modifiers, ModifiersChangedEvent, MonochromeSprite,
15 MouseButton, MouseEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels, PlatformAtlas,
16 PlatformDisplay, PlatformInput, PlatformInputHandler, PlatformWindow, Point, PolychromeSprite,
17 Priority, PromptButton, PromptLevel, Quad, Render, RenderGlyphParams, RenderImage,
18 RenderImageParams, RenderSvgParams, Replay, ResizeEdge, SMOOTH_SVG_SCALE_FACTOR,
19 SUBPIXEL_VARIANTS_X, SUBPIXEL_VARIANTS_Y, ScaledPixels, Scene, Shadow, SharedString, Size,
20 StrikethroughStyle, Style, SubpixelSprite, SubscriberSet, Subscription, SystemWindowTab,
21 SystemWindowTabController, TabStopMap, TaffyLayoutEngine, Task, TextInputConfiguration,
22 TextInputStateChange, TextRenderingMode, TextStyle, TextStyleRefinement, ThermalState,
23 TransformationMatrix, Underline, UnderlineStyle, WindowAppearance, WindowBackgroundAppearance,
24 WindowBounds, WindowControls, WindowDecorations, WindowOptions, WindowParams, WindowTextSystem,
25 WindowVisibility, point, prelude::*, px, rems, size, transparent_black,
26};
27
28use crate::gestures::{GestureTuning, RecognizedTouchGesture, TouchGestureRecognizer};
29use crate::interactive::TouchEvent;
30use anyhow::{Context as _, Result, anyhow};
31use collections::{FxHashMap, FxHashSet};
32#[cfg(target_os = "macos")]
33use core_video::pixel_buffer::CVPixelBuffer;
34use derive_more::{Deref, DerefMut};
35use futures::channel::oneshot;
36use gpui_util::post_inc;
37use gpui_util::{ResultExt, measure};
38use itertools::FoldWhile::{Continue, Done};
39use itertools::Itertools;
40use parking_lot::RwLock;
41use raw_window_handle::{HandleError, HasDisplayHandle, HasWindowHandle};
42use refineable::Refineable;
43use scheduler::Instant;
44use slotmap::SlotMap;
45use smallvec::SmallVec;
46use std::{
47 any::{Any, TypeId},
48 borrow::Cow,
49 cell::{Cell, RefCell},
50 cmp,
51 fmt::{Debug, Display},
52 hash::{Hash, Hasher},
53 marker::PhantomData,
54 mem,
55 ops::{DerefMut, Range},
56 rc::Rc,
57 sync::{
58 Arc, Weak,
59 atomic::{AtomicBool, AtomicUsize, Ordering::SeqCst},
60 },
61 thread::AccessError,
62 time::Duration,
63};
64use uuid::Uuid;
65
66pub(crate) mod a11y;
67mod prompts;
68
69pub use a11y::A11ySubtreeBuilder;
70
71use self::a11y::A11y;
72#[cfg(not(target_family = "wasm"))]
73use self::a11y::ROOT_NODE_ID;
74use crate::util::{
75 atomic_incr_if_not_zero, ceil_to_device_pixel, floor_to_device_pixel, round_half_toward_zero,
76 round_half_toward_zero_f64, round_stroke_to_device_pixel, round_to_device_pixel,
77};
78pub use prompts::*;
79
80pub const DEFAULT_WINDOW_SIZE: Size<Pixels> = size(px(1536.), px(1095.));
82
83pub const DEFAULT_ADDITIONAL_WINDOW_SIZE: Size<Pixels> = Size {
86 width: Pixels(900.),
87 height: Pixels(750.),
88};
89
90#[derive(Default, Copy, Clone, Debug, Eq, PartialEq)]
92pub enum DispatchPhase {
93 #[default]
98 Bubble,
99 Capture,
105}
106
107impl DispatchPhase {
108 #[inline]
110 pub fn bubble(self) -> bool {
111 self == DispatchPhase::Bubble
112 }
113
114 #[inline]
116 pub fn capture(self) -> bool {
117 self == DispatchPhase::Capture
118 }
119}
120
121struct WindowInvalidatorInner {
122 #[cfg(feature = "profiler")]
123 pub window_id: WindowId,
124 pub dirty: bool,
125 pub draw_phase: DrawPhase,
126 pub dirty_views: FxHashSet<EntityId>,
127 pub update_count: usize,
128 #[cfg(feature = "profiler")]
129 pub frame_dirty: FrameDirtyAccumulator,
130 pub platform_waker: Option<Rc<dyn Fn()>>,
131}
132
133#[cfg(feature = "profiler")]
139#[derive(Default)]
140struct FrameDirtyAccumulator {
141 dirty_at: Option<Instant>,
142 invalidations: u64,
143}
144
145#[derive(Clone)]
146pub(crate) struct WindowInvalidator {
147 inner: Rc<RefCell<WindowInvalidatorInner>>,
148}
149
150impl WindowInvalidator {
151 pub fn new(#[allow(unused_variables)] window_id: WindowId) -> Self {
152 WindowInvalidator {
153 inner: Rc::new(RefCell::new(WindowInvalidatorInner {
154 #[cfg(feature = "profiler")]
155 window_id,
156 dirty: true,
157 draw_phase: DrawPhase::None,
158 dirty_views: FxHashSet::default(),
159 update_count: 0,
160 #[cfg(feature = "profiler")]
161 frame_dirty: FrameDirtyAccumulator::default(),
162 platform_waker: None,
163 })),
164 }
165 }
166
167 pub fn invalidate_view(&self, entity: EntityId, cx: &mut App) -> bool {
168 let mut inner = self.inner.borrow_mut();
169 inner.update_count += 1;
170 inner.dirty_views.insert(entity);
171 if inner.draw_phase == DrawPhase::None {
172 #[cfg(feature = "profiler")]
173 let dirty_at = Self::record_frame_dirty(&mut inner);
174 let became_dirty = !inner.dirty;
175 inner.dirty = true;
176 let waker = became_dirty.then(|| inner.platform_waker.clone()).flatten();
177 #[cfg(feature = "profiler")]
178 let window_id = inner.window_id;
179 drop(inner);
180 #[cfg(feature = "profiler")]
181 if became_dirty {
182 profiler::journal::record_frame_pending(window_id, dirty_at);
183 }
184 cx.push_effect(Effect::Notify { emitter: entity });
185 if let Some(waker) = waker {
186 waker();
187 }
188 true
189 } else {
190 false
191 }
192 }
193
194 pub fn is_dirty(&self) -> bool {
195 self.inner.borrow().dirty
196 }
197
198 pub fn set_dirty(&self, dirty: bool) {
199 let mut inner = self.inner.borrow_mut();
200 let became_dirty = dirty && !inner.dirty;
201 inner.dirty = dirty;
202 if dirty {
203 inner.update_count += 1;
204 }
205 #[cfg(feature = "profiler")]
206 let dirty_at = dirty.then(|| Self::record_frame_dirty(&mut inner));
207 let waker = became_dirty.then(|| inner.platform_waker.clone()).flatten();
208 #[cfg(feature = "profiler")]
209 let window_id = inner.window_id;
210 drop(inner);
211 #[cfg(feature = "profiler")]
212 if became_dirty && let Some(dirty_at) = dirty_at {
213 profiler::journal::record_frame_pending(window_id, dirty_at);
214 }
215 if let Some(waker) = waker {
216 waker();
217 }
218 }
219
220 pub fn set_platform_waker(&self, waker: Option<Rc<dyn Fn()>>) {
221 let mut inner = self.inner.borrow_mut();
222 inner.platform_waker = waker;
223 let waker = inner.dirty.then(|| inner.platform_waker.clone()).flatten();
224 drop(inner);
225 if let Some(waker) = waker {
226 waker();
227 }
228 }
229
230 pub fn wake_platform(&self) {
234 let waker = self.inner.borrow().platform_waker.clone();
235 if let Some(waker) = waker {
236 waker();
237 }
238 }
239
240 pub fn set_phase(&self, phase: DrawPhase) {
241 self.inner.borrow_mut().draw_phase = phase
242 }
243
244 pub fn update_count(&self) -> usize {
245 self.inner.borrow().update_count
246 }
247
248 #[cfg(feature = "profiler")]
249 fn record_frame_dirty(inner: &mut WindowInvalidatorInner) -> Instant {
250 let dirty_at = *inner.frame_dirty.dirty_at.get_or_insert_with(Instant::now);
251 inner.frame_dirty.invalidations += 1;
252 dirty_at
253 }
254
255 #[cfg(feature = "profiler")]
256 fn take_frame_dirty(&self) -> FrameDirtyAccumulator {
257 mem::take(&mut self.inner.borrow_mut().frame_dirty)
258 }
259
260 pub fn take_views(&self) -> FxHashSet<EntityId> {
261 mem::take(&mut self.inner.borrow_mut().dirty_views)
262 }
263
264 pub fn replace_views(&self, views: FxHashSet<EntityId>) {
265 self.inner.borrow_mut().dirty_views = views;
266 }
267
268 pub fn not_drawing(&self) -> bool {
269 self.inner.borrow().draw_phase == DrawPhase::None
270 }
271
272 #[track_caller]
273 pub fn debug_assert_paint(&self) {
274 debug_assert!(
275 matches!(self.inner.borrow().draw_phase, DrawPhase::Paint),
276 "this method can only be called during paint"
277 );
278 }
279
280 #[track_caller]
281 pub fn debug_assert_prepaint(&self) {
282 debug_assert!(
283 matches!(self.inner.borrow().draw_phase, DrawPhase::Prepaint),
284 "this method can only be called during request_layout, or prepaint"
285 );
286 }
287
288 #[track_caller]
289 pub fn debug_assert_paint_or_prepaint(&self) {
290 debug_assert!(
291 matches!(
292 self.inner.borrow().draw_phase,
293 DrawPhase::Paint | DrawPhase::Prepaint
294 ),
295 "this method can only be called during request_layout, prepaint, or paint"
296 );
297 }
298}
299
300type AnyObserver = Box<dyn FnMut(&mut Window, &mut App) -> bool + 'static>;
301
302pub(crate) type AnyWindowFocusListener =
303 Box<dyn FnMut(&WindowFocusEvent, &mut Window, &mut App) -> bool + 'static>;
304
305pub(crate) struct WindowFocusEvent {
306 pub(crate) previous_focus_path: SmallVec<[FocusId; 8]>,
307 pub(crate) current_focus_path: SmallVec<[FocusId; 8]>,
308}
309
310impl WindowFocusEvent {
311 pub fn is_focus_in(&self, focus_id: FocusId) -> bool {
312 !self.previous_focus_path.contains(&focus_id) && self.current_focus_path.contains(&focus_id)
313 }
314
315 pub fn is_focus_out(&self, focus_id: FocusId) -> bool {
316 self.previous_focus_path.contains(&focus_id) && !self.current_focus_path.contains(&focus_id)
317 }
318}
319
320pub struct FocusOutEvent {
322 pub blurred: WeakFocusHandle,
324}
325
326slotmap::new_key_type! {
327 pub struct FocusId;
329}
330
331thread_local! {
332 pub(crate) static ELEMENT_ARENA: RefCell<Arena> = RefCell::new(Arena::new(1024 * 1024));
335
336 static CURRENT_ELEMENT_ARENA: Cell<Option<*const RefCell<Arena>>> = const { Cell::new(None) };
340}
341
342fn draw_in_progress() -> bool {
353 CURRENT_ELEMENT_ARENA.with(|current| current.get().is_some())
354}
355
356#[inline(always)]
359pub(crate) fn with_element_arena<R>(callback: impl FnOnce(&mut Arena) -> R) -> R {
360 let mut callback = Some(callback);
361 let mut result = None;
362 let access = with_element_arena_erased(&mut |arena| {
363 result = Some(callback.take().expect("arena callback runs once")(arena));
364 });
365 drop(callback);
366 access.expect("cannot access a Thread Local Storage value during or after destruction");
367 result.expect("arena callback produces a result")
368}
369
370pub(crate) struct ElementArenaScope {
385 entered: *const RefCell<Arena>,
388 previous: Option<*const RefCell<Arena>>,
389 exited: bool,
390}
391
392impl ElementArenaScope {
393 pub(crate) fn enter(arena: &RefCell<Arena>) -> Self {
395 arena.borrow_mut().begin_scope();
396 let previous = CURRENT_ELEMENT_ARENA.with(|current| {
397 let prev = current.get();
398 current.set(Some(arena as *const RefCell<Arena>));
399 prev
400 });
401 Self {
402 entered: arena as *const RefCell<Arena>,
403 previous,
404 exited: false,
405 }
406 }
407
408 pub(crate) fn exit(mut self, arena: &RefCell<Arena>) -> ArenaClearNeeded {
417 assert!(
418 std::ptr::eq(self.entered, arena),
419 "ElementArenaScope::exit called with a different arena than was entered"
420 );
421 self.exited = true;
422 ArenaClearNeeded::new(arena)
427 }
428}
429
430impl Drop for ElementArenaScope {
431 fn drop(&mut self) {
432 CURRENT_ELEMENT_ARENA.with(|current| {
439 current.set(self.previous);
440 });
441 unsafe { &*self.entered }.borrow_mut().end_scope();
445 if !self.exited && !std::thread::panicking() {
446 debug_assert!(false, "ElementArenaScope dropped without calling exit()");
447 log::error!(
448 "ElementArenaScope dropped without calling exit(); \
449 the arena clear for this draw was never requested"
450 );
451 }
452 }
453}
454
455#[must_use]
457pub struct ArenaClearNeeded {
458 arena: *const RefCell<Arena>,
461}
462
463impl ArenaClearNeeded {
464 fn new(arena: &RefCell<Arena>) -> Self {
467 Self {
468 arena: arena as *const RefCell<Arena>,
469 }
470 }
471
472 pub fn clear(self, cx: &mut App) {
481 assert!(
482 std::ptr::eq(self.arena, &cx.element_arena),
483 "ArenaClearNeeded::clear called with a different App than the draw ran against"
484 );
485 cx.element_arena.borrow_mut().clear();
486 }
487}
488
489pub(crate) type FocusMap = RwLock<SlotMap<FocusId, FocusRef>>;
490pub(crate) struct FocusRef {
491 pub(crate) ref_count: AtomicUsize,
492 pub(crate) tab_index: isize,
493 pub(crate) tab_stop: bool,
494}
495
496impl FocusId {
497 pub fn is_focused(&self, window: &Window) -> bool {
499 window.focus == Some(*self)
500 }
501
502 pub fn contains_focused(&self, window: &Window, cx: &App) -> bool {
505 window
506 .focused(cx)
507 .is_some_and(|focused| self.contains(focused.id, window))
508 }
509
510 pub fn within_focused(&self, window: &Window, cx: &App) -> bool {
513 let focused = window.focused(cx);
514 focused.is_some_and(|focused| focused.id.contains(*self, window))
515 }
516
517 pub(crate) fn contains(&self, other: Self, window: &Window) -> bool {
519 window
520 .rendered_frame
521 .dispatch_tree
522 .focus_contains(*self, other)
523 }
524}
525
526pub struct FocusHandle {
528 pub(crate) id: FocusId,
529 handles: Arc<FocusMap>,
530 pub tab_index: isize,
532 pub tab_stop: bool,
534}
535
536impl std::fmt::Debug for FocusHandle {
537 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
538 f.write_fmt(format_args!("FocusHandle({:?})", self.id))
539 }
540}
541
542impl FocusHandle {
543 pub(crate) fn new(handles: &Arc<FocusMap>) -> Self {
544 let id = handles.write().insert(FocusRef {
545 ref_count: AtomicUsize::new(1),
546 tab_index: 0,
547 tab_stop: false,
548 });
549
550 Self {
551 id,
552 tab_index: 0,
553 tab_stop: false,
554 handles: handles.clone(),
555 }
556 }
557
558 pub(crate) fn for_id(id: FocusId, handles: &Arc<FocusMap>) -> Option<Self> {
559 let lock = handles.read();
560 let focus = lock.get(id)?;
561 if atomic_incr_if_not_zero(&focus.ref_count) == 0 {
562 return None;
563 }
564 Some(Self {
565 id,
566 tab_index: focus.tab_index,
567 tab_stop: focus.tab_stop,
568 handles: handles.clone(),
569 })
570 }
571
572 pub fn tab_index(mut self, index: isize) -> Self {
574 self.tab_index = index;
575 if let Some(focus) = self.handles.write().get_mut(self.id) {
576 focus.tab_index = index;
577 }
578 self
579 }
580
581 pub fn tab_stop(mut self, tab_stop: bool) -> Self {
585 self.tab_stop = tab_stop;
586 if let Some(focus) = self.handles.write().get_mut(self.id) {
587 focus.tab_stop = tab_stop;
588 }
589 self
590 }
591
592 pub fn downgrade(&self) -> WeakFocusHandle {
594 WeakFocusHandle {
595 id: self.id,
596 handles: Arc::downgrade(&self.handles),
597 }
598 }
599
600 pub fn focus(&self, window: &mut Window, cx: &mut App) {
602 window.focus(self, cx)
603 }
604
605 pub fn is_focused(&self, window: &Window) -> bool {
607 self.id.is_focused(window)
608 }
609
610 pub fn contains_focused(&self, window: &Window, cx: &App) -> bool {
613 self.id.contains_focused(window, cx)
614 }
615
616 pub fn within_focused(&self, window: &Window, cx: &mut App) -> bool {
619 self.id.within_focused(window, cx)
620 }
621
622 pub fn contains(&self, other: &Self, window: &Window) -> bool {
624 self.id.contains(other.id, window)
625 }
626
627 pub fn dispatch_action(&self, action: &dyn Action, window: &mut Window, cx: &mut App) {
629 if let Some(node_id) = window
630 .rendered_frame
631 .dispatch_tree
632 .focusable_node_id(self.id)
633 {
634 window.dispatch_action_on_node(node_id, action, cx)
635 }
636 }
637}
638
639impl Clone for FocusHandle {
640 fn clone(&self) -> Self {
641 Self::for_id(self.id, &self.handles).unwrap()
642 }
643}
644
645impl PartialEq for FocusHandle {
646 fn eq(&self, other: &Self) -> bool {
647 self.id == other.id
648 }
649}
650
651impl Eq for FocusHandle {}
652
653impl Drop for FocusHandle {
654 fn drop(&mut self) {
655 self.handles
656 .read()
657 .get(self.id)
658 .unwrap()
659 .ref_count
660 .fetch_sub(1, SeqCst);
661 }
662}
663
664#[derive(Clone, Debug)]
666pub struct WeakFocusHandle {
667 pub(crate) id: FocusId,
668 pub(crate) handles: Weak<FocusMap>,
669}
670
671impl WeakFocusHandle {
672 pub fn upgrade(&self) -> Option<FocusHandle> {
674 let handles = self.handles.upgrade()?;
675 FocusHandle::for_id(self.id, &handles)
676 }
677}
678
679impl PartialEq for WeakFocusHandle {
680 fn eq(&self, other: &WeakFocusHandle) -> bool {
681 self.id == other.id
682 }
683}
684
685impl Eq for WeakFocusHandle {}
686
687impl PartialEq<FocusHandle> for WeakFocusHandle {
688 fn eq(&self, other: &FocusHandle) -> bool {
689 self.id == other.id
690 }
691}
692
693impl PartialEq<WeakFocusHandle> for FocusHandle {
694 fn eq(&self, other: &WeakFocusHandle) -> bool {
695 self.id == other.id
696 }
697}
698
699pub trait Focusable: 'static {
702 fn focus_handle(&self, cx: &App) -> FocusHandle;
704}
705
706impl<V: Focusable> Focusable for Entity<V> {
707 fn focus_handle(&self, cx: &App) -> FocusHandle {
708 self.read(cx).focus_handle(cx)
709 }
710}
711
712pub trait ManagedView: Focusable + EventEmitter<DismissEvent> + Render {}
715
716impl<M: Focusable + EventEmitter<DismissEvent> + Render> ManagedView for M {}
717
718pub struct DismissEvent;
720
721type FrameCallback = Box<dyn FnOnce(&mut Window, &mut App)>;
722
723pub(crate) type AnyMouseListener =
724 Box<dyn FnMut(&dyn Any, DispatchPhase, &mut Window, &mut App) + 'static>;
725
726#[derive(Clone)]
727pub(crate) struct CursorStyleRequest {
728 pub(crate) hitbox_id: Option<HitboxId>,
729 pub(crate) style: CursorStyle,
730}
731
732#[derive(Default, Eq, PartialEq)]
733pub(crate) struct HitTest {
734 pub(crate) ids: SmallVec<[HitboxId; 8]>,
735 pub(crate) hover_hitbox_count: usize,
736}
737
738#[derive(Clone, Copy, Debug, Eq, PartialEq)]
740pub enum WindowControlArea {
741 Drag,
743 Close,
745 Max,
747 Min,
749}
750
751#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
753pub struct HitboxId(u64);
754
755#[cfg(feature = "test-support")]
756impl HitboxId {
757 pub const fn placeholder() -> Self {
762 Self(0)
763 }
764}
765
766impl HitboxId {
767 pub fn is_hovered(self, window: &Window) -> bool {
774 if window.captured_hitbox == Some(self) {
776 return true;
777 }
778 if window.last_input_was_keyboard() {
779 return false;
780 }
781 self.hit_test(window)
782 }
783
784 pub(crate) fn is_hovered_ignoring_last_input(self, window: &Window) -> bool {
789 if window.captured_hitbox == Some(self) {
791 return true;
792 }
793 self.hit_test(window)
794 }
795
796 fn hit_test(self, window: &Window) -> bool {
797 let hit_test = &window.mouse_hit_test;
798 for id in hit_test.ids.iter().take(hit_test.hover_hitbox_count) {
799 if self == *id {
800 return true;
801 }
802 }
803 false
804 }
805
806 pub fn should_handle_scroll(self, window: &Window) -> bool {
811 window.mouse_hit_test.ids.contains(&self)
812 }
813
814 fn next(mut self) -> HitboxId {
815 HitboxId(self.0.wrapping_add(1))
816 }
817}
818
819#[derive(Clone, Copy, Debug, PartialEq)]
826pub struct EdgeFade {
827 pub bounds: Bounds<Pixels>,
829 pub band: Pixels,
831 pub top: bool,
833 pub bottom: bool,
835 pub left: bool,
837 pub right: bool,
839}
840
841#[derive(Clone, Debug, Deref)]
844pub struct Hitbox {
845 pub id: HitboxId,
847 #[deref]
849 pub bounds: Bounds<Pixels>,
850 pub content_mask: ContentMask<Pixels>,
852 pub behavior: HitboxBehavior,
854}
855
856impl Hitbox {
857 pub fn is_hovered(&self, window: &Window) -> bool {
874 self.id.is_hovered(window)
875 }
876
877 pub fn is_hovered_at(&self, position: Point<Pixels>, window: &Window) -> bool {
880 let hit_test = window.rendered_frame.hit_test(position);
881 hit_test
882 .ids
883 .iter()
884 .take(hit_test.hover_hitbox_count)
885 .any(|id| self.id == *id)
886 }
887
888 pub fn should_handle_scroll(&self, window: &Window) -> bool {
895 self.id.should_handle_scroll(window)
896 }
897}
898
899#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
901pub enum HitboxBehavior {
902 #[default]
904 Normal,
905
906 BlockMouse,
928
929 BlockMouseExceptScroll,
956}
957
958#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
960pub struct TooltipId(usize);
961
962impl TooltipId {
963 pub fn is_hovered(&self, window: &Window) -> bool {
965 window
966 .tooltip_bounds
967 .as_ref()
968 .is_some_and(|tooltip_bounds| {
969 tooltip_bounds.id == *self
970 && tooltip_bounds.bounds.contains(&window.mouse_position())
971 })
972 }
973}
974
975pub(crate) struct TooltipBounds {
976 id: TooltipId,
977 bounds: Bounds<Pixels>,
978}
979
980#[derive(Clone)]
981pub(crate) struct TooltipRequest {
982 id: TooltipId,
983 tooltip: AnyTooltip,
984}
985
986pub(crate) struct DeferredDraw {
987 current_view: EntityId,
988 priority: usize,
989 parent_node: DispatchNodeId,
990 element_id_stack: SmallVec<[ElementId; 32]>,
991 text_style_stack: Vec<TextStyleRefinement>,
992 content_mask: Option<ContentMask<Pixels>>,
993 rem_size: Pixels,
994 element: Option<AnyElement>,
995 absolute_offset: Point<Pixels>,
996 prepaint_range: Range<PrepaintStateIndex>,
997 paint_range: Range<PaintIndex>,
998}
999
1000pub(crate) struct Frame {
1001 pub(crate) focus: Option<FocusId>,
1002 pub(crate) window_active: bool,
1003 pub(crate) element_states: FxHashMap<(GlobalElementId, TypeId), ElementStateBox>,
1004 accessed_element_states: Vec<(GlobalElementId, TypeId)>,
1005 pub(crate) mouse_listeners: Vec<Option<AnyMouseListener>>,
1006 pub(crate) dispatch_tree: DispatchTree,
1007 pub(crate) scene: Scene,
1008 pub(crate) hitboxes: Vec<Hitbox>,
1009 pub(crate) window_control_hitboxes: Vec<(WindowControlArea, Hitbox)>,
1010 pub(crate) deferred_draws: Vec<DeferredDraw>,
1011 pub(crate) input_handlers: Vec<Option<PlatformInputHandler>>,
1012 pub(crate) tooltip_requests: Vec<Option<TooltipRequest>>,
1013 pub(crate) cursor_styles: Vec<CursorStyleRequest>,
1014 #[cfg(any(test, feature = "test-support"))]
1015 pub(crate) debug_bounds: FxHashMap<String, Bounds<Pixels>>,
1016 #[cfg(any(test, feature = "test-support"))]
1017 debug_bounds_records: Vec<(String, Bounds<Pixels>)>,
1018 #[cfg(any(feature = "inspector", debug_assertions))]
1019 pub(crate) next_inspector_instance_ids: FxHashMap<Rc<crate::InspectorElementPath>, usize>,
1020 #[cfg(any(feature = "inspector", debug_assertions))]
1021 pub(crate) inspector_hitboxes: FxHashMap<HitboxId, crate::InspectorElementId>,
1022 pub(crate) tab_stops: TabStopMap,
1023}
1024
1025#[derive(Clone, Default)]
1026pub(crate) struct PrepaintStateIndex {
1027 hitboxes_index: usize,
1028 tooltips_index: usize,
1029 deferred_draws_index: usize,
1030 dispatch_tree_index: usize,
1031 accessed_element_states_index: usize,
1032 line_layout_index: LineLayoutIndex,
1033}
1034
1035#[derive(Clone, Default)]
1036pub(crate) struct PaintIndex {
1037 scene_index: usize,
1038 #[cfg(any(test, feature = "test-support"))]
1039 debug_bounds_index: usize,
1040 mouse_listeners_index: usize,
1041 input_handlers_index: usize,
1042 cursor_styles_index: usize,
1043 accessed_element_states_index: usize,
1044 tab_handle_index: usize,
1045 line_layout_index: LineLayoutIndex,
1046}
1047
1048impl Frame {
1049 #[cfg(any(test, feature = "test-support"))]
1050 pub(crate) fn record_debug_bounds(&mut self, selector: String, bounds: Bounds<Pixels>) {
1051 self.debug_bounds.insert(selector.clone(), bounds);
1052 self.debug_bounds_records.push((selector, bounds));
1053 }
1054
1055 pub(crate) fn new(dispatch_tree: DispatchTree) -> Self {
1056 Frame {
1057 focus: None,
1058 window_active: false,
1059 element_states: FxHashMap::default(),
1060 accessed_element_states: Vec::new(),
1061 mouse_listeners: Vec::new(),
1062 dispatch_tree,
1063 scene: Scene::default(),
1064 hitboxes: Vec::new(),
1065 window_control_hitboxes: Vec::new(),
1066 deferred_draws: Vec::new(),
1067 input_handlers: Vec::new(),
1068 tooltip_requests: Vec::new(),
1069 cursor_styles: Vec::new(),
1070
1071 #[cfg(any(test, feature = "test-support"))]
1072 debug_bounds: FxHashMap::default(),
1073 #[cfg(any(test, feature = "test-support"))]
1074 debug_bounds_records: Vec::new(),
1075
1076 #[cfg(any(feature = "inspector", debug_assertions))]
1077 next_inspector_instance_ids: FxHashMap::default(),
1078
1079 #[cfg(any(feature = "inspector", debug_assertions))]
1080 inspector_hitboxes: FxHashMap::default(),
1081 tab_stops: TabStopMap::default(),
1082 }
1083 }
1084
1085 pub(crate) fn clear(&mut self) {
1086 self.element_states.clear();
1087 self.accessed_element_states.clear();
1088 self.mouse_listeners.clear();
1089 self.dispatch_tree.clear();
1090 self.scene.clear();
1091 self.input_handlers.clear();
1092 self.tooltip_requests.clear();
1093 self.cursor_styles.clear();
1094 self.hitboxes.clear();
1095 self.window_control_hitboxes.clear();
1096 self.deferred_draws.clear();
1097 self.tab_stops.clear();
1098 self.focus = None;
1099
1100 #[cfg(any(test, feature = "test-support"))]
1101 {
1102 self.debug_bounds.clear();
1103 self.debug_bounds_records.clear();
1104 }
1105
1106 #[cfg(any(feature = "inspector", debug_assertions))]
1107 {
1108 self.next_inspector_instance_ids.clear();
1109 self.inspector_hitboxes.clear();
1110 }
1111 }
1112
1113 pub(crate) fn cursor_style(&self, window: &Window) -> Option<CursorStyle> {
1114 self.cursor_styles
1115 .iter()
1116 .rev()
1117 .fold_while(None, |style, request| match request.hitbox_id {
1118 None => Done(Some(request.style)),
1119 Some(hitbox_id) => Continue(style.or_else(|| {
1120 hitbox_id
1121 .is_hovered_ignoring_last_input(window)
1122 .then_some(request.style)
1123 })),
1124 })
1125 .into_inner()
1126 }
1127
1128 pub(crate) fn hit_test(&self, position: Point<Pixels>) -> HitTest {
1129 let mut set_hover_hitbox_count = false;
1130 let mut hit_test = HitTest::default();
1131 for hitbox in self.hitboxes.iter().rev() {
1132 let bounds = hitbox.bounds.intersect(&hitbox.content_mask.bounds);
1133 if bounds.contains(&position) {
1134 hit_test.ids.push(hitbox.id);
1135 if !set_hover_hitbox_count
1136 && hitbox.behavior == HitboxBehavior::BlockMouseExceptScroll
1137 {
1138 hit_test.hover_hitbox_count = hit_test.ids.len();
1139 set_hover_hitbox_count = true;
1140 }
1141 if hitbox.behavior == HitboxBehavior::BlockMouse {
1142 break;
1143 }
1144 }
1145 }
1146 if !set_hover_hitbox_count {
1147 hit_test.hover_hitbox_count = hit_test.ids.len();
1148 }
1149 hit_test
1150 }
1151
1152 pub(crate) fn focus_path(&self) -> SmallVec<[FocusId; 8]> {
1153 self.focus
1154 .map(|focus_id| self.dispatch_tree.focus_path(focus_id))
1155 .unwrap_or_default()
1156 }
1157
1158 pub(crate) fn finish(&mut self, prev_frame: &mut Self) {
1159 for element_state_key in &self.accessed_element_states {
1160 if let Some((element_state_key, element_state)) =
1161 prev_frame.element_states.remove_entry(element_state_key)
1162 {
1163 self.element_states.insert(element_state_key, element_state);
1164 }
1165 }
1166
1167 self.scene.finish();
1168 }
1169}
1170
1171#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
1172enum InputModality {
1173 Mouse,
1174 Keyboard,
1175 Touch,
1176}
1177
1178pub struct Window {
1180 pub(crate) handle: AnyWindowHandle,
1181 pub(crate) invalidator: WindowInvalidator,
1182 pub(crate) removed: bool,
1183 pub(crate) platform_window: Box<dyn PlatformWindow>,
1184 display_id: Option<DisplayId>,
1185 is_resizable: bool,
1186 is_minimizable: bool,
1187 sprite_atlas: Arc<dyn PlatformAtlas>,
1188 text_system: Arc<WindowTextSystem>,
1189 text_rendering_mode: Rc<Cell<TextRenderingMode>>,
1190 rem_size: Pixels,
1191 rem_size_override_stack: SmallVec<[Pixels; 8]>,
1196 pub(crate) viewport_size: Size<Pixels>,
1197 layout_engine: Option<TaffyLayoutEngine>,
1198 pub(crate) root: Option<AnyView>,
1199 pub(crate) element_id_stack: SmallVec<[ElementId; 32]>,
1200 pub(crate) text_style_stack: Vec<TextStyleRefinement>,
1201 pub(crate) rendered_entity_stack: Vec<EntityId>,
1202 pub(crate) element_offset_stack: Vec<Point<Pixels>>,
1203 pub(crate) element_opacity: f32,
1204 pub(crate) edge_fade: Option<EdgeFade>,
1205 pub(crate) content_mask_stack: Vec<ContentMask<Pixels>>,
1206 pub(crate) requested_autoscroll: Option<Bounds<Pixels>>,
1207 last_text_input_configuration: Option<TextInputConfiguration>,
1211 focused_text_input_active: bool,
1212 pub(crate) image_cache_stack: Vec<AnyImageCache>,
1213 pub(crate) rendered_frame: Frame,
1214 pub(crate) next_frame: Frame,
1215 next_hitbox_id: HitboxId,
1216 pub(crate) next_tooltip_id: TooltipId,
1217 pub(crate) tooltip_bounds: Option<TooltipBounds>,
1218 pub(crate) next_frame_callbacks: Rc<RefCell<Vec<FrameCallback>>>,
1219 pub(crate) dirty_views: FxHashSet<EntityId>,
1220 focus_listeners: SubscriberSet<(), AnyWindowFocusListener>,
1221 pub(crate) focus_lost_listeners: SubscriberSet<(), AnyObserver>,
1222 focus_lost_path: SmallVec<[FocusId; 8]>,
1223 default_prevented: bool,
1224 mouse_position: Point<Pixels>,
1225 mouse_hit_test: HitTest,
1226 modifiers: Modifiers,
1227 capslock: Capslock,
1228 scale_factor: f32,
1229 pub(crate) bounds_observers: SubscriberSet<(), AnyObserver>,
1230 appearance: WindowAppearance,
1231 pub(crate) appearance_observers: SubscriberSet<(), AnyObserver>,
1232 pub(crate) button_layout_observers: SubscriberSet<(), AnyObserver>,
1233 active: Rc<Cell<bool>>,
1234 visibility: WindowVisibility,
1235 pub(crate) visibility_observers:
1236 SubscriberSet<(), Box<dyn FnMut(WindowVisibility, &mut Window, &mut App) -> bool>>,
1237 hovered: Rc<Cell<bool>>,
1238 pub(crate) needs_present: Rc<Cell<bool>>,
1239 pub(crate) input_rate_tracker: Rc<RefCell<InputRateTracker>>,
1242 #[cfg(feature = "profiler")]
1243 window_profiler: profiler::WindowProfiler,
1244 last_input_modality: InputModality,
1245 touch_gestures: TouchGestureRecognizer,
1246 touch_prediction_enabled: bool,
1247 long_press_timer: Option<Task<()>>,
1248 long_press_capture: Option<EntityId>,
1249 pub(crate) refreshing: bool,
1250 pub(crate) activation_observers: SubscriberSet<(), AnyObserver>,
1251 pub(crate) focus: Option<FocusId>,
1252 focus_enabled: bool,
1253 pub(crate) focus_generation: u64,
1256 pending_input: Option<PendingInput>,
1257 pending_modifier: ModifierState,
1258 pub(crate) pending_input_observers: SubscriberSet<(), AnyObserver>,
1259 prompt: Option<RenderablePromptHandle>,
1260 pub(crate) client_inset: Option<Pixels>,
1261 captured_hitbox: Option<HitboxId>,
1264 #[cfg(any(feature = "inspector", debug_assertions))]
1265 inspector: Option<Entity<Inspector>>,
1266 #[cfg(feature = "profiler")]
1267 debug_frame_overlay: crate::debug_overlay::DebugFrameOverlay,
1268 pub(crate) a11y: A11y,
1269}
1270
1271#[derive(Clone, Debug, Default)]
1272struct ModifierState {
1273 modifiers: Modifiers,
1274 saw_other_input: bool,
1275}
1276
1277#[derive(Clone, Debug)]
1280pub(crate) struct InputRateTracker {
1281 timestamps: Vec<Instant>,
1282 window: Duration,
1283 inputs_per_second: u32,
1284 sustain_until: Instant,
1285 sustain_duration: Duration,
1286}
1287
1288impl Default for InputRateTracker {
1289 fn default() -> Self {
1290 Self {
1291 timestamps: Vec::new(),
1292 window: Duration::from_millis(100),
1293 inputs_per_second: 60,
1294 sustain_until: Instant::now(),
1295 sustain_duration: Duration::from_secs(1),
1296 }
1297 }
1298}
1299
1300impl InputRateTracker {
1301 pub fn record_input(&mut self) {
1302 let now = Instant::now();
1303 self.timestamps.push(now);
1304 self.prune_old_timestamps(now);
1305
1306 let min_events = self.inputs_per_second as u128 * self.window.as_millis() / 1000;
1307 if self.timestamps.len() as u128 >= min_events {
1308 self.sustain_until = now + self.sustain_duration;
1309 }
1310 }
1311
1312 pub fn is_high_rate(&self) -> bool {
1313 Instant::now() < self.sustain_until
1314 }
1315
1316 fn prune_old_timestamps(&mut self, now: Instant) {
1317 self.timestamps
1318 .retain(|&t| now.duration_since(t) <= self.window);
1319 }
1320}
1321
1322#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1323pub(crate) enum DrawPhase {
1324 None,
1325 Prepaint,
1326 Paint,
1327 Focus,
1328}
1329
1330pub(crate) const PENDING_INPUT_TIMEOUT: Duration = Duration::from_secs(1);
1331
1332pub struct PendingInputStatus<'a> {
1334 keystrokes: &'a [Keystroke],
1335 timeout: Option<PendingInputTimeoutStatus>,
1336}
1337
1338impl<'a> PendingInputStatus<'a> {
1339 pub fn keystrokes(&self) -> &'a [Keystroke] {
1341 self.keystrokes
1342 }
1343
1344 pub fn timeout(&self) -> Option<PendingInputTimeoutStatus> {
1346 self.timeout
1347 }
1348}
1349
1350#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1352pub struct PendingInputTimeoutStatus {
1353 duration: Duration,
1354 remaining: Duration,
1355 started_at: Option<Instant>,
1356 paused: bool,
1357}
1358
1359impl PendingInputTimeoutStatus {
1360 pub fn duration(&self) -> Duration {
1362 self.duration
1363 }
1364
1365 pub fn remaining(&self, cx: &App) -> Duration {
1367 self.started_at
1368 .map(|started_at| {
1369 self.remaining
1370 .saturating_sub(cx.background_executor().now() - started_at)
1371 })
1372 .unwrap_or(self.remaining)
1373 }
1374
1375 pub fn is_paused(&self) -> bool {
1377 self.paused
1378 }
1379}
1380
1381#[derive(Debug)]
1382struct PendingInputTimeout {
1383 duration: Duration,
1384 remaining: Duration,
1385 state: PendingInputTimeoutState,
1386}
1387
1388#[derive(Debug)]
1389enum PendingInputTimeoutState {
1390 Running { started_at: Instant, task: Task<()> },
1391 Paused { pause: PendingInputTimeoutPause },
1392}
1393
1394#[derive(Debug)]
1395struct PendingInputTimeoutPause {
1396 owner_id: EntityId,
1397 _release_subscription: Subscription,
1398}
1399
1400impl PendingInputTimeout {
1401 fn is_paused(&self) -> bool {
1402 matches!(&self.state, PendingInputTimeoutState::Paused { .. })
1403 }
1404
1405 fn pause(&mut self, pause: PendingInputTimeoutPause, now: Instant) -> bool {
1406 match std::mem::replace(&mut self.state, PendingInputTimeoutState::Paused { pause }) {
1407 PendingInputTimeoutState::Running { started_at, task } => {
1408 self.remaining = self.remaining.saturating_sub(now - started_at);
1409 drop(task);
1410 true
1411 }
1412 previous_state @ PendingInputTimeoutState::Paused { .. } => {
1413 self.state = previous_state;
1414 false
1415 }
1416 }
1417 }
1418
1419 fn pause_owner_id(&self) -> Option<EntityId> {
1420 match &self.state {
1421 PendingInputTimeoutState::Running { .. } => None,
1422 PendingInputTimeoutState::Paused { pause } => Some(pause.owner_id),
1423 }
1424 }
1425
1426 fn resume(&mut self, owner_id: EntityId, started_at: Instant, task: Task<()>) -> bool {
1427 match std::mem::replace(
1428 &mut self.state,
1429 PendingInputTimeoutState::Running { started_at, task },
1430 ) {
1431 PendingInputTimeoutState::Paused { pause } if pause.owner_id == owner_id => true,
1432 previous_state => {
1433 self.state = previous_state;
1434 false
1435 }
1436 }
1437 }
1438
1439 fn reset_duration(&mut self, duration: Duration) {
1440 self.duration = duration;
1441 self.remaining = duration;
1442 }
1443
1444 fn status(&self) -> PendingInputTimeoutStatus {
1445 let (started_at, paused) = match &self.state {
1446 PendingInputTimeoutState::Running { started_at, .. } => (Some(*started_at), false),
1447 PendingInputTimeoutState::Paused { .. } => (None, true),
1448 };
1449 PendingInputTimeoutStatus {
1450 duration: self.duration,
1451 remaining: self.remaining,
1452 started_at,
1453 paused,
1454 }
1455 }
1456}
1457
1458#[derive(Default, Debug)]
1459struct PendingInput {
1460 keystrokes: SmallVec<[Keystroke; 1]>,
1461 focus: Option<FocusId>,
1462 timeout: Option<PendingInputTimeout>,
1463}
1464
1465pub(crate) struct ElementStateBox {
1466 pub(crate) inner: Box<dyn Any>,
1467 #[cfg(debug_assertions)]
1468 pub(crate) type_name: &'static str,
1469}
1470
1471fn default_bounds(display_id: Option<DisplayId>, cx: &mut App) -> WindowBounds {
1472 let active_window_bounds = cx
1477 .active_window()
1478 .and_then(|w| w.update(cx, |_, window, _| window.window_bounds()).ok());
1479
1480 const CASCADE_OFFSET: f32 = 25.0;
1481
1482 let display = display_id
1483 .map(|id| cx.find_display(id))
1484 .unwrap_or_else(|| cx.primary_display());
1485
1486 let default_placement = || Bounds::new(point(px(0.), px(0.)), DEFAULT_WINDOW_SIZE);
1487
1488 let display_bounds = display
1490 .as_ref()
1491 .map(|d| d.visible_bounds())
1492 .unwrap_or_else(default_placement);
1493
1494 let (
1495 Bounds {
1496 origin: base_origin,
1497 size: base_size,
1498 },
1499 window_bounds_ctor,
1500 ): (_, fn(Bounds<Pixels>) -> WindowBounds) = match active_window_bounds {
1501 Some(bounds) => match bounds {
1502 WindowBounds::Windowed(bounds) => (bounds, WindowBounds::Windowed),
1503 WindowBounds::Maximized(bounds) => (bounds, WindowBounds::Maximized),
1504 WindowBounds::Fullscreen(bounds) => (bounds, WindowBounds::Fullscreen),
1505 },
1506 None => (
1507 display
1508 .as_ref()
1509 .map(|d| d.default_bounds())
1510 .unwrap_or_else(default_placement),
1511 WindowBounds::Windowed,
1512 ),
1513 };
1514
1515 let cascade_offset = point(px(CASCADE_OFFSET), px(CASCADE_OFFSET));
1516 let proposed_origin = base_origin + cascade_offset;
1517 let proposed_bounds = Bounds::new(proposed_origin, base_size);
1518
1519 let display_right = display_bounds.origin.x + display_bounds.size.width;
1520 let display_bottom = display_bounds.origin.y + display_bounds.size.height;
1521 let window_right = proposed_bounds.origin.x + proposed_bounds.size.width;
1522 let window_bottom = proposed_bounds.origin.y + proposed_bounds.size.height;
1523
1524 let fits_horizontally = window_right <= display_right;
1525 let fits_vertically = window_bottom <= display_bottom;
1526
1527 let final_origin = match (fits_horizontally, fits_vertically) {
1528 (true, true) => proposed_origin,
1529 (false, true) => point(display_bounds.origin.x, base_origin.y),
1530 (true, false) => point(base_origin.x, display_bounds.origin.y),
1531 (false, false) => display_bounds.origin,
1532 };
1533 window_bounds_ctor(Bounds::new(final_origin, base_size))
1534}
1535
1536#[derive(Debug, Clone, Copy)]
1539pub struct GlassEffect {
1540 pub blur_radius: Pixels,
1542 pub lens: Pixels,
1544 pub reach: Pixels,
1547 pub magnify: f32,
1549 pub dispersion: f32,
1551 pub gain: f32,
1553 pub saturation: f32,
1556 pub tint: Hsla,
1558 pub edge: f32,
1560 pub edge_width: Pixels,
1562 pub edge_aa: Pixels,
1564}
1565
1566impl Window {
1567 pub(crate) fn new(
1568 handle: AnyWindowHandle,
1569 options: WindowOptions,
1570 cx: &mut App,
1571 ) -> Result<Self> {
1572 let WindowOptions {
1573 window_bounds,
1574 titlebar,
1575 focus,
1576 show,
1577 kind,
1578 is_movable,
1579 app_owns_titlebar_drag,
1580 inactive_frame_interval,
1581 is_resizable,
1582 is_minimizable,
1583 display_id,
1584 window_background,
1585 app_id,
1586 window_min_size,
1587 window_decorations,
1588 #[cfg_attr(
1589 not(any(target_os = "linux", target_os = "freebsd")),
1590 allow(unused_variables)
1591 )]
1592 icon,
1593 #[cfg_attr(not(target_os = "macos"), allow(unused_variables))]
1594 tabbing_identifier,
1595 } = options;
1596
1597 let initial_window_title = titlebar
1598 .as_ref()
1599 .and_then(|titlebar| titlebar.title.clone());
1600
1601 let window_bounds = window_bounds.unwrap_or_else(|| default_bounds(display_id, cx));
1602 let mut platform_window = cx.platform.open_window(
1603 handle,
1604 WindowParams {
1605 bounds: window_bounds.get_bounds(),
1606 titlebar,
1607 kind,
1608 is_movable,
1609 app_owns_titlebar_drag,
1610 is_resizable,
1611 is_minimizable,
1612 focus,
1613 show,
1614 display_id,
1615 window_min_size,
1616 app_id: app_id.clone(),
1617 icon,
1618 #[cfg(target_os = "macos")]
1619 tabbing_identifier,
1620 },
1621 )?;
1622
1623 let tab_bar_visible = platform_window.tab_bar_visible();
1624 SystemWindowTabController::init_visible(cx, tab_bar_visible);
1625 if let Some(tabs) = platform_window.tabbed_windows() {
1626 SystemWindowTabController::add_tab(cx, handle.window_id(), tabs);
1627 }
1628
1629 let display_id = platform_window.display().map(|display| display.id());
1630 let sprite_atlas = platform_window.sprite_atlas();
1631 let mouse_position = platform_window.mouse_position();
1632 let modifiers = platform_window.modifiers();
1633 let capslock = platform_window.capslock();
1634 let content_size = platform_window.content_size();
1635 let scale_factor = platform_window.scale_factor();
1636 let appearance = platform_window.appearance();
1637 let text_system = Arc::new(WindowTextSystem::new(cx.text_system().clone()));
1638 let invalidator = WindowInvalidator::new(handle.window_id());
1639 let active = Rc::new(Cell::new(platform_window.is_active()));
1640 let visibility = platform_window.visibility();
1641 #[cfg(feature = "profiler")]
1642 profiler::journal::record_window_visibility(handle.window_id(), visibility);
1643 let hovered = Rc::new(Cell::new(platform_window.is_hovered()));
1644 let needs_present = Rc::new(Cell::new(false));
1645 let next_frame_callbacks: Rc<RefCell<Vec<FrameCallback>>> = Default::default();
1646 let input_rate_tracker = Rc::new(RefCell::new(InputRateTracker::default()));
1647 let last_frame_time = Rc::new(Cell::new(None));
1648
1649 platform_window
1650 .request_decorations(window_decorations.unwrap_or(WindowDecorations::Server));
1651 platform_window.set_background_appearance(window_background);
1652
1653 match window_bounds {
1654 WindowBounds::Fullscreen(_) => platform_window.toggle_fullscreen(),
1655 WindowBounds::Maximized(_) => platform_window.zoom(),
1656 WindowBounds::Windowed(_) => {}
1657 }
1658
1659 let accessibility_force_disabled = cx.accessibility_force_disabled;
1660 let a11y_active_flag = Arc::new(AtomicBool::new(false));
1661
1662 #[cfg(not(target_family = "wasm"))]
1663 if !accessibility_force_disabled {
1664 let mut initial_root_node = accesskit::Node::new(accesskit::Role::Window);
1665 if let Some(title) = &initial_window_title {
1666 initial_root_node.set_label(title.to_string());
1667 }
1668 let initial_tree = accesskit::TreeUpdate {
1669 nodes: vec![(ROOT_NODE_ID, initial_root_node)],
1670 tree: Some(accesskit::Tree::new(ROOT_NODE_ID)),
1671 tree_id: accesskit::TreeId::ROOT,
1672 focus: ROOT_NODE_ID,
1673 };
1674 let (activation_sender, activation_receiver) = async_channel::unbounded::<()>();
1675 let (deactivation_sender, deactivation_receiver) = async_channel::unbounded::<()>();
1676 let (action_sender, action_receiver) =
1677 async_channel::unbounded::<accesskit::ActionRequest>();
1678
1679 platform_window.a11y_init(crate::A11yCallbacks {
1680 activation: {
1681 let active_flag = a11y_active_flag.clone();
1682 Box::new(move || {
1683 log::info!("Accessibility activated");
1684 active_flag.store(true, SeqCst);
1685 activation_sender.send_blocking(()).log_err();
1686 Some(initial_tree.clone())
1687 })
1688 },
1689 action: Box::new(move |request| {
1690 action_sender.send_blocking(request).log_err();
1691 }),
1692 deactivation: {
1693 let active_flag = a11y_active_flag.clone();
1694 Box::new(move || {
1695 log::info!("Accessibility deactivated");
1696 active_flag.store(false, SeqCst);
1697 deactivation_sender.send_blocking(()).log_err();
1698 })
1699 },
1700 });
1701
1702 let mut async_cx = cx.to_async();
1708 cx.foreground_executor()
1709 .spawn(async move {
1710 while activation_receiver.recv().await.is_ok() {
1711 handle
1712 .update(&mut async_cx, |_, window, _| window.refresh())
1713 .log_err();
1714 }
1715 })
1716 .detach();
1717
1718 let mut async_cx = cx.to_async();
1719 cx.foreground_executor()
1720 .spawn(async move {
1721 while deactivation_receiver.recv().await.is_ok() {
1722 handle
1723 .update(&mut async_cx, |_, window, _| window.refresh())
1724 .log_err();
1725 }
1726 })
1727 .detach();
1728
1729 let mut async_cx = cx.to_async();
1730 cx.foreground_executor()
1731 .spawn(async move {
1732 while let Ok(request) = action_receiver.recv().await {
1733 handle
1734 .update(&mut async_cx, |_, window, cx| {
1735 window.handle_a11y_action(request, cx);
1736 })
1737 .log_err();
1738 }
1739 })
1740 .detach();
1741 }
1742
1743 platform_window.on_close(Box::new({
1744 let window_id = handle.window_id();
1745 let mut cx = cx.to_async();
1746 move || {
1747 let _ = handle.update(&mut cx, |_, window, _| window.remove_window());
1748 let _ = cx.update(|cx| {
1749 SystemWindowTabController::remove_tab(cx, window_id);
1750 });
1751 }
1752 }));
1753 platform_window.on_request_frame(Box::new({
1754 let mut cx = cx.to_async();
1755 let invalidator = invalidator.clone();
1756 let active = active.clone();
1757 let needs_present = needs_present.clone();
1758 let next_frame_callbacks = next_frame_callbacks.clone();
1759 let input_rate_tracker = input_rate_tracker.clone();
1760 let mut deferred_force_render = false;
1761 move |request_frame_options| {
1762 #[cfg(feature = "profiler")]
1763 let _foreground_turn = profiler::journal::foreground_turn();
1764 if draw_in_progress() {
1780 log::debug!("deferring re-entrant window draw request");
1781 deferred_force_render |= request_frame_options.force_render;
1782 return;
1783 }
1784 let force_render =
1788 mem::take(&mut deferred_force_render) || request_frame_options.force_render;
1789
1790 let thermal_state = handle
1791 .update(&mut cx, |_, _, cx| cx.thermal_state())
1792 .log_err();
1793
1794 let min_frame_interval = if request_frame_options.require_presentation
1798 || (!request_frame_options.force_render
1799 && next_frame_callbacks.borrow().is_empty())
1800 {
1801 None
1802 } else if !active.get() && !input_rate_tracker.borrow_mut().is_high_rate() {
1803 inactive_frame_interval
1804 } else if let Some(ThermalState::Critical | ThermalState::Serious) = thermal_state {
1805 Some(Duration::from_micros(16667))
1806 } else {
1807 None
1808 };
1809
1810 let now = Instant::now();
1811 if let Some(min_interval) = min_frame_interval {
1812 if let Some(last_frame) = last_frame_time.get()
1813 && now.duration_since(last_frame) < min_interval
1814 {
1815 deferred_force_render |= force_render;
1817 handle
1819 .update(&mut cx, |_, window, _| {
1820 window.platform_window.schedule_frame();
1821 })
1822 .log_err();
1823 invalidator.wake_platform();
1828 return;
1829 }
1830 }
1831 last_frame_time.set(Some(now));
1832
1833 let pending_next_frame_callbacks = next_frame_callbacks.take();
1834 if !pending_next_frame_callbacks.is_empty() {
1835 handle
1836 .update(&mut cx, |_, window, cx| {
1837 for callback in pending_next_frame_callbacks {
1838 callback(window, cx);
1839 }
1840 })
1841 .log_err();
1842 }
1843
1844 let needs_present = request_frame_options.require_presentation
1848 || needs_present.get()
1849 || input_rate_tracker.borrow_mut().is_high_rate();
1850
1851 if invalidator.is_dirty() || force_render {
1852 measure("frame duration", || {
1853 handle
1854 .update(&mut cx, |_, window, cx| {
1855 if force_render {
1856 window.refresh();
1859 }
1860 let arena_clear_needed = window.draw(cx);
1861 window.present();
1862 arena_clear_needed.clear(cx);
1863 })
1864 .log_err();
1865 })
1866 } else if needs_present {
1867 handle
1868 .update(&mut cx, |_, window, _| window.present())
1869 .log_err();
1870 }
1871
1872 handle
1873 .update(&mut cx, |_, window, _| {
1874 if window.invalidator.is_dirty()
1875 || !window.next_frame_callbacks.borrow().is_empty()
1876 {
1877 window.platform_window.schedule_frame();
1878 }
1879 })
1880 .log_err();
1881
1882 if invalidator.is_dirty() || !next_frame_callbacks.borrow().is_empty() {
1888 invalidator.wake_platform();
1889 }
1890 }
1891 }));
1892 invalidator.set_platform_waker(platform_window.frame_waker());
1893 platform_window.on_visual_viewport_changed(Box::new({
1894 let mut cx = cx.to_async();
1895 move || {
1896 handle
1897 .update(&mut cx, |_, window, _| window.refresh())
1898 .log_err();
1899 }
1900 }));
1901 platform_window.on_insets_changed(Box::new({
1902 let mut cx = cx.to_async();
1903 move |_| {
1904 handle
1905 .update(&mut cx, |_, window, _| window.refresh())
1906 .log_err();
1907 }
1908 }));
1909 platform_window.on_resize(Box::new({
1910 let mut cx = cx.to_async();
1911 move |_, _| {
1912 handle
1913 .update(&mut cx, |_, window, cx| window.bounds_changed(cx))
1914 .log_err();
1915 }
1916 }));
1917 platform_window.on_moved(Box::new({
1918 let mut cx = cx.to_async();
1919 move || {
1920 handle
1921 .update(&mut cx, |_, window, cx| window.bounds_changed(cx))
1922 .log_err();
1923 }
1924 }));
1925 platform_window.on_appearance_changed(Box::new({
1926 let cx = cx.to_async();
1927 let foreground_executor = cx.foreground_executor().clone();
1928 move || {
1929 let mut cx = cx.clone();
1930 foreground_executor
1933 .spawn(async move {
1934 handle
1935 .update(&mut cx, |_, window, cx| window.appearance_changed(cx))
1936 .log_err();
1937 })
1938 .detach();
1939 }
1940 }));
1941 platform_window.on_button_layout_changed(Box::new({
1942 let mut cx = cx.to_async();
1943 move || {
1944 handle
1945 .update(&mut cx, |_, window, cx| window.button_layout_changed(cx))
1946 .log_err();
1947 }
1948 }));
1949 platform_window.on_active_status_change(Box::new({
1950 let mut cx = cx.to_async();
1951 move |active| {
1952 handle
1953 .update(&mut cx, |_, window, cx| {
1954 window.active.set(active);
1955 window.modifiers = window.platform_window.modifiers();
1956 window.capslock = window.platform_window.capslock();
1957 window
1958 .activation_observers
1959 .clone()
1960 .retain(&(), |callback| callback(window, cx));
1961
1962 window.bounds_changed(cx);
1963 window.refresh();
1964
1965 SystemWindowTabController::update_last_active(cx, window.handle.id);
1966 })
1967 .log_err();
1968 }
1969 }));
1970 platform_window.on_visibility_change(Box::new({
1971 let mut cx = cx.to_async();
1972 move |_| {
1973 handle
1974 .update(&mut cx, |_, window, cx| {
1975 window.refresh_visibility(cx);
1976 })
1977 .log_err();
1978 }
1979 }));
1980 platform_window.on_hover_status_change(Box::new({
1981 let mut cx = cx.to_async();
1982 move |active| {
1983 handle
1984 .update(&mut cx, |_, window, _| {
1985 window.hovered.set(active);
1986 window.refresh();
1987 })
1988 .log_err();
1989 }
1990 }));
1991 platform_window.on_input({
1992 let mut cx = cx.to_async();
1993 Box::new(move |event| {
1994 handle
1995 .update(&mut cx, |_, window, cx| window.dispatch_event(event, cx))
1996 .log_err()
1997 .unwrap_or(DispatchEventResult::default())
1998 })
1999 });
2000 platform_window.on_hit_test_window_control({
2001 let mut cx = cx.to_async();
2002 Box::new(move || {
2003 handle
2004 .update(&mut cx, |_, window, _cx| {
2005 for (area, hitbox) in &window.rendered_frame.window_control_hitboxes {
2006 if window.mouse_hit_test.ids.contains(&hitbox.id) {
2007 return Some(*area);
2008 }
2009 }
2010 None
2011 })
2012 .log_err()
2013 .unwrap_or(None)
2014 })
2015 });
2016 platform_window.on_move_tab_to_new_window({
2017 let mut cx = cx.to_async();
2018 Box::new(move || {
2019 handle
2020 .update(&mut cx, |_, _window, cx| {
2021 SystemWindowTabController::move_tab_to_new_window(cx, handle.window_id());
2022 })
2023 .log_err();
2024 })
2025 });
2026 platform_window.on_merge_all_windows({
2027 let mut cx = cx.to_async();
2028 Box::new(move || {
2029 handle
2030 .update(&mut cx, |_, _window, cx| {
2031 SystemWindowTabController::merge_all_windows(cx, handle.window_id());
2032 })
2033 .log_err();
2034 })
2035 });
2036 platform_window.on_select_next_tab({
2037 let mut cx = cx.to_async();
2038 Box::new(move || {
2039 handle
2040 .update(&mut cx, |_, _window, cx| {
2041 SystemWindowTabController::select_next_tab(cx, handle.window_id());
2042 })
2043 .log_err();
2044 })
2045 });
2046 platform_window.on_select_previous_tab({
2047 let mut cx = cx.to_async();
2048 Box::new(move || {
2049 handle
2050 .update(&mut cx, |_, _window, cx| {
2051 SystemWindowTabController::select_previous_tab(cx, handle.window_id())
2052 })
2053 .log_err();
2054 })
2055 });
2056 platform_window.on_toggle_tab_bar({
2057 let mut cx = cx.to_async();
2058 Box::new(move || {
2059 handle
2060 .update(&mut cx, |_, window, cx| {
2061 let tab_bar_visible = window.platform_window.tab_bar_visible();
2062 SystemWindowTabController::set_visible(cx, tab_bar_visible);
2063 })
2064 .log_err();
2065 })
2066 });
2067
2068 if let Some(app_id) = app_id {
2069 platform_window.set_app_id(&app_id);
2070 }
2071
2072 platform_window.map_window().unwrap();
2073
2074 Ok(Window {
2075 handle,
2076 invalidator,
2077 removed: false,
2078 platform_window,
2079 display_id,
2080 is_resizable,
2081 is_minimizable,
2082 sprite_atlas,
2083 text_system,
2084 text_rendering_mode: cx.text_rendering_mode.clone(),
2085 rem_size: px(16.),
2086 rem_size_override_stack: SmallVec::new(),
2087 viewport_size: content_size,
2088 layout_engine: Some(TaffyLayoutEngine::new()),
2089 root: None,
2090 element_id_stack: SmallVec::default(),
2091 text_style_stack: Vec::new(),
2092 rendered_entity_stack: Vec::new(),
2093 element_offset_stack: Vec::new(),
2094 content_mask_stack: Vec::new(),
2095 element_opacity: 1.0,
2096 edge_fade: None,
2097 requested_autoscroll: None,
2098 last_text_input_configuration: None,
2099 focused_text_input_active: false,
2100 rendered_frame: Frame::new(DispatchTree::new(cx.keymap.clone(), cx.actions.clone())),
2101 next_frame: Frame::new(DispatchTree::new(cx.keymap.clone(), cx.actions.clone())),
2102 next_frame_callbacks,
2103 next_hitbox_id: HitboxId(0),
2104 next_tooltip_id: TooltipId::default(),
2105 tooltip_bounds: None,
2106 dirty_views: FxHashSet::default(),
2107 focus_listeners: SubscriberSet::new(),
2108 focus_lost_listeners: SubscriberSet::new(),
2109 focus_lost_path: SmallVec::new(),
2110 default_prevented: true,
2111 mouse_position,
2112 mouse_hit_test: HitTest::default(),
2113 modifiers,
2114 capslock,
2115 scale_factor,
2116 bounds_observers: SubscriberSet::new(),
2117 appearance,
2118 appearance_observers: SubscriberSet::new(),
2119 button_layout_observers: SubscriberSet::new(),
2120 active,
2121 visibility,
2122 visibility_observers: SubscriberSet::new(),
2123 hovered,
2124 needs_present,
2125 input_rate_tracker,
2126 #[cfg(feature = "profiler")]
2127 window_profiler: profiler::WindowProfiler::new(handle.window_id())?,
2128 last_input_modality: InputModality::Mouse,
2129 touch_gestures: TouchGestureRecognizer::new(
2130 cx.platform
2131 .gestures()
2132 .map_or_else(GestureTuning::default, |gestures| gestures.tuning()),
2133 ),
2134 touch_prediction_enabled: true,
2135 long_press_timer: None,
2136 long_press_capture: None,
2137 refreshing: false,
2138 activation_observers: SubscriberSet::new(),
2139 focus: None,
2140 focus_enabled: true,
2141 focus_generation: 0,
2142 pending_input: None,
2143 pending_modifier: ModifierState::default(),
2144 pending_input_observers: SubscriberSet::new(),
2145 prompt: None,
2146 client_inset: None,
2147 image_cache_stack: Vec::new(),
2148 captured_hitbox: None,
2149 #[cfg(any(feature = "inspector", debug_assertions))]
2150 inspector: None,
2151 #[cfg(feature = "profiler")]
2152 debug_frame_overlay: crate::debug_overlay::DebugFrameOverlay::new(),
2153 a11y: A11y::new(
2154 a11y_active_flag,
2155 accessibility_force_disabled,
2156 initial_window_title,
2157 ),
2158 })
2159 }
2160
2161 pub(crate) fn new_focus_listener(
2162 &self,
2163 value: AnyWindowFocusListener,
2164 ) -> (Subscription, impl FnOnce() + use<>) {
2165 self.focus_listeners.insert((), value)
2166 }
2167}
2168
2169#[derive(Clone, Debug, Default, PartialEq, Eq)]
2170#[expect(missing_docs)]
2171pub struct DispatchEventResult {
2172 pub propagate: bool,
2173 pub default_prevented: bool,
2174}
2175
2176#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
2180#[repr(C)]
2181pub struct ContentMask<P: Clone + Debug + Default + PartialEq> {
2182 pub bounds: Bounds<P>,
2184 pub corner_radii: Corners<P>,
2187}
2188
2189impl<P: Clone + Debug + Default + PartialEq> ContentMask<P> {
2190 pub fn new(bounds: Bounds<P>) -> Self {
2192 Self {
2193 bounds,
2194 corner_radii: Corners::default(),
2195 }
2196 }
2197}
2198
2199impl ContentMask<Pixels> {
2200 pub fn scale(&self, factor: f32) -> ContentMask<ScaledPixels> {
2202 ContentMask {
2203 bounds: self.bounds.scale(factor),
2204 corner_radii: self.corner_radii.scale(factor),
2205 }
2206 }
2207
2208 pub fn intersect(&self, other: &Self) -> Self {
2216 let bounds = self.bounds.intersect(&other.bounds);
2217 let corner_radii = if bounds == other.bounds {
2218 other.corner_radii.clone()
2219 } else if bounds == self.bounds {
2220 self.corner_radii.clone()
2221 } else {
2222 Corners::default()
2223 };
2224 ContentMask {
2225 bounds,
2226 corner_radii,
2227 }
2228 }
2229}
2230
2231impl Window {
2232 fn mark_view_dirty(&mut self, view_id: EntityId) {
2233 for view_id in self
2236 .rendered_frame
2237 .dispatch_tree
2238 .view_path_reversed(view_id)
2239 {
2240 if !self.dirty_views.insert(view_id) {
2241 break;
2242 }
2243 }
2244 }
2245
2246 pub(crate) fn refresh_visibility(&mut self, cx: &mut App) {
2247 let visibility = self.platform_window.visibility();
2248 if self.visibility != visibility {
2249 self.visibility = visibility;
2250 #[cfg(feature = "profiler")]
2251 profiler::journal::record_window_visibility(self.handle.window_id(), visibility);
2252 self.visibility_observers
2253 .clone()
2254 .retain(&(), |callback| callback(visibility, self, cx));
2255 }
2256 #[cfg(feature = "profiler")]
2257 if self.invalidator.is_dirty() || self.needs_present.get() {
2258 profiler::journal::record_frame_pending(self.handle.window_id(), Instant::now());
2259 }
2260 }
2261
2262 pub fn visibility(&self) -> WindowVisibility {
2265 self.visibility
2266 }
2267
2268 pub fn is_visible(&self) -> bool {
2274 self.visibility.is_visible()
2275 }
2276
2277 pub fn observe_window_visibility(
2279 &self,
2280 mut callback: impl FnMut(WindowVisibility, &mut Window, &mut App) + 'static,
2281 ) -> Subscription {
2282 let (subscription, activate) = self.visibility_observers.insert(
2283 (),
2284 Box::new(move |visibility, window, cx| {
2285 callback(visibility, window, cx);
2286 true
2287 }),
2288 );
2289 activate();
2290 subscription
2291 }
2292
2293 pub fn observe_window_appearance(
2295 &self,
2296 mut callback: impl FnMut(&mut Window, &mut App) + 'static,
2297 ) -> Subscription {
2298 let (subscription, activate) = self.appearance_observers.insert(
2299 (),
2300 Box::new(move |window, cx| {
2301 callback(window, cx);
2302 true
2303 }),
2304 );
2305 activate();
2306 subscription
2307 }
2308
2309 pub fn observe_button_layout_changed(
2311 &self,
2312 mut callback: impl FnMut(&mut Window, &mut App) + 'static,
2313 ) -> Subscription {
2314 let (subscription, activate) = self.button_layout_observers.insert(
2315 (),
2316 Box::new(move |window, cx| {
2317 callback(window, cx);
2318 true
2319 }),
2320 );
2321 activate();
2322 subscription
2323 }
2324
2325 pub fn replace_root<E>(
2327 &mut self,
2328 cx: &mut App,
2329 build_view: impl FnOnce(&mut Window, &mut Context<E>) -> E,
2330 ) -> Entity<E>
2331 where
2332 E: 'static + Render,
2333 {
2334 let view = cx.new(|cx| build_view(self, cx));
2335 self.root = Some(view.clone().into());
2336 self.refresh();
2337 view
2338 }
2339
2340 pub fn root<E>(&self) -> Option<Option<Entity<E>>>
2342 where
2343 E: 'static + Render,
2344 {
2345 self.root
2346 .as_ref()
2347 .map(|view| view.clone().downcast::<E>().ok())
2348 }
2349
2350 pub fn window_handle(&self) -> AnyWindowHandle {
2352 self.handle
2353 }
2354
2355 pub fn refresh(&mut self) {
2357 if self.invalidator.not_drawing() {
2358 self.refreshing = true;
2359 self.invalidator.set_dirty(true);
2360 }
2361 }
2362
2363 pub fn remove_window(&mut self) {
2365 self.removed = true;
2366 }
2367
2368 pub fn focused(&self, cx: &App) -> Option<FocusHandle> {
2370 self.focus
2371 .and_then(|id| FocusHandle::for_id(id, &cx.focus_handles))
2372 }
2373
2374 pub fn focus_lost_restore_target(&self, cx: &App) -> Option<FocusHandle> {
2378 let (_leaf, ancestors) = self.focus_lost_path.split_last()?;
2379 ancestors.iter().rev().find_map(|id| {
2380 self.rendered_frame.dispatch_tree.focusable_node_id(*id)?;
2381 FocusHandle::for_id(*id, &cx.focus_handles)
2382 })
2383 }
2384
2385 pub fn focus(&mut self, handle: &FocusHandle, cx: &mut App) {
2387 if !self.focus_enabled || self.focus == Some(handle.id) {
2388 return;
2389 }
2390
2391 self.focus = Some(handle.id);
2392 self.focus_generation = self.focus_generation.wrapping_add(1);
2393 self.clear_pending_keystrokes(cx);
2394
2395 self.refresh();
2396 }
2397
2398 pub fn blur(&mut self, cx: &mut App) {
2400 self.clear_pending_keystrokes(cx);
2401
2402 if !self.focus_enabled {
2403 return;
2404 }
2405
2406 if self.focus.is_some() {
2407 self.focus_generation = self.focus_generation.wrapping_add(1);
2408 }
2409 self.focus = None;
2410 self.refresh();
2411 }
2412
2413 pub fn disable_focus(&mut self, cx: &mut App) {
2415 self.blur(cx);
2416 self.focus_enabled = false;
2417 }
2418
2419 pub fn focus_next(&mut self, cx: &mut App) {
2421 if !self.focus_enabled {
2422 return;
2423 }
2424
2425 if let Some(handle) = self.rendered_frame.tab_stops.next(self.focus.as_ref()) {
2426 self.focus(&handle, cx)
2427 }
2428 }
2429
2430 pub fn focus_prev(&mut self, cx: &mut App) {
2432 if !self.focus_enabled {
2433 return;
2434 }
2435
2436 if let Some(handle) = self.rendered_frame.tab_stops.prev(self.focus.as_ref()) {
2437 self.focus(&handle, cx)
2438 }
2439 }
2440
2441 pub fn text_system(&self) -> &Arc<WindowTextSystem> {
2443 &self.text_system
2444 }
2445
2446 pub fn text_style(&self) -> TextStyle {
2448 let mut style = TextStyle::default();
2449 for refinement in &self.text_style_stack {
2450 style.refine(refinement);
2451 }
2452 style
2453 }
2454
2455 pub fn is_maximized(&self) -> bool {
2459 self.platform_window.is_maximized()
2460 }
2461
2462 pub fn request_decorations(&self, decorations: WindowDecorations) {
2464 self.platform_window.request_decorations(decorations);
2465 }
2466
2467 pub fn set_exclusive_zone(&self, zone: Pixels) {
2473 self.platform_window.set_exclusive_zone(zone);
2474 }
2475
2476 #[cfg(all(target_os = "linux", feature = "wayland"))]
2481 pub fn set_exclusive_edge(&self, edge: crate::layer_shell::Anchor) {
2482 self.platform_window.set_exclusive_edge(edge);
2483 }
2484
2485 pub fn start_window_resize(&self, edge: ResizeEdge) {
2487 if self.is_resizable {
2488 self.platform_window.start_window_resize(edge);
2489 }
2490 }
2491
2492 pub fn set_input_region(&self, region: Option<&[Bounds<Pixels>]>) {
2499 self.platform_window.set_input_region(region);
2500 }
2501
2502 pub fn window_bounds(&self) -> WindowBounds {
2505 self.platform_window.window_bounds()
2506 }
2507
2508 pub fn inner_window_bounds(&self) -> WindowBounds {
2510 self.platform_window.inner_window_bounds()
2511 }
2512
2513 pub fn native_window_state(&self) -> Option<Vec<u8>> {
2516 self.platform_window.native_window_state()
2517 }
2518
2519 pub fn restore_native_window_state(&self, state: &[u8]) {
2522 self.platform_window.restore_native_window_state(state);
2523 }
2524
2525 pub fn dispatch_action(&mut self, action: Box<dyn Action>, cx: &mut App) {
2527 let focus_id = self.focused(cx).map(|handle| handle.id);
2528
2529 let window = self.handle;
2530 cx.defer(move |cx| {
2531 window
2532 .update(cx, |_, window, cx| {
2533 let node_id = window.focus_node_id_in_rendered_frame(focus_id);
2534 window.dispatch_action_on_node(node_id, action.as_ref(), cx);
2535 })
2536 .log_err();
2537 })
2538 }
2539
2540 pub(crate) fn dispatch_keystroke_observers(
2541 &mut self,
2542 keystroke: &Keystroke,
2543 action: Option<&dyn Action>,
2544 context_stack: Vec<KeyContext>,
2545 cx: &mut App,
2546 ) {
2547 cx.keystroke_observers.clone().retain(&(), move |callback| {
2548 (callback)(
2549 &KeystrokeEvent {
2550 keystroke: keystroke.clone(),
2551 action: action.map(|action| action.boxed_clone()),
2552 context_stack: context_stack.clone(),
2553 },
2554 self,
2555 cx,
2556 )
2557 });
2558 }
2559
2560 pub(crate) fn dispatch_keystroke_interceptors(
2561 &mut self,
2562 keystroke: &Keystroke,
2563 context_stack: Vec<KeyContext>,
2564 cx: &mut App,
2565 ) {
2566 cx.keystroke_interceptors
2567 .clone()
2568 .retain(&(), move |callback| {
2569 (callback)(
2570 &KeystrokeEvent {
2571 keystroke: keystroke.clone(),
2572 action: None,
2573 context_stack: context_stack.clone(),
2574 },
2575 self,
2576 cx,
2577 )
2578 });
2579 }
2580
2581 pub fn defer(&self, cx: &mut App, f: impl FnOnce(&mut Window, &mut App) + 'static) {
2584 let handle = self.handle;
2585 cx.defer(move |cx| {
2586 handle.update(cx, |_, window, cx| f(window, cx)).ok();
2587 });
2588 }
2589
2590 pub fn observe<T: 'static>(
2594 &mut self,
2595 observed: &Entity<T>,
2596 cx: &mut App,
2597 mut on_notify: impl FnMut(Entity<T>, &mut Window, &mut App) + 'static,
2598 ) -> Subscription {
2599 let entity_id = observed.entity_id();
2600 let observed = observed.downgrade();
2601 let window_handle = self.handle;
2602 cx.new_observer(
2603 entity_id,
2604 Box::new(move |cx| {
2605 window_handle
2606 .update(cx, |_, window, cx| {
2607 if let Some(handle) = observed.upgrade() {
2608 on_notify(handle, window, cx);
2609 true
2610 } else {
2611 false
2612 }
2613 })
2614 .unwrap_or(false)
2615 }),
2616 )
2617 }
2618
2619 pub fn subscribe<Emitter, Evt>(
2623 &mut self,
2624 entity: &Entity<Emitter>,
2625 cx: &mut App,
2626 mut on_event: impl FnMut(Entity<Emitter>, &Evt, &mut Window, &mut App) + 'static,
2627 ) -> Subscription
2628 where
2629 Emitter: EventEmitter<Evt>,
2630 Evt: 'static,
2631 {
2632 let entity_id = entity.entity_id();
2633 let handle = entity.downgrade();
2634 let window_handle = self.handle;
2635 cx.new_subscription(
2636 entity_id,
2637 (
2638 TypeId::of::<Evt>(),
2639 Box::new(move |event, cx| {
2640 window_handle
2641 .update(cx, |_, window, cx| {
2642 if let Some(entity) = handle.upgrade() {
2643 let event = event.downcast_ref().expect("invalid event type");
2644 on_event(entity, event, window, cx);
2645 true
2646 } else {
2647 false
2648 }
2649 })
2650 .unwrap_or(false)
2651 }),
2652 ),
2653 )
2654 }
2655
2656 pub fn observe_release<T>(
2658 &self,
2659 entity: &Entity<T>,
2660 cx: &mut App,
2661 mut on_release: impl FnOnce(&mut T, &mut Window, &mut App) + 'static,
2662 ) -> Subscription
2663 where
2664 T: 'static,
2665 {
2666 let entity_id = entity.entity_id();
2667 let window_handle = self.handle;
2668 let (subscription, activate) = cx.release_listeners.insert(
2669 entity_id,
2670 Box::new(move |entity, cx| {
2671 let entity = entity.downcast_mut().expect("invalid entity type");
2672 let _ = window_handle.update(cx, |_, window, cx| on_release(entity, window, cx));
2673 }),
2674 );
2675 activate();
2676 subscription
2677 }
2678
2679 pub fn to_async(&self, cx: &App) -> AsyncWindowContext {
2682 AsyncWindowContext::new_context(cx.to_async(), self.handle)
2683 }
2684
2685 pub fn on_next_frame(&self, callback: impl FnOnce(&mut Window, &mut App) + 'static) {
2687 RefCell::borrow_mut(&self.next_frame_callbacks).push(Box::new(callback));
2688 self.platform_window.schedule_frame();
2689 self.invalidator.wake_platform();
2692 }
2693
2694 pub fn request_animation_frame(&self) {
2707 let entity = self.current_view();
2708 self.on_next_frame(move |_, cx| cx.notify(entity));
2709 }
2710
2711 #[cfg(any(test, feature = "test-support"))]
2716 pub fn simulate_next_frame(&mut self, cx: &mut App) -> usize {
2717 let callbacks = self.next_frame_callbacks.take();
2718 let count = callbacks.len();
2719 for callback in callbacks {
2720 callback(self, cx);
2721 }
2722 count
2723 }
2724
2725 #[track_caller]
2729 pub fn spawn<AsyncFn, R>(&self, cx: &App, f: AsyncFn) -> Task<R>
2730 where
2731 R: 'static,
2732 AsyncFn: AsyncFnOnce(&mut AsyncWindowContext) -> R + 'static,
2733 {
2734 let handle = self.handle;
2735 cx.spawn(async move |app| {
2736 let mut async_window_cx = AsyncWindowContext::new_context(app.clone(), handle);
2737 f(&mut async_window_cx).await
2738 })
2739 }
2740
2741 #[track_caller]
2745 pub fn spawn_with_priority<AsyncFn, R>(
2746 &self,
2747 priority: Priority,
2748 cx: &App,
2749 f: AsyncFn,
2750 ) -> Task<R>
2751 where
2752 R: 'static,
2753 AsyncFn: AsyncFnOnce(&mut AsyncWindowContext) -> R + 'static,
2754 {
2755 let handle = self.handle;
2756 cx.spawn_with_priority(priority, async move |app| {
2757 let mut async_window_cx = AsyncWindowContext::new_context(app.clone(), handle);
2758 f(&mut async_window_cx).await
2759 })
2760 }
2761
2762 pub fn bounds_changed(&mut self, cx: &mut App) {
2768 self.scale_factor = self.platform_window.scale_factor();
2769 self.viewport_size = self.platform_window.content_size();
2770 self.display_id = self.platform_window.display().map(|display| display.id());
2771 self.mouse_position = self.platform_window.mouse_position();
2772
2773 self.refresh();
2774
2775 self.bounds_observers
2776 .clone()
2777 .retain(&(), |callback| callback(self, cx));
2778 }
2779
2780 pub fn bounds(&self) -> Bounds<Pixels> {
2782 self.platform_window.bounds()
2783 }
2784
2785 #[cfg(any(test, feature = "test-support"))]
2789 pub fn render_to_image(&self) -> anyhow::Result<image::RgbaImage> {
2790 self.platform_window
2791 .render_to_image(&self.rendered_frame.scene)
2792 }
2793
2794 #[cfg(any(test, feature = "test-support"))]
2799 pub fn painted_quads(&self) -> Vec<Quad> {
2800 self.rendered_frame.scene.quads.clone()
2801 }
2802
2803 #[cfg(any(test, feature = "test-support"))]
2805 pub fn painted_underlines(&self) -> Vec<Underline> {
2806 self.rendered_frame.scene.underlines.clone()
2807 }
2808
2809 pub fn resize(&mut self, size: Size<Pixels>) {
2811 self.platform_window.resize(size);
2812 }
2813
2814 pub fn is_fullscreen(&self) -> bool {
2816 self.platform_window.is_fullscreen()
2817 }
2818
2819 pub fn is_simple_fullscreen(&self) -> bool {
2823 self.platform_window.is_simple_fullscreen()
2824 }
2825
2826 pub(crate) fn appearance_changed(&mut self, cx: &mut App) {
2827 self.appearance = self.platform_window.appearance();
2828
2829 self.appearance_observers
2830 .clone()
2831 .retain(&(), |callback| callback(self, cx));
2832 }
2833
2834 pub(crate) fn button_layout_changed(&mut self, cx: &mut App) {
2835 self.button_layout_observers
2836 .clone()
2837 .retain(&(), |callback| callback(self, cx));
2838 }
2839
2840 pub fn appearance(&self) -> WindowAppearance {
2842 self.appearance
2843 }
2844
2845 pub fn viewport_size(&self) -> Size<Pixels> {
2847 self.viewport_size
2848 }
2849
2850 pub fn visual_viewport_bounds(&self) -> Bounds<Pixels> {
2856 self.platform_window.visual_viewport_bounds()
2857 }
2858
2859 pub fn fully_visible_bounds(&self) -> Bounds<Pixels> {
2864 let insets = self.platform_window.insets().effective();
2865 let viewport = self.viewport_size();
2866 let left = insets.left.max(Pixels::ZERO).min(viewport.width);
2867 let top = insets.top.max(Pixels::ZERO).min(viewport.height);
2868 let right = (viewport.width - insets.right.max(Pixels::ZERO)).max(left);
2869 let bottom = (viewport.height - insets.bottom.max(Pixels::ZERO)).max(top);
2870 let safe_bounds = Bounds::from_corners(point(left, top), point(right, bottom));
2871 let mut visible = safe_bounds.intersect(&self.visual_viewport_bounds());
2872 visible.size.width = visible.size.width.max(Pixels::ZERO);
2873 visible.size.height = visible.size.height.max(Pixels::ZERO);
2874 visible
2875 }
2876
2877 pub fn request_virtual_keyboard(&self) {
2882 self.platform_window.show_soft_keyboard();
2883 }
2884
2885 pub fn dismiss_virtual_keyboard(&self) {
2887 self.platform_window.hide_soft_keyboard();
2888 }
2889
2890 pub fn is_window_active(&self) -> bool {
2892 self.active.get()
2893 }
2894
2895 pub fn is_window_hovered(&self) -> bool {
2899 if cfg!(any(
2900 target_os = "windows",
2901 target_os = "linux",
2902 target_os = "freebsd"
2903 )) {
2904 self.hovered.get()
2905 } else {
2906 self.is_window_active()
2907 }
2908 }
2909
2910 pub fn zoom_window(&self) {
2912 self.platform_window.zoom();
2913 }
2914
2915 pub fn show_window_menu(&self, position: Point<Pixels>) {
2917 self.platform_window.show_window_menu(position)
2918 }
2919
2920 pub fn start_window_move(&self) {
2925 self.platform_window.start_window_move()
2926 }
2927
2928 pub fn set_client_inset(&mut self, inset: Pixels) {
2930 self.client_inset = Some(inset);
2931 self.platform_window.set_client_inset(inset);
2932 }
2933
2934 pub fn client_inset(&self) -> Option<Pixels> {
2936 self.client_inset
2937 }
2938
2939 pub fn window_decorations(&self) -> Decorations {
2941 self.platform_window.window_decorations()
2942 }
2943
2944 pub fn is_resizable(&self) -> bool {
2946 self.is_resizable
2947 }
2948
2949 pub fn is_minimizable(&self) -> bool {
2951 self.is_minimizable
2952 }
2953
2954 pub fn window_controls(&self) -> WindowControls {
2956 self.platform_window.window_controls()
2957 }
2958
2959 pub fn set_window_title(&mut self, title: &str) {
2961 self.platform_window.set_title(title);
2962 self.a11y.set_window_title(title.to_string());
2963 }
2964
2965 #[cfg(target_os = "macos")]
2967 pub fn set_traffic_light_position(&self, position: Point<Pixels>) {
2968 self.platform_window.set_traffic_light_position(position);
2969 }
2970
2971 pub fn set_app_id(&mut self, app_id: &str) {
2973 self.platform_window.set_app_id(app_id);
2974 }
2975
2976 pub fn set_background_appearance(&self, background_appearance: WindowBackgroundAppearance) {
2978 self.platform_window
2979 .set_background_appearance(background_appearance);
2980 }
2981
2982 pub fn set_window_edited(&mut self, edited: bool) {
2984 self.platform_window.set_edited(edited);
2985 }
2986
2987 pub fn set_document_path(&self, path: Option<&std::path::Path>) {
2990 self.platform_window.set_document_path(path);
2991 }
2992
2993 pub fn display(&self, cx: &App) -> Option<Rc<dyn PlatformDisplay>> {
2995 cx.platform
2996 .displays()
2997 .into_iter()
2998 .find(|display| Some(display.id()) == self.display_id)
2999 }
3000
3001 pub fn show_character_palette(&self) {
3003 self.platform_window.show_character_palette();
3004 }
3005
3006 pub fn scale_factor(&self) -> f32 {
3010 self.scale_factor
3011 }
3012
3013 #[cfg(any(test, feature = "test-support"))]
3015 pub fn set_scale_factor(&mut self, scale_factor: f32) {
3016 self.scale_factor = scale_factor;
3017 self.refresh();
3018 }
3019
3020 pub fn rem_size(&self) -> Pixels {
3023 self.rem_size_override_stack
3024 .last()
3025 .copied()
3026 .unwrap_or(self.rem_size)
3027 }
3028
3029 pub fn set_rem_size(&mut self, rem_size: impl Into<Pixels>) {
3032 self.rem_size = rem_size.into();
3033 }
3034
3035 pub fn with_global_id<R>(
3038 &mut self,
3039 element_id: ElementId,
3040 f: impl FnOnce(&GlobalElementId, &mut Self) -> R,
3041 ) -> R {
3042 self.with_id(element_id, |this| {
3043 let global_id = GlobalElementId(Arc::from(&*this.element_id_stack));
3044
3045 f(&global_id, this)
3046 })
3047 }
3048
3049 #[inline]
3051 pub fn with_id<R>(
3052 &mut self,
3053 element_id: impl Into<ElementId>,
3054 f: impl FnOnce(&mut Self) -> R,
3055 ) -> R {
3056 self.element_id_stack.push(element_id.into());
3057 let result = f(self);
3058 self.element_id_stack.pop();
3059 result
3060 }
3061
3062 #[inline]
3068 pub fn with_rem_size<F, R>(&mut self, rem_size: Option<impl Into<Pixels>>, f: F) -> R
3069 where
3070 F: FnOnce(&mut Self) -> R,
3071 {
3072 self.invalidator.debug_assert_paint_or_prepaint();
3073
3074 if let Some(rem_size) = rem_size {
3075 self.rem_size_override_stack.push(rem_size.into());
3076 let result = f(self);
3077 self.rem_size_override_stack.pop();
3078 result
3079 } else {
3080 f(self)
3081 }
3082 }
3083
3084 pub fn line_height(&self) -> Pixels {
3086 self.text_style().line_height_in_pixels(self.rem_size())
3087 }
3088
3089 #[inline]
3091 pub fn pixel_snap(&self, value: Pixels) -> Pixels {
3092 px(round_to_device_pixel(value.0, self.scale_factor()) / self.scale_factor())
3093 }
3094
3095 #[inline]
3097 pub fn pixel_snap_f64(&self, value: f64) -> f64 {
3098 let scale_factor = f64::from(self.scale_factor());
3099 round_half_toward_zero_f64(value * scale_factor) / scale_factor
3100 }
3101
3102 #[inline]
3104 pub fn pixel_snap_bounds(&self, bounds: Bounds<Pixels>) -> Bounds<Pixels> {
3105 bounds.map(|c| self.pixel_snap(c))
3106 }
3107
3108 #[inline]
3110 pub fn pixel_snap_point(&self, position: Point<Pixels>) -> Point<Pixels> {
3111 position.map(|c| self.pixel_snap(c))
3112 }
3113
3114 pub fn underline_bounds(
3116 &self,
3117 origin: Point<Pixels>,
3118 width: Pixels,
3119 style: &UnderlineStyle,
3120 ) -> Bounds<ScaledPixels> {
3121 let scale_factor = self.scale_factor();
3122 let thickness = self.snap_stroke(style.thickness);
3123 let height = if style.wavy {
3124 ScaledPixels(thickness.0 * 3.)
3125 } else {
3126 thickness
3127 };
3128 Bounds {
3129 origin: origin.map(|c| ScaledPixels(round_to_device_pixel(c.0, scale_factor))),
3130 size: size(self.snap_stroke(width), height),
3131 }
3132 }
3133
3134 pub fn paint_underline_with_exclusions(
3136 &mut self,
3137 origin: Point<Pixels>,
3138 width: Pixels,
3139 style: &UnderlineStyle,
3140 exclusions: &[Range<ScaledPixels>],
3141 ) {
3142 self.invalidator.debug_assert_paint();
3143 let underline = self.underline(origin, width, style);
3144 if exclusions.is_empty() {
3145 self.next_frame.scene.insert_primitive(underline);
3146 return;
3147 }
3148
3149 let bounds = underline.bounds.intersect(&underline.content_mask.bounds);
3150 if bounds.is_empty() {
3151 return;
3152 }
3153
3154 let mut exclusions = exclusions
3155 .iter()
3156 .filter_map(|span| {
3157 let start = span.start.max(bounds.left());
3158 let end = span.end.min(bounds.right());
3159 (start < end).then_some(start..end)
3160 })
3161 .collect::<SmallVec<[_; 4]>>();
3162 if exclusions.is_empty() {
3163 self.next_frame.scene.insert_primitive(underline);
3164 return;
3165 }
3166 exclusions.sort_unstable_by_key(|span| span.start);
3167
3168 let mut paint_span = |start, end| {
3169 self.next_frame.scene.insert_primitive(Underline {
3170 content_mask: ContentMask {
3171 bounds: Bounds::from_corners(
3172 point(start, bounds.top()),
3173 point(end, bounds.bottom()),
3174 ),
3175 corner_radii: underline.content_mask.corner_radii,
3176 },
3177 ..underline
3178 });
3179 };
3180 let mut start = bounds.left();
3181 for exclusion in exclusions {
3182 if start < exclusion.start {
3183 paint_span(start, exclusion.start);
3184 }
3185 start = start.max(exclusion.end);
3186 }
3187 if start < bounds.right() {
3188 paint_span(start, bounds.right());
3189 }
3190 }
3191
3192 fn underline(&self, origin: Point<Pixels>, width: Pixels, style: &UnderlineStyle) -> Underline {
3193 Underline {
3194 order: 0,
3195 pad: 0,
3196 bounds: self.underline_bounds(origin, width, style),
3197 content_mask: self.snapped_content_mask(),
3198 color: style
3199 .color
3200 .unwrap_or_default()
3201 .opacity(self.element_opacity_at(origin)),
3202 thickness: self.snap_stroke(style.thickness),
3203 wavy: style.wavy.into(),
3204 }
3205 }
3206
3207 #[inline]
3208 fn snap_bounds(&self, bounds: Bounds<Pixels>) -> Bounds<ScaledPixels> {
3209 let scale_factor = self.scale_factor();
3210 let left = round_to_device_pixel(bounds.left().0, scale_factor);
3211 let top = round_to_device_pixel(bounds.top().0, scale_factor);
3212 let right = round_to_device_pixel(bounds.right().0, scale_factor).max(left);
3213 let bottom = round_to_device_pixel(bounds.bottom().0, scale_factor).max(top);
3214 Bounds::from_corners(
3215 point(ScaledPixels(left), ScaledPixels(top)),
3216 point(ScaledPixels(right), ScaledPixels(bottom)),
3217 )
3218 }
3219
3220 #[inline]
3222 fn snap_stroke(&self, value: Pixels) -> ScaledPixels {
3223 ScaledPixels(round_stroke_to_device_pixel(value.0, self.scale_factor()))
3224 }
3225
3226 #[inline]
3227 fn snap_border_widths(&self, edges: Edges<Pixels>) -> Edges<ScaledPixels> {
3228 edges.map(|e| self.snap_stroke(*e))
3229 }
3230
3231 #[inline]
3233 fn cover_bounds(&self, bounds: Bounds<Pixels>) -> Bounds<ScaledPixels> {
3234 let scale_factor = self.scale_factor();
3235 let left = floor_to_device_pixel(bounds.left().0, scale_factor);
3236 let top = floor_to_device_pixel(bounds.top().0, scale_factor);
3237 let right = ceil_to_device_pixel(bounds.right().0, scale_factor).max(left);
3238 let bottom = ceil_to_device_pixel(bounds.bottom().0, scale_factor).max(top);
3239 Bounds::from_corners(
3240 point(ScaledPixels(left), ScaledPixels(top)),
3241 point(ScaledPixels(right), ScaledPixels(bottom)),
3242 )
3243 }
3244
3245 #[inline]
3246 fn snapped_content_mask(&self) -> ContentMask<ScaledPixels> {
3247 ContentMask {
3248 bounds: self.cover_bounds(self.content_mask().bounds),
3249 corner_radii: self.content_mask().corner_radii.scale(self.scale_factor()),
3250 }
3251 }
3252
3253 pub fn prevent_default(&mut self) {
3256 self.default_prevented = true;
3257 }
3258
3259 pub fn default_prevented(&self) -> bool {
3261 self.default_prevented
3262 }
3263
3264 pub fn is_action_available(&self, action: &dyn Action, cx: &App) -> bool {
3266 let node_id =
3267 self.focus_node_id_in_rendered_frame(self.focused(cx).map(|handle| handle.id));
3268 self.rendered_frame
3269 .dispatch_tree
3270 .is_action_available(action, node_id)
3271 }
3272
3273 pub fn is_action_available_in(&self, action: &dyn Action, focus_handle: &FocusHandle) -> bool {
3275 let node_id = self.focus_node_id_in_rendered_frame(Some(focus_handle.id));
3276 self.rendered_frame
3277 .dispatch_tree
3278 .is_action_available(action, node_id)
3279 }
3280
3281 pub fn mouse_position(&self) -> Point<Pixels> {
3283 self.mouse_position
3284 }
3285
3286 pub fn capture_pointer(&mut self, hitbox_id: HitboxId) {
3293 self.captured_hitbox = Some(hitbox_id);
3294 }
3295
3296 pub fn release_pointer(&mut self) {
3298 self.captured_hitbox = None;
3299 }
3300
3301 pub fn captured_hitbox(&self) -> Option<HitboxId> {
3303 self.captured_hitbox
3304 }
3305
3306 pub fn capture_long_press<T: 'static>(&mut self, entity: &Entity<T>) {
3312 self.long_press_capture = Some(entity.entity_id());
3313 }
3314
3315 pub fn has_long_press_capture<T: 'static>(&self, entity: &Entity<T>) -> bool {
3317 self.long_press_capture == Some(entity.entity_id())
3318 }
3319
3320 pub fn modifiers(&self) -> Modifiers {
3322 self.modifiers
3323 }
3324
3325 pub fn last_input_was_keyboard(&self) -> bool {
3328 self.last_input_modality == InputModality::Keyboard
3329 }
3330
3331 pub(crate) fn last_input_was_touch(&self) -> bool {
3332 self.last_input_modality == InputModality::Touch
3333 }
3334
3335 pub fn capslock(&self) -> Capslock {
3337 self.capslock
3338 }
3339
3340 #[profiling::function]
3343 pub fn draw(&mut self, cx: &mut App) -> ArenaClearNeeded {
3344 #[cfg(feature = "profiler")]
3347 let frame_dirty = self.invalidator.take_frame_dirty();
3348 #[cfg(feature = "profiler")]
3349 self.window_profiler.begin_draw();
3350
3351 let arena_scope = ElementArenaScope::enter(&cx.element_arena);
3354
3355 if self.platform_window.prepare_frame() {
3356 self.refresh();
3357 }
3358 self.invalidate_entities();
3359 cx.entities.clear_accessed();
3360 debug_assert!(self.rendered_entity_stack.is_empty());
3361 self.invalidator.set_dirty(false);
3362 self.requested_autoscroll = None;
3363
3364 if let Some(input_handler) = self.platform_window.take_input_handler() {
3369 if let Some(slot) = self
3370 .rendered_frame
3371 .input_handlers
3372 .iter_mut()
3373 .rev()
3374 .find(|h| h.is_none())
3375 {
3376 *slot = Some(input_handler);
3377 } else {
3378 self.rendered_frame.input_handlers.push(Some(input_handler));
3379 }
3380 }
3381 if !cx.mode.skip_drawing() {
3382 self.draw_roots(cx);
3383 #[cfg(feature = "profiler")]
3384 {
3385 let viewport_size = self.viewport_size;
3386 let scale_factor = self.scale_factor();
3387 self.debug_frame_overlay.paint(
3388 &mut self.next_frame.scene,
3389 viewport_size,
3390 scale_factor,
3391 );
3392 }
3393 }
3394 self.dirty_views.clear();
3395 self.next_frame.window_active = self.active.get();
3396
3397 let focused_text_input_active = if let Some(mut input_handler) = self
3403 .next_frame
3404 .input_handlers
3405 .iter_mut()
3406 .rev()
3407 .find_map(|h| h.take())
3408 {
3409 let accepts_text_input = input_handler.accepts_text_input(self, cx);
3410 self.platform_window.set_input_handler(input_handler);
3411 accepts_text_input
3412 } else {
3413 false
3414 };
3415 self.apply_text_input_configuration(cx);
3416 if focused_text_input_active != self.focused_text_input_active {
3417 self.focused_text_input_active = focused_text_input_active;
3418 self.platform_window
3419 .text_input_state_changed(if focused_text_input_active {
3420 TextInputStateChange::FocusGained
3421 } else {
3422 TextInputStateChange::FocusLost
3423 });
3424 }
3425
3426 self.layout_engine.as_mut().unwrap().clear();
3427 self.text_system().finish_frame();
3428 self.next_frame.finish(&mut self.rendered_frame);
3429
3430 self.invalidator.set_phase(DrawPhase::Focus);
3431 let previous_focus_path = self.rendered_frame.focus_path();
3432 let previous_window_active = self.rendered_frame.window_active;
3433 mem::swap(&mut self.rendered_frame, &mut self.next_frame);
3434 self.next_frame.clear();
3435 let current_focus_path = self.rendered_frame.focus_path();
3436 let current_window_active = self.rendered_frame.window_active;
3437 let mut focus_before_listeners = self.focus;
3438
3439 if previous_focus_path != current_focus_path
3440 || previous_window_active != current_window_active
3441 {
3442 if !previous_focus_path.is_empty() && current_focus_path.is_empty() {
3443 self.focus_lost_path = previous_focus_path.clone();
3444 self.focus_lost_listeners
3445 .clone()
3446 .retain(&(), |listener| listener(self, cx));
3447 self.focus_lost_path = SmallVec::new();
3448 focus_before_listeners = self.focus;
3453 }
3454
3455 let event = WindowFocusEvent {
3456 previous_focus_path: if previous_window_active {
3457 previous_focus_path
3458 } else {
3459 Default::default()
3460 },
3461 current_focus_path: if current_window_active {
3462 current_focus_path
3463 } else {
3464 Default::default()
3465 },
3466 };
3467 self.focus_listeners
3468 .clone()
3469 .retain(&(), |listener| listener(&event, self, cx));
3470 }
3471
3472 debug_assert!(self.rendered_entity_stack.is_empty());
3473 self.record_entities_accessed(cx);
3474 self.reset_cursor_style(cx);
3475 self.refreshing = false;
3476 self.invalidator.set_phase(DrawPhase::None);
3477 if self.focus != focus_before_listeners {
3482 self.refresh();
3483 }
3484 self.needs_present.set(true);
3485
3486 #[cfg(feature = "profiler")]
3487 {
3488 let draw_duration = self
3489 .window_profiler
3490 .end_draw(frame_dirty.dirty_at, frame_dirty.invalidations);
3491 self.debug_frame_overlay.record_frame(draw_duration);
3492 }
3493
3494 arena_scope.exit(&cx.element_arena)
3497 }
3498
3499 fn record_entities_accessed(&mut self, cx: &mut App) {
3500 let mut entities_ref = cx.entities.accessed_entities.get_mut();
3501 let mut entities = mem::take(entities_ref.deref_mut());
3502 let handle = self.handle;
3503 cx.record_entities_accessed(
3504 handle,
3505 self.invalidator.clone(),
3507 &entities,
3508 );
3509 let mut entities_ref = cx.entities.accessed_entities.get_mut();
3510 mem::swap(&mut entities, entities_ref.deref_mut());
3511 }
3512
3513 fn invalidate_entities(&mut self) {
3514 let mut views = self.invalidator.take_views();
3515 for entity in views.drain() {
3516 self.mark_view_dirty(entity);
3517 }
3518 self.invalidator.replace_views(views);
3519 }
3520
3521 #[profiling::function]
3522 fn present(&mut self) {
3523 #[cfg(feature = "profiler")]
3524 let _foreground_turn = profiler::journal::foreground_turn();
3525 #[cfg(feature = "profiler")]
3526 let present_start = Instant::now();
3527 self.platform_window.draw(&self.rendered_frame.scene);
3528 #[cfg(feature = "profiler")]
3529 self.window_profiler.record_present(
3530 present_start,
3531 Instant::now(),
3532 self.active.get(),
3533 !self.next_frame_callbacks.borrow().is_empty(),
3534 );
3535 self.needs_present.set(false);
3536 profiling::finish_frame!();
3537 }
3538
3539 #[cfg(all(test, feature = "profiler"))]
3541 pub fn present_if_needed(&mut self) {
3542 if self.needs_present.get() {
3543 self.present();
3544 }
3545 }
3546
3547 #[cfg(feature = "profiler")]
3549 pub fn input_latency_snapshot(&self) -> profiler::InputLatencySnapshot {
3550 self.window_profiler.input_latency_snapshot()
3551 }
3552
3553 #[cfg(feature = "profiler")]
3555 pub fn frame_duration_snapshot(&self) -> profiler::FrameDurationSnapshot {
3556 self.window_profiler.frame_duration_snapshot()
3557 }
3558
3559 #[cfg(feature = "profiler")]
3561 pub fn debug_frame_overlay_mode(&self) -> DebugFrameOverlayMode {
3562 self.debug_frame_overlay.mode()
3563 }
3564
3565 #[cfg(feature = "profiler")]
3567 pub fn set_debug_frame_overlay_mode(&mut self, mode: DebugFrameOverlayMode) {
3568 self.debug_frame_overlay.set_mode(mode);
3569 self.refresh();
3570 }
3571
3572 #[cfg(feature = "profiler")]
3575 pub fn cycle_debug_frame_overlay_mode(&mut self) {
3576 self.set_debug_frame_overlay_mode(self.debug_frame_overlay.mode().next());
3577 }
3578
3579 #[cfg(feature = "profiler")]
3582 pub fn reset_debug_frame_overlay_stats(&mut self) {
3583 self.debug_frame_overlay.reset_stats();
3584 self.refresh();
3585 }
3586
3587 fn draw_roots(&mut self, cx: &mut App) {
3588 self.invalidator.set_phase(DrawPhase::Prepaint);
3589 self.tooltip_bounds.take();
3590
3591 self.a11y.sync_active_flag();
3592 if self.a11y.is_active() {
3593 self.a11y.begin_frame();
3594 }
3595
3596 let _inspector_width: Pixels = rems(30.0).to_pixels(self.rem_size());
3597 let root_size = {
3598 #[cfg(any(feature = "inspector", debug_assertions))]
3599 {
3600 if self.inspector.is_some() {
3601 let mut size = self.viewport_size;
3602 size.width = (size.width - _inspector_width).max(px(0.0));
3603 size
3604 } else {
3605 self.viewport_size
3606 }
3607 }
3608 #[cfg(not(any(feature = "inspector", debug_assertions)))]
3609 {
3610 self.viewport_size
3611 }
3612 };
3613
3614 let scale_factor = self.scale_factor();
3618 let mut root_element = self.root.as_ref().unwrap().clone().into_any_element();
3619 let root_layout_id = root_element.request_layout(self, cx);
3620 self.layout_engine
3621 .as_mut()
3622 .unwrap()
3623 .stretch_auto_size_to_fill(root_layout_id, root_size, scale_factor);
3624 root_element.prepaint_as_root(Point::default(), root_size.into(), self, cx);
3625
3626 #[cfg(any(feature = "inspector", debug_assertions))]
3627 let inspector_element = self.prepaint_inspector(_inspector_width, cx);
3628
3629 self.prepaint_deferred_draws(cx);
3630
3631 let mut prompt_element = None;
3632 let mut active_drag_element = None;
3633 let mut tooltip_element = None;
3634 if let Some(prompt) = self.prompt.take() {
3635 let mut element = prompt.view.any_view().into_any_element();
3636 let prompt_layout_id = element.request_layout(self, cx);
3637 self.layout_engine
3638 .as_mut()
3639 .unwrap()
3640 .stretch_auto_size_to_fill(prompt_layout_id, root_size, scale_factor);
3641 element.prepaint_as_root(Point::default(), root_size.into(), self, cx);
3642 prompt_element = Some(element);
3643 self.prompt = Some(prompt);
3644 } else if let Some(active_drag) = cx.active_drag.take() {
3645 let mut element = active_drag.view.clone().into_any_element();
3646 let offset = self.mouse_position() - active_drag.cursor_offset;
3647 element.prepaint_as_root(offset, AvailableSpace::min_size(), self, cx);
3648 active_drag_element = Some(element);
3649 cx.active_drag = Some(active_drag);
3650 } else {
3651 tooltip_element = self.prepaint_tooltip(cx);
3652 }
3653
3654 self.mouse_hit_test = self.next_frame.hit_test(self.mouse_position);
3655
3656 self.invalidator.set_phase(DrawPhase::Paint);
3658 root_element.paint(self, cx);
3659
3660 #[cfg(any(feature = "inspector", debug_assertions))]
3661 self.paint_inspector(inspector_element, cx);
3662
3663 self.paint_deferred_draws(cx);
3664
3665 if let Some(mut prompt_element) = prompt_element {
3666 prompt_element.paint(self, cx);
3667 } else if let Some(mut drag_element) = active_drag_element {
3668 drag_element.paint(self, cx);
3669 } else if let Some(mut tooltip_element) = tooltip_element {
3670 tooltip_element.paint(self, cx);
3671 }
3672
3673 #[cfg(any(feature = "inspector", debug_assertions))]
3674 self.paint_inspector_hitbox(cx);
3675
3676 let a11y_active_start_of_frame = self.a11y.is_active();
3678 self.a11y.sync_active_flag();
3679 let a11y_active_end_of_frame = self.a11y.is_active();
3680
3681 let should_send_a11y_update = a11y_active_start_of_frame && a11y_active_end_of_frame;
3682
3683 if a11y_active_start_of_frame {
3684 let frame_info = crate::window::a11y::debug::FrameDebugInfo {
3687 viewport_size: self.viewport_size,
3688 scale_factor: self.scale_factor,
3689 tab_stop_count: self.next_frame.tab_stops.tab_stop_count(),
3690 };
3691 let tree_update = self.a11y.end_frame(frame_info);
3693
3694 if should_send_a11y_update {
3695 log::debug!(
3696 "Sending a11y tree update: {} nodes",
3697 tree_update.nodes.len()
3698 );
3699 self.platform_window.a11y_tree_update(tree_update);
3700 }
3701 }
3702 }
3703
3704 fn prepaint_tooltip(&mut self, cx: &mut App) -> Option<AnyElement> {
3705 for tooltip_request_index in (0..self.next_frame.tooltip_requests.len()).rev() {
3707 let Some(Some(tooltip_request)) = self
3708 .next_frame
3709 .tooltip_requests
3710 .get(tooltip_request_index)
3711 .cloned()
3712 else {
3713 log::error!("Unexpectedly absent TooltipRequest");
3714 continue;
3715 };
3716 let mut element = tooltip_request.tooltip.view.clone().into_any_element();
3717 let mouse_position = tooltip_request.tooltip.mouse_position;
3718 let tooltip_size = element.layout_as_root(AvailableSpace::min_size(), self, cx);
3719
3720 let mut tooltip_bounds =
3721 Bounds::new(mouse_position + point(px(1.), px(1.)), tooltip_size);
3722 let window_bounds = Bounds {
3723 origin: Point::default(),
3724 size: self.viewport_size(),
3725 };
3726
3727 if tooltip_bounds.right() > window_bounds.right() {
3728 let new_x = mouse_position.x - tooltip_bounds.size.width - px(1.);
3729 if new_x >= Pixels::ZERO {
3730 tooltip_bounds.origin.x = new_x;
3731 } else {
3732 tooltip_bounds.origin.x = cmp::max(
3733 Pixels::ZERO,
3734 tooltip_bounds.origin.x - tooltip_bounds.right() - window_bounds.right(),
3735 );
3736 }
3737 }
3738
3739 if tooltip_bounds.bottom() > window_bounds.bottom() {
3740 let new_y = mouse_position.y - tooltip_bounds.size.height - px(1.);
3741 if new_y >= Pixels::ZERO {
3742 tooltip_bounds.origin.y = new_y;
3743 } else {
3744 tooltip_bounds.origin.y = cmp::max(
3745 Pixels::ZERO,
3746 tooltip_bounds.origin.y - tooltip_bounds.bottom() - window_bounds.bottom(),
3747 );
3748 }
3749 }
3750
3751 let is_visible =
3755 (tooltip_request.tooltip.check_visible_and_update)(tooltip_bounds, self, cx);
3756 if !is_visible {
3757 continue;
3758 }
3759
3760 self.with_absolute_element_offset(tooltip_bounds.origin, |window| {
3761 element.prepaint(window, cx)
3762 });
3763
3764 self.tooltip_bounds = Some(TooltipBounds {
3765 id: tooltip_request.id,
3766 bounds: tooltip_bounds,
3767 });
3768 return Some(element);
3769 }
3770 None
3771 }
3772
3773 fn prepaint_deferred_draws(&mut self, cx: &mut App) {
3774 assert_eq!(self.element_id_stack.len(), 0);
3775
3776 let mut round_start = 0;
3787 let mut depth = 0;
3788 loop {
3789 let round_end = self.next_frame.deferred_draws.len();
3790 if round_start == round_end {
3791 break;
3792 }
3793 assert!(depth < 10, "Exceeded maximum (10) deferred depth");
3795 depth += 1;
3796
3797 let mut traversal_order = (round_start..round_end).collect::<SmallVec<[usize; 8]>>();
3799 traversal_order.sort_by_key(|ix| self.next_frame.deferred_draws[*ix].priority);
3800
3801 for deferred_draw_ix in traversal_order {
3802 let (element, parent_node, current_view, rem_size, absolute_offset, prepaint_range) = {
3803 let deferred_draw = &mut self.next_frame.deferred_draws[deferred_draw_ix];
3804 self.element_id_stack
3805 .clone_from(&deferred_draw.element_id_stack);
3806 self.text_style_stack
3807 .clone_from(&deferred_draw.text_style_stack);
3808 (
3809 deferred_draw.element.take(),
3810 deferred_draw.parent_node,
3811 deferred_draw.current_view,
3812 deferred_draw.rem_size,
3813 deferred_draw.absolute_offset,
3814 deferred_draw.prepaint_range.clone(),
3815 )
3816 };
3817 self.next_frame.dispatch_tree.set_active_node(parent_node);
3818
3819 let prepaint_start = self.prepaint_index();
3820 if let Some(mut element) = element {
3821 self.with_rendered_view(current_view, |window| {
3822 window.with_rem_size(Some(rem_size), |window| {
3823 window.with_absolute_element_offset(absolute_offset, |window| {
3824 element.prepaint(window, cx);
3825 });
3826 });
3827 });
3828 self.next_frame.deferred_draws[deferred_draw_ix].element = Some(element);
3829 } else {
3830 self.reuse_prepaint(prepaint_range);
3831 }
3832 let prepaint_end = self.prepaint_index();
3833 self.next_frame.deferred_draws[deferred_draw_ix].prepaint_range =
3834 prepaint_start..prepaint_end;
3835 }
3836
3837 self.element_id_stack.clear();
3838 self.text_style_stack.clear();
3839 round_start = round_end;
3840 }
3841 }
3842
3843 fn paint_deferred_draws(&mut self, cx: &mut App) {
3844 assert_eq!(self.element_id_stack.len(), 0);
3845
3846 if self.next_frame.deferred_draws.len() == 0 {
3849 return;
3850 }
3851
3852 let traversal_order = self.deferred_draw_traversal_order();
3853 let mut deferred_draws = mem::take(&mut self.next_frame.deferred_draws);
3854 for deferred_draw_ix in traversal_order {
3855 let mut deferred_draw = &mut deferred_draws[deferred_draw_ix];
3856 self.element_id_stack
3857 .clone_from(&deferred_draw.element_id_stack);
3858 self.next_frame
3859 .dispatch_tree
3860 .set_active_node(deferred_draw.parent_node);
3861
3862 let paint_start = self.paint_index();
3863 let content_mask = deferred_draw.content_mask;
3864 if let Some(element) = deferred_draw.element.as_mut() {
3865 self.with_rendered_view(deferred_draw.current_view, |window| {
3866 window.with_content_mask(content_mask, |window| {
3867 window.with_rem_size(Some(deferred_draw.rem_size), |window| {
3868 element.paint(window, cx);
3869 });
3870 })
3871 })
3872 } else {
3873 self.reuse_paint(deferred_draw.paint_range.clone());
3874 }
3875 let paint_end = self.paint_index();
3876 deferred_draw.paint_range = paint_start..paint_end;
3877 }
3878 self.next_frame.deferred_draws = deferred_draws;
3879 self.element_id_stack.clear();
3880 }
3881
3882 fn deferred_draw_traversal_order(&mut self) -> SmallVec<[usize; 8]> {
3883 let deferred_count = self.next_frame.deferred_draws.len();
3884 let mut sorted_indices = (0..deferred_count).collect::<SmallVec<[_; 8]>>();
3885 sorted_indices.sort_by_key(|ix| self.next_frame.deferred_draws[*ix].priority);
3886 sorted_indices
3887 }
3888
3889 pub(crate) fn prepaint_index(&self) -> PrepaintStateIndex {
3890 PrepaintStateIndex {
3891 hitboxes_index: self.next_frame.hitboxes.len(),
3892 tooltips_index: self.next_frame.tooltip_requests.len(),
3893 deferred_draws_index: self.next_frame.deferred_draws.len(),
3894 dispatch_tree_index: self.next_frame.dispatch_tree.len(),
3895 accessed_element_states_index: self.next_frame.accessed_element_states.len(),
3896 line_layout_index: self.text_system.layout_index(),
3897 }
3898 }
3899
3900 pub(crate) fn reuse_prepaint(&mut self, range: Range<PrepaintStateIndex>) {
3901 self.next_frame.hitboxes.extend(
3902 self.rendered_frame.hitboxes[range.start.hitboxes_index..range.end.hitboxes_index]
3903 .iter()
3904 .cloned(),
3905 );
3906 self.next_frame.tooltip_requests.extend(
3907 self.rendered_frame.tooltip_requests
3908 [range.start.tooltips_index..range.end.tooltips_index]
3909 .iter_mut()
3910 .map(|request| request.take()),
3911 );
3912 self.next_frame.accessed_element_states.extend(
3913 self.rendered_frame.accessed_element_states[range.start.accessed_element_states_index
3914 ..range.end.accessed_element_states_index]
3915 .iter()
3916 .map(|(id, type_id)| (id.clone(), *type_id)),
3917 );
3918 self.text_system
3919 .reuse_layouts(range.start.line_layout_index..range.end.line_layout_index);
3920
3921 let reused_subtree = self.next_frame.dispatch_tree.reuse_subtree(
3922 range.start.dispatch_tree_index..range.end.dispatch_tree_index,
3923 &mut self.rendered_frame.dispatch_tree,
3924 self.focus,
3925 );
3926
3927 if reused_subtree.contains_focus() {
3928 self.next_frame.focus = self.focus;
3929 }
3930
3931 self.next_frame.deferred_draws.extend(
3932 self.rendered_frame.deferred_draws
3933 [range.start.deferred_draws_index..range.end.deferred_draws_index]
3934 .iter()
3935 .map(|deferred_draw| DeferredDraw {
3936 current_view: deferred_draw.current_view,
3937 parent_node: reused_subtree.refresh_node_id(deferred_draw.parent_node),
3938 element_id_stack: deferred_draw.element_id_stack.clone(),
3939 text_style_stack: deferred_draw.text_style_stack.clone(),
3940 content_mask: deferred_draw.content_mask,
3941 rem_size: deferred_draw.rem_size,
3942 priority: deferred_draw.priority,
3943 element: None,
3944 absolute_offset: deferred_draw.absolute_offset,
3945 prepaint_range: deferred_draw.prepaint_range.clone(),
3946 paint_range: deferred_draw.paint_range.clone(),
3947 }),
3948 );
3949 }
3950
3951 pub(crate) fn paint_index(&self) -> PaintIndex {
3952 PaintIndex {
3953 scene_index: self.next_frame.scene.len(),
3954 #[cfg(any(test, feature = "test-support"))]
3955 debug_bounds_index: self.next_frame.debug_bounds_records.len(),
3956 mouse_listeners_index: self.next_frame.mouse_listeners.len(),
3957 input_handlers_index: self.next_frame.input_handlers.len(),
3958 cursor_styles_index: self.next_frame.cursor_styles.len(),
3959 accessed_element_states_index: self.next_frame.accessed_element_states.len(),
3960 tab_handle_index: self.next_frame.tab_stops.paint_index(),
3961 line_layout_index: self.text_system.layout_index(),
3962 }
3963 }
3964
3965 pub(crate) fn reuse_paint(&mut self, range: Range<PaintIndex>) {
3966 #[cfg(any(test, feature = "test-support"))]
3968 for (selector, bounds) in &self.rendered_frame.debug_bounds_records
3969 [range.start.debug_bounds_index..range.end.debug_bounds_index]
3970 {
3971 self.next_frame
3972 .record_debug_bounds(selector.clone(), *bounds);
3973 }
3974 self.next_frame.cursor_styles.extend(
3975 self.rendered_frame.cursor_styles
3976 [range.start.cursor_styles_index..range.end.cursor_styles_index]
3977 .iter()
3978 .cloned(),
3979 );
3980 self.next_frame.input_handlers.extend(
3981 self.rendered_frame.input_handlers
3982 [range.start.input_handlers_index..range.end.input_handlers_index]
3983 .iter_mut()
3984 .map(|handler| handler.take()),
3985 );
3986 self.next_frame.mouse_listeners.extend(
3987 self.rendered_frame.mouse_listeners
3988 [range.start.mouse_listeners_index..range.end.mouse_listeners_index]
3989 .iter_mut()
3990 .map(|listener| listener.take()),
3991 );
3992 self.next_frame.accessed_element_states.extend(
3993 self.rendered_frame.accessed_element_states[range.start.accessed_element_states_index
3994 ..range.end.accessed_element_states_index]
3995 .iter()
3996 .map(|(id, type_id)| (id.clone(), *type_id)),
3997 );
3998 self.next_frame.tab_stops.replay(
3999 &self.rendered_frame.tab_stops.insertion_history
4000 [range.start.tab_handle_index..range.end.tab_handle_index],
4001 );
4002
4003 self.text_system
4004 .reuse_layouts(range.start.line_layout_index..range.end.line_layout_index);
4005 self.next_frame.scene.replay(
4006 range.start.scene_index..range.end.scene_index,
4007 &self.rendered_frame.scene,
4008 );
4009 }
4010
4011 pub fn with_text_style<F, R>(&mut self, style: Option<TextStyleRefinement>, f: F) -> R
4015 where
4016 F: FnOnce(&mut Self) -> R,
4017 {
4018 self.invalidator.debug_assert_paint_or_prepaint();
4019 if let Some(style) = style {
4020 self.text_style_stack.push(style);
4021 let result = f(self);
4022 self.text_style_stack.pop();
4023 result
4024 } else {
4025 f(self)
4026 }
4027 }
4028
4029 pub fn set_cursor_style(&mut self, style: CursorStyle, hitbox: &Hitbox) {
4032 self.invalidator.debug_assert_paint();
4033 self.next_frame.cursor_styles.push(CursorStyleRequest {
4034 hitbox_id: Some(hitbox.id),
4035 style,
4036 });
4037 }
4038
4039 pub fn set_window_cursor_style(&mut self, style: CursorStyle) {
4044 self.invalidator.debug_assert_paint();
4045 self.next_frame.cursor_styles.push(CursorStyleRequest {
4046 hitbox_id: None,
4047 style,
4048 })
4049 }
4050
4051 pub fn set_tooltip(&mut self, tooltip: AnyTooltip) -> TooltipId {
4054 self.invalidator.debug_assert_prepaint();
4055 let id = TooltipId(post_inc(&mut self.next_tooltip_id.0));
4056 self.next_frame
4057 .tooltip_requests
4058 .push(Some(TooltipRequest { id, tooltip }));
4059 id
4060 }
4061
4062 #[inline]
4067 pub fn with_content_mask<R>(
4068 &mut self,
4069 mask: Option<ContentMask<Pixels>>,
4070 f: impl FnOnce(&mut Self) -> R,
4071 ) -> R {
4072 self.invalidator.debug_assert_paint_or_prepaint();
4073 if let Some(mask) = mask {
4074 let mask = mask.intersect(&self.content_mask());
4075 self.content_mask_stack.push(mask);
4076 let result = f(self);
4077 self.content_mask_stack.pop();
4078 result
4079 } else {
4080 f(self)
4081 }
4082 }
4083
4084 pub fn with_element_offset<R>(
4087 &mut self,
4088 offset: Point<Pixels>,
4089 f: impl FnOnce(&mut Self) -> R,
4090 ) -> R {
4091 self.invalidator.debug_assert_prepaint();
4092
4093 if offset.is_zero() {
4094 return f(self);
4095 };
4096
4097 let abs_offset = self.element_offset() + offset;
4098 self.with_absolute_element_offset(abs_offset, f)
4099 }
4100
4101 pub fn with_absolute_element_offset<R>(
4105 &mut self,
4106 offset: Point<Pixels>,
4107 f: impl FnOnce(&mut Self) -> R,
4108 ) -> R {
4109 self.invalidator.debug_assert_prepaint();
4110 self.element_offset_stack.push(offset);
4111 let result = f(self);
4112 self.element_offset_stack.pop();
4113 result
4114 }
4115
4116 pub(crate) fn with_element_opacity<R>(
4117 &mut self,
4118 opacity: Option<f32>,
4119 f: impl FnOnce(&mut Self) -> R,
4120 ) -> R {
4121 self.invalidator.debug_assert_paint_or_prepaint();
4122
4123 let Some(opacity) = opacity else {
4124 return f(self);
4125 };
4126
4127 let previous_opacity = self.element_opacity;
4128 self.element_opacity = previous_opacity * opacity;
4129 let result = f(self);
4130 self.element_opacity = previous_opacity;
4131 result
4132 }
4133
4134 pub fn with_edge_fade<R>(
4141 &mut self,
4142 fade: Option<EdgeFade>,
4143 f: impl FnOnce(&mut Self) -> R,
4144 ) -> R {
4145 let Some(fade) = fade else {
4146 return f(self);
4147 };
4148 if !(fade.top || fade.bottom || fade.left || fade.right) {
4149 return f(self);
4150 }
4151 self.invalidator.debug_assert_paint_or_prepaint();
4152 let previous = self.edge_fade.replace(fade);
4153 let result = f(self);
4154 self.edge_fade = previous;
4155 result
4156 }
4157
4158 pub fn transact<T, U>(&mut self, f: impl FnOnce(&mut Self) -> Result<T, U>) -> Result<T, U> {
4164 self.invalidator.debug_assert_prepaint();
4165 let index = self.prepaint_index();
4166 let result = f(self);
4167 if result.is_err() {
4168 self.next_frame.hitboxes.truncate(index.hitboxes_index);
4169 self.next_frame
4170 .tooltip_requests
4171 .truncate(index.tooltips_index);
4172 self.next_frame
4173 .deferred_draws
4174 .truncate(index.deferred_draws_index);
4175 self.next_frame
4176 .dispatch_tree
4177 .truncate(index.dispatch_tree_index);
4178 self.next_frame
4179 .accessed_element_states
4180 .truncate(index.accessed_element_states_index);
4181 self.text_system.truncate_layouts(index.line_layout_index);
4182 }
4183 result
4184 }
4185
4186 pub fn request_autoscroll(&mut self, bounds: Bounds<Pixels>) {
4192 self.invalidator.debug_assert_prepaint();
4193 self.requested_autoscroll = Some(bounds);
4194 }
4195
4196 pub fn take_autoscroll(&mut self) -> Option<Bounds<Pixels>> {
4199 self.invalidator.debug_assert_prepaint();
4200 self.requested_autoscroll.take()
4201 }
4202
4203 pub fn use_asset<A: Asset>(&mut self, source: &A::Source, cx: &mut App) -> Option<A::Output> {
4209 cx.asset_entry::<A>(source).use_by(self.current_view())
4210 }
4211
4212 pub fn get_asset<A: Asset>(&mut self, source: &A::Source, cx: &mut App) -> Option<A::Output> {
4218 cx.fetch_asset::<A>(source)
4219 }
4220 pub fn element_offset(&self) -> Point<Pixels> {
4223 self.invalidator.debug_assert_prepaint();
4224 self.element_offset_stack
4225 .last()
4226 .copied()
4227 .unwrap_or_default()
4228 }
4229
4230 #[inline]
4233 pub(crate) fn element_opacity(&self) -> f32 {
4234 self.invalidator.debug_assert_paint_or_prepaint();
4235 self.element_opacity
4236 }
4237
4238 #[inline]
4241 pub(crate) fn element_opacity_at(&self, center: Point<Pixels>) -> f32 {
4242 let opacity = self.element_opacity();
4243 let Some(fade) = &self.edge_fade else {
4244 return opacity;
4245 };
4246 let band = fade.band.0.max(1.0);
4247 let mut ramp: f32 = 1.0;
4248 if fade.top {
4249 ramp = ramp.min(((center.y.0 - fade.bounds.top().0) / band).clamp(0.0, 1.0));
4250 }
4251 if fade.bottom {
4252 ramp = ramp.min(((fade.bounds.bottom().0 - center.y.0) / band).clamp(0.0, 1.0));
4253 }
4254 if fade.left {
4255 ramp = ramp.min(((center.x.0 - fade.bounds.left().0) / band).clamp(0.0, 1.0));
4256 }
4257 if fade.right {
4258 ramp = ramp.min(((fade.bounds.right().0 - center.x.0) / band).clamp(0.0, 1.0));
4259 }
4260 opacity * ramp
4261 }
4262
4263 #[inline]
4270 pub(crate) fn element_opacity_for_bounds(&self, bounds: &Bounds<Pixels>) -> f32 {
4271 let opacity = self.element_opacity();
4272 let Some(fade) = &self.edge_fade else {
4273 return opacity;
4274 };
4275 let band = fade.band.0.max(1.0);
4276 let mut ramp: f32 = 1.0;
4277 if fade.top {
4278 ramp = ramp.min(((bounds.top().0 - fade.bounds.top().0) / band).clamp(0.0, 1.0));
4279 }
4280 if fade.bottom {
4281 ramp = ramp.min(((fade.bounds.bottom().0 - bounds.bottom().0) / band).clamp(0.0, 1.0));
4282 }
4283 if fade.left {
4284 ramp = ramp.min(((bounds.left().0 - fade.bounds.left().0) / band).clamp(0.0, 1.0));
4285 }
4286 if fade.right {
4287 ramp = ramp.min(((fade.bounds.right().0 - bounds.right().0) / band).clamp(0.0, 1.0));
4288 }
4289 opacity * ramp
4290 }
4291
4292 fn quad_fade_gradient(
4301 &self,
4302 bounds: Bounds<Pixels>,
4303 background: &Background,
4304 ) -> Option<Background> {
4305 let fade = self.edge_fade.as_ref()?;
4306 if background.tag != crate::color::BackgroundTag::Solid {
4307 return None;
4308 }
4309 let horizontal = fade.left || fade.right;
4310 let vertical = fade.top || fade.bottom;
4311 if horizontal == vertical {
4312 return None;
4313 }
4314 let band = fade.band.0.max(1.0);
4315 let (lo, hi, edge_lo, edge_hi, fade_lo, fade_hi, angle) = if horizontal {
4316 (
4317 bounds.left().0,
4318 bounds.right().0,
4319 fade.bounds.left().0,
4320 fade.bounds.right().0,
4321 fade.left,
4322 fade.right,
4323 90.0,
4324 )
4325 } else {
4326 (
4327 bounds.top().0,
4328 bounds.bottom().0,
4329 fade.bounds.top().0,
4330 fade.bounds.bottom().0,
4331 fade.top,
4332 fade.bottom,
4333 180.0,
4334 )
4335 };
4336 let extent = (hi - lo).max(1.0);
4337 let in_lo_band = fade_lo && lo < edge_lo + band;
4338 let in_hi_band = fade_hi && hi > edge_hi - band;
4339 let base = self.element_opacity();
4340 let color = background.solid;
4341 let (v0, v1, a0, a1) = match (in_lo_band, in_hi_band) {
4347 (true, true) | (false, false) => return None,
4350 (true, false) => {
4351 let v0 = lo.max(edge_lo);
4352 let v1 = hi.min(edge_lo + band);
4353 let ramp = |v: f32| ((v - edge_lo) / band).clamp(0.0, 1.0);
4354 (v0, v1, ramp(v0), ramp(v1))
4355 }
4356 (false, true) => {
4357 let v0 = lo.max(edge_hi - band);
4358 let v1 = hi.min(edge_hi);
4359 let ramp = |v: f32| ((edge_hi - v) / band).clamp(0.0, 1.0);
4360 (v0, v1, ramp(v0), ramp(v1))
4361 }
4362 };
4363 let p0 = (v0 - lo) / extent;
4364 let p1 = (v1 - lo) / extent;
4365 if (p1 - p0) < 0.001 {
4366 return None;
4367 }
4368 Some(crate::linear_gradient(
4369 angle,
4370 crate::linear_color_stop(color.opacity(a0 * base), p0),
4371 crate::linear_color_stop(color.opacity(a1 * base), p1),
4372 ))
4373 }
4374
4375 pub fn content_mask(&self) -> ContentMask<Pixels> {
4377 self.invalidator.debug_assert_paint_or_prepaint();
4378 self.content_mask_stack.last().cloned().unwrap_or_else(|| {
4379 ContentMask::new(Bounds {
4380 origin: Point::default(),
4381 size: self.viewport_size,
4382 })
4383 })
4384 }
4385
4386 pub fn with_element_namespace<R>(
4389 &mut self,
4390 element_id: impl Into<ElementId>,
4391 f: impl FnOnce(&mut Self) -> R,
4392 ) -> R {
4393 self.element_id_stack.push(element_id.into());
4394 let result = f(self);
4395 self.element_id_stack.pop();
4396 result
4397 }
4398
4399 pub fn use_keyed_state<S: 'static>(
4401 &mut self,
4402 key: impl Into<ElementId>,
4403 cx: &mut App,
4404 init: impl FnOnce(&mut Self, &mut Context<S>) -> S,
4405 ) -> Entity<S> {
4406 let current_view = self.current_view();
4407 self.with_global_id(key.into(), |global_id, window| {
4408 window.with_element_state(global_id, |state: Option<Entity<S>>, window| {
4409 if let Some(state) = state {
4410 (state.clone(), state)
4411 } else {
4412 let new_state = cx.new(|cx| init(window, cx));
4413 Self::observe_keyed_state(&new_state, current_view, cx);
4414 (new_state.clone(), new_state)
4415 }
4416 })
4417 })
4418 }
4419
4420 #[track_caller]
4426 pub fn use_state<S: 'static>(
4427 &mut self,
4428 cx: &mut App,
4429 init: impl FnOnce(&mut Self, &mut Context<S>) -> S,
4430 ) -> Entity<S> {
4431 self.use_keyed_state(
4432 ElementId::CodeLocation(*core::panic::Location::caller()),
4433 cx,
4434 init,
4435 )
4436 }
4437
4438 #[inline(always)]
4443 pub fn with_element_state<S, R>(
4444 &mut self,
4445 global_id: &GlobalElementId,
4446 f: impl FnOnce(Option<S>, &mut Self) -> (R, S),
4447 ) -> R
4448 where
4449 S: 'static,
4450 {
4451 self.invalidator.debug_assert_paint_or_prepaint();
4452
4453 let (key, state) = self.take_element_state(global_id, TypeId::of::<S>());
4454
4455 if let Some(any) = state {
4456 let ElementStateBox {
4457 inner,
4458 #[cfg(debug_assertions)]
4459 type_name,
4460 } = any;
4461 let mut state_box = inner
4463 .downcast::<Option<S>>()
4464 .map_err(|_| {
4465 #[cfg(debug_assertions)]
4466 {
4467 anyhow::anyhow!(
4468 "invalid element state type for id, requested {:?}, actual: {:?}",
4469 std::any::type_name::<S>(),
4470 type_name
4471 )
4472 }
4473
4474 #[cfg(not(debug_assertions))]
4475 {
4476 anyhow::anyhow!(
4477 "invalid element state type for id, requested {:?}",
4478 std::any::type_name::<S>(),
4479 )
4480 }
4481 })
4482 .unwrap();
4483
4484 let state = state_box.take().expect(
4485 "reentrant call to with_element_state for the same state type and element id",
4486 );
4487 let (result, state) = f(Some(state), self);
4488 state_box.replace(state);
4489 self.insert_element_state(
4490 key,
4491 ElementStateBox {
4492 inner: state_box,
4493 #[cfg(debug_assertions)]
4494 type_name,
4495 },
4496 );
4497 result
4498 } else {
4499 let (result, state) = f(None, self);
4500 self.insert_element_state(
4501 key,
4502 ElementStateBox {
4503 inner: Box::new(Some(state)),
4504 #[cfg(debug_assertions)]
4505 type_name: std::any::type_name::<S>(),
4506 },
4507 );
4508 result
4509 }
4510 }
4511
4512 pub fn with_optional_element_state<S, R>(
4519 &mut self,
4520 global_id: Option<&GlobalElementId>,
4521 f: impl FnOnce(Option<Option<S>>, &mut Self) -> (R, Option<S>),
4522 ) -> R
4523 where
4524 S: 'static,
4525 {
4526 self.invalidator.debug_assert_paint_or_prepaint();
4527
4528 if let Some(global_id) = global_id {
4529 self.with_element_state(global_id, |state, cx| {
4530 let (result, state) = f(Some(state), cx);
4531 let state =
4532 state.expect("you must return some state when you pass some element id");
4533 (result, state)
4534 })
4535 } else {
4536 let (result, state) = f(None, self);
4537 debug_assert!(
4538 state.is_none(),
4539 "you must not return an element state when passing None for the global id"
4540 );
4541 result
4542 }
4543 }
4544
4545 #[inline]
4547 pub fn with_tab_group<R>(&mut self, index: Option<isize>, f: impl FnOnce(&mut Self) -> R) -> R {
4548 if let Some(index) = index {
4549 self.next_frame.tab_stops.begin_group(index);
4550 let result = f(self);
4551 self.next_frame.tab_stops.end_group();
4552 result
4553 } else {
4554 f(self)
4555 }
4556 }
4557
4558 pub fn defer_draw(
4567 &mut self,
4568 element: AnyElement,
4569 absolute_offset: Point<Pixels>,
4570 priority: usize,
4571 content_mask: Option<ContentMask<Pixels>>,
4572 ) {
4573 self.invalidator.debug_assert_prepaint();
4574 let parent_node = self.next_frame.dispatch_tree.active_node_id().unwrap();
4575 self.next_frame.deferred_draws.push(DeferredDraw {
4576 current_view: self.current_view(),
4577 parent_node,
4578 element_id_stack: self.element_id_stack.clone(),
4579 text_style_stack: self.text_style_stack.clone(),
4580 content_mask,
4581 rem_size: self.rem_size(),
4582 priority,
4583 element: Some(element),
4584 absolute_offset,
4585 prepaint_range: PrepaintStateIndex::default()..PrepaintStateIndex::default(),
4586 paint_range: PaintIndex::default()..PaintIndex::default(),
4587 });
4588 }
4589
4590 pub fn paint_layer<R>(&mut self, bounds: Bounds<Pixels>, f: impl FnOnce(&mut Self) -> R) -> R {
4596 self.invalidator.debug_assert_paint();
4597
4598 let content_mask = self.content_mask();
4599 let clipped_bounds = bounds.intersect(&content_mask.bounds);
4600 if !clipped_bounds.is_empty() {
4601 self.next_frame
4602 .scene
4603 .push_layer(self.cover_bounds(clipped_bounds));
4604 }
4605
4606 let result = f(self);
4607
4608 if !clipped_bounds.is_empty() {
4609 self.next_frame.scene.pop_layer();
4610 }
4611
4612 result
4613 }
4614
4615 pub fn paint_drop_shadows(
4621 &mut self,
4622 bounds: Bounds<Pixels>,
4623 corner_radii: Corners<Pixels>,
4624 shadows: &[BoxShadow],
4625 ) {
4626 self.drop_shadows(bounds, corner_radii, shadows, false);
4627 }
4628
4629 pub fn paint_drop_shadows_outside(
4638 &mut self,
4639 bounds: Bounds<Pixels>,
4640 corner_radii: Corners<Pixels>,
4641 shadows: &[BoxShadow],
4642 ) {
4643 self.drop_shadows(bounds, corner_radii, shadows, true);
4644 }
4645
4646 fn drop_shadows(
4647 &mut self,
4648 bounds: Bounds<Pixels>,
4649 corner_radii: Corners<Pixels>,
4650 shadows: &[BoxShadow],
4651 outside: bool,
4652 ) {
4653 self.invalidator.debug_assert_paint();
4654
4655 let scale_factor = self.scale_factor();
4656 let content_mask = self.snapped_content_mask();
4657 let opacity = self.element_opacity_for_bounds(&bounds);
4658 let element_bounds = self.cover_bounds(bounds);
4659 let element_corner_radii = corner_radii.scale(scale_factor);
4660 for shadow in shadows {
4661 if shadow.inset {
4662 continue;
4663 }
4664 let shadow_bounds = (bounds + shadow.offset).dilate(shadow.spread_radius);
4665 self.next_frame.scene.insert_primitive(Shadow {
4666 order: 0,
4667 blur_radius: shadow.blur_radius.scale(scale_factor),
4668 bounds: self.cover_bounds(shadow_bounds),
4669 content_mask,
4670 corner_radii: corner_radii.scale(scale_factor),
4671 color: shadow.color.opacity(opacity),
4672 element_bounds,
4673 element_corner_radii,
4674 inset: if outside { 2 } else { 0 },
4675 pad: 0,
4676 });
4677 }
4678 }
4679
4680 pub fn paint_inset_shadows(
4684 &mut self,
4685 bounds: Bounds<Pixels>,
4686 corner_radii: Corners<Pixels>,
4687 shadows: &[BoxShadow],
4688 ) {
4689 self.invalidator.debug_assert_paint();
4690
4691 let scale_factor = self.scale_factor();
4692 let content_mask = self.snapped_content_mask();
4693 let opacity = self.element_opacity_for_bounds(&bounds);
4694 let element_bounds = self.cover_bounds(bounds);
4695 let element_corner_radii = corner_radii.scale(scale_factor);
4696 for shadow in shadows {
4697 if !shadow.inset {
4698 continue;
4699 }
4700 let hole = (bounds + shadow.offset).dilate(-shadow.spread_radius);
4701 let zero = Pixels::ZERO;
4704 let hole_corner_radii = Corners {
4705 top_left: (corner_radii.top_left - shadow.spread_radius).max(zero),
4706 top_right: (corner_radii.top_right - shadow.spread_radius).max(zero),
4707 bottom_right: (corner_radii.bottom_right - shadow.spread_radius).max(zero),
4708 bottom_left: (corner_radii.bottom_left - shadow.spread_radius).max(zero),
4709 };
4710 self.next_frame.scene.insert_primitive(Shadow {
4711 order: 0,
4712 blur_radius: shadow.blur_radius.scale(scale_factor),
4713 bounds: self.cover_bounds(hole),
4714 content_mask,
4715 corner_radii: hole_corner_radii.scale(scale_factor),
4716 color: shadow.color.opacity(opacity),
4717 element_bounds,
4718 element_corner_radii,
4719 inset: 1,
4720 pad: 0,
4721 });
4722 }
4723 }
4724
4725 pub fn paint_backdrop_blur(
4731 &mut self,
4732 bounds: Bounds<Pixels>,
4733 corner_radii: Corners<Pixels>,
4734 glass: GlassEffect,
4735 ) {
4736 self.invalidator.debug_assert_paint();
4737 let scale_factor = self.scale_factor();
4738 let content_mask = self.content_mask().scale(scale_factor);
4739 let limit = bounds.size.width.min(bounds.size.height) / 2.;
4743 let corner_radii = Corners {
4744 top_left: corner_radii.top_left.min(limit),
4745 top_right: corner_radii.top_right.min(limit),
4746 bottom_right: corner_radii.bottom_right.min(limit),
4747 bottom_left: corner_radii.bottom_left.min(limit),
4748 };
4749 self.next_frame.scene.insert_primitive(Shadow {
4752 order: 0,
4753 blur_radius: ScaledPixels(0.),
4754 bounds: bounds.scale(scale_factor),
4755 corner_radii: corner_radii.scale(scale_factor),
4756 content_mask,
4757 color: crate::transparent_black(),
4758 element_bounds: bounds.scale(scale_factor),
4759 element_corner_radii: corner_radii.scale(scale_factor),
4760 inset: 0,
4761 pad: 0,
4762 });
4763 self.next_frame.scene.insert_backdrop_blur(BackdropBlur {
4764 order: 0,
4765 blur_radius: glass.blur_radius.scale(scale_factor),
4766 bounds: bounds.scale(scale_factor),
4767 content_mask,
4768 corner_radii: corner_radii.scale(scale_factor),
4769 lens: glass.lens.scale(scale_factor),
4770 reach: glass.reach.scale(scale_factor),
4771 magnify: glass.magnify,
4772 dispersion: glass.dispersion,
4773 gain: glass.gain,
4774 saturation: glass.saturation,
4775 tint: glass.tint,
4776 edge: glass.edge,
4777 edge_width: glass.edge_width.scale(scale_factor),
4778 edge_aa: glass.edge_aa.scale(scale_factor),
4779 opacity: self.element_opacity_for_bounds(&bounds),
4782 });
4783 }
4784
4785 fn largest_border_interior(quad: &Quad) -> Bounds<ScaledPixels> {
4786 let radii = &quad.corner_radii;
4787 let widths = &quad.border_widths;
4788 let edge_radii = Edges {
4789 top: radii.top_left.max(radii.top_right),
4790 right: radii.top_right.max(radii.bottom_right),
4791 bottom: radii.bottom_left.max(radii.bottom_right),
4792 left: radii.top_left.max(radii.bottom_left),
4793 };
4794
4795 let antialias_inset = point(ScaledPixels(1.0), ScaledPixels(1.0));
4796 let inset_bounds = |top_left_inset, bottom_right_inset| {
4797 Bounds::from_corners(
4798 quad.bounds.origin + top_left_inset + antialias_inset,
4799 quad.bounds.bottom_right() - bottom_right_inset - antialias_inset,
4800 )
4801 };
4802
4803 let horizontal_band = inset_bounds(
4806 point(widths.left, widths.top.max(edge_radii.top)),
4807 point(widths.right, widths.bottom.max(edge_radii.bottom)),
4808 );
4809 let vertical_band = inset_bounds(
4810 point(widths.left.max(edge_radii.left), widths.top),
4811 point(widths.right.max(edge_radii.right), widths.bottom),
4812 );
4813
4814 let area = |bounds: &Bounds<ScaledPixels>| {
4815 bounds.size.width.0.max(0.) * bounds.size.height.0.max(0.)
4816 };
4817 if area(&horizontal_band) >= area(&vertical_band) {
4818 horizontal_band
4819 } else {
4820 vertical_band
4821 }
4822 }
4823
4824 pub fn paint_quad(&mut self, quad: PaintQuad) {
4834 self.invalidator.debug_assert_paint();
4835
4836 let opacity = self.element_opacity_at(quad.bounds.center());
4837 let background = self
4838 .quad_fade_gradient(quad.bounds, &quad.background)
4839 .unwrap_or_else(|| quad.background.opacity(opacity));
4840 let snapped_bounds = self.snap_bounds(quad.bounds);
4841 let snapped_border_widths = self.snap_border_widths(quad.border_widths);
4842 let quad = Quad {
4843 order: 0,
4844 bounds: snapped_bounds,
4845 content_mask: self.snapped_content_mask(),
4846 background,
4847 border_color: quad.border_color.opacity(opacity),
4848 corner_radii: quad.corner_radii.scale(self.scale_factor()),
4849 border_widths: snapped_border_widths,
4850 border_style: quad.border_style,
4851 };
4852
4853 if !quad.background.is_transparent() {
4854 self.next_frame.scene.insert_primitive(quad);
4855 return;
4856 }
4857
4858 let outer_bounds = quad.bounds;
4861 let inner_bounds = Self::largest_border_interior(&quad);
4862
4863 if inner_bounds.is_empty() {
4864 self.next_frame.scene.insert_primitive(quad);
4865 return;
4866 }
4867
4868 let strips = [
4869 Bounds::from_corners(
4871 outer_bounds.origin,
4872 point(outer_bounds.right(), inner_bounds.top()),
4873 ),
4874 Bounds::from_corners(
4876 point(outer_bounds.left(), inner_bounds.bottom()),
4877 outer_bounds.bottom_right(),
4878 ),
4879 Bounds::from_corners(
4881 point(outer_bounds.left(), inner_bounds.top()),
4882 inner_bounds.bottom_left(),
4883 ),
4884 Bounds::from_corners(
4886 inner_bounds.top_right(),
4887 point(outer_bounds.right(), inner_bounds.bottom()),
4888 ),
4889 ];
4890
4891 for strip in strips {
4892 let content_mask_bounds = quad.content_mask.bounds.intersect(&strip);
4893 if !content_mask_bounds.is_empty() {
4894 self.next_frame.scene.insert_primitive(Quad {
4898 content_mask: ContentMask::new(content_mask_bounds),
4899 ..quad
4900 });
4901 }
4902 }
4903 }
4904
4905 pub fn paint_path(&mut self, mut path: Path<Pixels>, color: impl Into<Background>) {
4909 self.invalidator.debug_assert_paint();
4910
4911 let scale_factor = self.scale_factor();
4912 let content_mask = self.content_mask();
4913 let opacity = self.element_opacity_for_bounds(&path.bounds);
4914 path.content_mask = content_mask;
4915 let color: Background = color.into();
4916 path.color = color.opacity(opacity);
4917 self.next_frame
4918 .scene
4919 .insert_primitive(path.scale(scale_factor));
4920 }
4921
4922 pub fn paint_underline(
4926 &mut self,
4927 origin: Point<Pixels>,
4928 width: Pixels,
4929 style: &UnderlineStyle,
4930 ) {
4931 self.invalidator.debug_assert_paint();
4932 let underline = self.underline(origin, width, style);
4933 self.next_frame.scene.insert_primitive(underline);
4934 }
4935
4936 pub fn paint_strikethrough(
4940 &mut self,
4941 origin: Point<Pixels>,
4942 width: Pixels,
4943 style: &StrikethroughStyle,
4944 ) {
4945 self.invalidator.debug_assert_paint();
4946
4947 let scale_factor = self.scale_factor();
4948 let height = style.thickness;
4949 let bounds = Bounds {
4950 origin: origin.map(|c| ScaledPixels(round_to_device_pixel(c.0, scale_factor))),
4951 size: size(self.snap_stroke(width), self.snap_stroke(height)),
4952 };
4953 let opacity = self.element_opacity_at(origin);
4954
4955 self.next_frame.scene.insert_primitive(Underline {
4956 order: 0,
4957 pad: 0,
4958 bounds,
4959 content_mask: self.snapped_content_mask(),
4960 thickness: self.snap_stroke(style.thickness),
4961 color: style.color.unwrap_or_default().opacity(opacity),
4962 wavy: false.into(),
4963 });
4964 }
4965
4966 pub fn paint_glyph(
4975 &mut self,
4976 origin: Point<Pixels>,
4977 font_id: FontId,
4978 glyph_id: GlyphId,
4979 font_size: Pixels,
4980 color: Hsla,
4981 ) -> Result<()> {
4982 self.invalidator.debug_assert_paint();
4983
4984 let element_opacity = self.element_opacity_for_bounds(&Bounds {
4985 origin,
4986 size: size(font_size * 0.6, font_size),
4987 });
4988 let scale_factor = self.scale_factor();
4989 let glyph_origin = origin.scale(scale_factor);
4990
4991 let quantized_origin = Point::new(
4992 round_half_toward_zero(glyph_origin.x.0 * SUBPIXEL_VARIANTS_X as f32)
4993 / SUBPIXEL_VARIANTS_X as f32,
4994 round_half_toward_zero(glyph_origin.y.0 * SUBPIXEL_VARIANTS_Y as f32)
4995 / SUBPIXEL_VARIANTS_Y as f32,
4996 );
4997 let subpixel_variant = Point::new(
4998 (quantized_origin.x.fract() * SUBPIXEL_VARIANTS_X as f32) as u8,
4999 (quantized_origin.y.fract() * SUBPIXEL_VARIANTS_Y as f32) as u8,
5000 );
5001 let integer_origin = quantized_origin.map(|c| ScaledPixels(c.trunc()));
5002 let subpixel_rendering = self.should_use_subpixel_rendering(font_id, font_size);
5003 let dilation = self.text_system().glyph_dilation_for_color(color);
5004 let params = RenderGlyphParams {
5005 font_id,
5006 glyph_id,
5007 font_size,
5008 subpixel_variant,
5009 scale_factor,
5010 is_emoji: false,
5011 subpixel_rendering,
5012 dilation,
5013 };
5014
5015 let raster_bounds = self.text_system().raster_bounds(¶ms)?;
5016 if !raster_bounds.is_zero() {
5017 let tile = self
5018 .sprite_atlas
5019 .get_or_insert_with(params.clone().into(), &mut || {
5020 let (size, bytes) = self.text_system().rasterize_glyph(¶ms)?;
5021 Ok(Some((size, Cow::Owned(bytes))))
5022 })?
5023 .expect("Callback above only errors or returns Some");
5024 let bounds = Bounds {
5025 origin: integer_origin + raster_bounds.origin.map(Into::into),
5026 size: tile.bounds.size.map(Into::into),
5027 };
5028 let content_mask = self.snapped_content_mask();
5029
5030 if subpixel_rendering {
5031 self.next_frame.scene.insert_primitive(SubpixelSprite {
5032 order: 0,
5033 pad: 0,
5034 bounds,
5035 content_mask,
5036 color: color.opacity(element_opacity),
5037 tile,
5038 transformation: TransformationMatrix::unit(),
5039 });
5040 } else {
5041 self.next_frame.scene.insert_primitive(MonochromeSprite {
5042 order: 0,
5043 pad: 0,
5044 bounds,
5045 content_mask,
5046 color: color.opacity(element_opacity),
5047 tile,
5048 transformation: TransformationMatrix::unit(),
5049 });
5050 }
5051 }
5052 Ok(())
5053 }
5054
5055 fn should_use_subpixel_rendering(&self, font_id: FontId, font_size: Pixels) -> bool {
5056 if self.platform_window.background_appearance() != WindowBackgroundAppearance::Opaque {
5057 return false;
5058 }
5059
5060 if !self.platform_window.is_subpixel_rendering_supported() {
5061 return false;
5062 }
5063
5064 let mode = match self.text_rendering_mode.get() {
5065 TextRenderingMode::PlatformDefault => self
5066 .text_system()
5067 .recommended_rendering_mode(font_id, font_size),
5068 mode => mode,
5069 };
5070
5071 mode == TextRenderingMode::Subpixel
5072 }
5073
5074 pub fn paint_emoji(
5083 &mut self,
5084 origin: Point<Pixels>,
5085 font_id: FontId,
5086 glyph_id: GlyphId,
5087 font_size: Pixels,
5088 ) -> Result<()> {
5089 self.invalidator.debug_assert_paint();
5090
5091 let scale_factor = self.scale_factor();
5092 let glyph_origin = origin.scale(scale_factor);
5093 let integer_origin = glyph_origin.map(|c| ScaledPixels(round_half_toward_zero(c.0)));
5094 let params = RenderGlyphParams {
5095 font_id,
5096 glyph_id,
5097 font_size,
5098 subpixel_variant: Default::default(),
5099 scale_factor,
5100 is_emoji: true,
5101 subpixel_rendering: false,
5102 dilation: 0,
5103 };
5104
5105 let raster_bounds = self.text_system().raster_bounds(¶ms)?;
5106 if !raster_bounds.is_zero() {
5107 let tile = self
5108 .sprite_atlas
5109 .get_or_insert_with(params.clone().into(), &mut || {
5110 let (size, bytes) = self.text_system().rasterize_glyph(¶ms)?;
5111 Ok(Some((size, Cow::Owned(bytes))))
5112 })?
5113 .expect("Callback above only errors or returns Some");
5114
5115 let bounds = Bounds {
5116 origin: integer_origin + raster_bounds.origin.map(Into::into),
5117 size: tile.bounds.size.map(Into::into),
5118 };
5119 let content_mask = self.snapped_content_mask();
5120 let opacity = self.element_opacity_for_bounds(&Bounds {
5121 origin,
5122 size: size(font_size * 0.6, font_size),
5123 });
5124
5125 self.next_frame.scene.insert_primitive(PolychromeSprite {
5126 order: 0,
5127 pad: 0,
5128 grayscale: false.into(),
5129 bounds,
5130 corner_radii: Default::default(),
5131 content_mask,
5132 tile,
5133 opacity,
5134 });
5135 }
5136 Ok(())
5137 }
5138
5139 pub fn paint_svg(
5143 &mut self,
5144 bounds: Bounds<Pixels>,
5145 path: SharedString,
5146 mut data: Option<&[u8]>,
5147 transformation: TransformationMatrix,
5148 color: Hsla,
5149 cx: &App,
5150 ) -> Result<()> {
5151 self.invalidator.debug_assert_paint();
5152
5153 let element_opacity = self.element_opacity_for_bounds(&bounds);
5154 let bounds = self.snap_bounds(bounds);
5155
5156 let params = RenderSvgParams {
5157 path,
5158 size: bounds.size.map(|pixels| {
5159 DevicePixels::from((pixels.0 * SMOOTH_SVG_SCALE_FACTOR).ceil() as i32)
5160 }),
5161 };
5162
5163 let Some(tile) =
5164 self.sprite_atlas
5165 .get_or_insert_with(params.clone().into(), &mut || {
5166 let Some((size, bytes)) = cx.svg_renderer.render_alpha_mask(¶ms, data)?
5167 else {
5168 return Ok(None);
5169 };
5170 Ok(Some((size, Cow::Owned(bytes))))
5171 })?
5172 else {
5173 return Ok(());
5174 };
5175 let content_mask = self.snapped_content_mask();
5176 let svg_bounds = Bounds {
5177 origin: bounds.center()
5178 - Point::new(
5179 ScaledPixels(tile.bounds.size.width.0 as f32 / SMOOTH_SVG_SCALE_FACTOR / 2.),
5180 ScaledPixels(tile.bounds.size.height.0 as f32 / SMOOTH_SVG_SCALE_FACTOR / 2.),
5181 ),
5182 size: tile
5183 .bounds
5184 .size
5185 .map(|value| ScaledPixels(value.0 as f32 / SMOOTH_SVG_SCALE_FACTOR)),
5186 };
5187 let final_bounds = svg_bounds
5194 .map_origin(|value| ScaledPixels(round_half_toward_zero(value.0)))
5195 .map_size(|size| ScaledPixels(size.0.floor().max(1.)));
5198
5199 self.next_frame.scene.insert_primitive(MonochromeSprite {
5200 order: 0,
5201 pad: 0,
5202 bounds: final_bounds,
5203 content_mask,
5204 color: color.opacity(element_opacity),
5205 tile,
5206 transformation,
5207 });
5208
5209 Ok(())
5210 }
5211
5212 pub fn paint_image(
5221 &mut self,
5222 bounds: Bounds<Pixels>,
5223 image_bounds: Bounds<Pixels>,
5224 corner_radii: Corners<Pixels>,
5225 data: Arc<RenderImage>,
5226 frame_index: usize,
5227 grayscale: bool,
5228 ) -> Result<()> {
5229 self.invalidator.debug_assert_paint();
5230
5231 let fade_bounds = bounds;
5232 let visible_bounds = bounds.intersect(&image_bounds);
5233 if visible_bounds.size.width <= Pixels::ZERO || visible_bounds.size.height <= Pixels::ZERO {
5234 return Ok(());
5235 }
5236 if image_bounds.size.width <= Pixels::ZERO || image_bounds.size.height <= Pixels::ZERO {
5237 return Ok(());
5238 }
5239
5240 let params = RenderImageParams {
5241 image_id: data.id,
5242 frame_index,
5243 };
5244
5245 let tile = self
5246 .sprite_atlas
5247 .get_or_insert_with(params.into(), &mut || {
5248 Ok(Some((
5249 data.size(frame_index),
5250 Cow::Borrowed(
5251 data.as_bytes(frame_index)
5252 .expect("It's the caller's job to pass a valid frame index"),
5253 ),
5254 )))
5255 })?
5256 .expect("Callback above only returns Some");
5257
5258 let visible_bounds_snapped = self.snap_bounds(visible_bounds);
5259
5260 let sub_tile = if visible_bounds == image_bounds {
5261 tile
5262 } else {
5263 let x_offset_ratio =
5264 (visible_bounds.origin.x - image_bounds.origin.x) / image_bounds.size.width;
5265 let y_offset_ratio =
5266 (visible_bounds.origin.y - image_bounds.origin.y) / image_bounds.size.height;
5267 let width_ratio = visible_bounds.size.width / image_bounds.size.width;
5268 let height_ratio = visible_bounds.size.height / image_bounds.size.height;
5269
5270 let tile_origin_x = tile.bounds.origin.x.0;
5271 let tile_origin_y = tile.bounds.origin.y.0;
5272 let tile_width = tile.bounds.size.width.0;
5273 let tile_height = tile.bounds.size.height.0;
5274
5275 let sub_origin_x = tile_origin_x + (x_offset_ratio * tile_width as f32).round() as i32;
5276 let sub_origin_y = tile_origin_y + (y_offset_ratio * tile_height as f32).round() as i32;
5277 let sub_width = (width_ratio * tile_width as f32).round() as i32;
5278 let sub_height = (height_ratio * tile_height as f32).round() as i32;
5279
5280 let max_x = tile_origin_x + tile_width;
5281 let max_y = tile_origin_y + tile_height;
5282
5283 let clamped_origin_x = sub_origin_x.clamp(tile_origin_x, max_x);
5284 let clamped_origin_y = sub_origin_y.clamp(tile_origin_y, max_y);
5285 let clamped_width = sub_width.min(max_x - clamped_origin_x).max(0);
5286 let clamped_height = sub_height.min(max_y - clamped_origin_y).max(0);
5287
5288 AtlasTile {
5289 bounds: Bounds {
5290 origin: point(
5291 DevicePixels(clamped_origin_x),
5292 DevicePixels(clamped_origin_y),
5293 ),
5294 size: size(DevicePixels(clamped_width), DevicePixels(clamped_height)),
5295 },
5296 ..tile
5297 }
5298 };
5299
5300 let content_mask = self.snapped_content_mask();
5301 let corner_radii = corner_radii
5302 .clamp_radii_for_quad_size(visible_bounds.size)
5303 .scale(self.scale_factor());
5304 let opacity = self.element_opacity_for_bounds(&fade_bounds);
5305
5306 self.next_frame.scene.insert_primitive(PolychromeSprite {
5307 order: 0,
5308 pad: 0,
5309 grayscale: grayscale.into(),
5310 bounds: visible_bounds_snapped,
5311 content_mask,
5312 corner_radii,
5313 tile: sub_tile,
5314 opacity,
5315 });
5316 Ok(())
5317 }
5318
5319 #[cfg(target_os = "macos")]
5323 pub fn paint_surface(&mut self, bounds: Bounds<Pixels>, image_buffer: CVPixelBuffer) {
5324 use crate::PaintSurface;
5325
5326 self.invalidator.debug_assert_paint();
5327
5328 let bounds = self.snap_bounds(bounds);
5329 let content_mask = self.snapped_content_mask();
5330 self.next_frame.scene.insert_primitive(PaintSurface {
5331 order: 0,
5332 bounds,
5333 content_mask,
5334 image_buffer,
5335 });
5336 }
5337
5338 pub fn drop_image(&mut self, data: Arc<RenderImage>) -> Result<()> {
5340 for frame_index in 0..data.frame_count() {
5341 let params = RenderImageParams {
5342 image_id: data.id,
5343 frame_index,
5344 };
5345
5346 self.sprite_atlas.remove(¶ms.clone().into());
5347 }
5348
5349 Ok(())
5350 }
5351
5352 #[cfg(any(test, feature = "test-support"))]
5354 pub fn has_image_atlas_entry(&self, data: &RenderImage) -> bool {
5355 data.frame_count() > 0
5356 && (0..data.frame_count()).all(|frame_index| {
5357 self.sprite_atlas.contains(
5358 &RenderImageParams {
5359 image_id: data.id,
5360 frame_index,
5361 }
5362 .into(),
5363 )
5364 })
5365 }
5366
5367 #[must_use]
5373 pub fn request_layout(
5374 &mut self,
5375 style: Style,
5376 children: impl IntoIterator<Item = LayoutId>,
5377 cx: &mut App,
5378 ) -> LayoutId {
5379 self.invalidator.debug_assert_prepaint();
5380
5381 cx.layout_id_buffer.clear();
5382 cx.layout_id_buffer.extend(children);
5383 let rem_size = self.rem_size();
5384 let scale_factor = self.scale_factor();
5385
5386 self.layout_engine.as_mut().unwrap().request_layout(
5387 style,
5388 rem_size,
5389 scale_factor,
5390 &cx.layout_id_buffer,
5391 )
5392 }
5393
5394 pub fn request_measured_layout<F>(&mut self, style: Style, measure: F) -> LayoutId
5403 where
5404 F: Fn(Size<Option<Pixels>>, Size<AvailableSpace>, &mut Window, &mut App) -> Size<Pixels>
5405 + 'static,
5406 {
5407 self.invalidator.debug_assert_prepaint();
5408
5409 let rem_size = self.rem_size();
5410 let scale_factor = self.scale_factor();
5411 self.layout_engine
5412 .as_mut()
5413 .unwrap()
5414 .request_measured_layout(style, rem_size, scale_factor, measure)
5415 }
5416
5417 pub fn compute_layout(
5423 &mut self,
5424 layout_id: LayoutId,
5425 available_space: Size<AvailableSpace>,
5426 cx: &mut App,
5427 ) {
5428 self.invalidator.debug_assert_prepaint();
5429
5430 let mut layout_engine = self.layout_engine.take().unwrap();
5431 layout_engine.compute_layout(layout_id, available_space, self, cx);
5432 self.layout_engine = Some(layout_engine);
5433 }
5434
5435 pub fn layout_bounds(&mut self, layout_id: LayoutId) -> Bounds<Pixels> {
5440 self.invalidator.debug_assert_prepaint();
5441
5442 let scale_factor = self.scale_factor();
5443 let mut bounds = self
5444 .layout_engine
5445 .as_mut()
5446 .unwrap()
5447 .layout_bounds(layout_id, scale_factor)
5448 .map(Into::into);
5449 let snapped_offset = self.pixel_snap_point(self.element_offset());
5450 bounds.origin += snapped_offset;
5451 bounds
5452 }
5453
5454 pub fn insert_hitbox(&mut self, bounds: Bounds<Pixels>, behavior: HitboxBehavior) -> Hitbox {
5460 self.invalidator.debug_assert_prepaint();
5461
5462 let content_mask = self.content_mask();
5463 let mut id = self.next_hitbox_id;
5464 self.next_hitbox_id = self.next_hitbox_id.next();
5465 let hitbox = Hitbox {
5466 id,
5467 bounds,
5468 content_mask,
5469 behavior,
5470 };
5471 self.next_frame.hitboxes.push(hitbox.clone());
5472 hitbox
5473 }
5474
5475 pub fn insert_window_control_hitbox(&mut self, area: WindowControlArea, hitbox: Hitbox) {
5479 self.invalidator.debug_assert_paint();
5480 self.next_frame.window_control_hitboxes.push((area, hitbox));
5481 }
5482
5483 pub fn set_key_context(&mut self, context: KeyContext) {
5488 self.invalidator.debug_assert_paint();
5489 self.next_frame.dispatch_tree.set_key_context(context);
5490 }
5491
5492 pub fn set_focus_handle(&mut self, focus_handle: &FocusHandle, _: &App) {
5497 self.invalidator.debug_assert_prepaint();
5498 if focus_handle.is_focused(self) {
5499 self.next_frame.focus = Some(focus_handle.id);
5500 }
5501 self.next_frame.dispatch_tree.set_focus_id(focus_handle.id);
5502 }
5503
5504 pub fn set_view_id(&mut self, view_id: EntityId) {
5510 self.invalidator.debug_assert_prepaint();
5511 self.next_frame.dispatch_tree.set_view_id(view_id);
5512 }
5513
5514 pub fn current_view(&self) -> EntityId {
5516 self.invalidator.debug_assert_paint_or_prepaint();
5517 self.rendered_entity_stack.last().copied().unwrap()
5518 }
5519
5520 #[inline]
5521 pub(crate) fn with_rendered_view<R>(
5522 &mut self,
5523 id: EntityId,
5524 f: impl FnOnce(&mut Self) -> R,
5525 ) -> R {
5526 self.rendered_entity_stack.push(id);
5527 let result = f(self);
5528 self.rendered_entity_stack.pop();
5529 result
5530 }
5531
5532 pub fn with_image_cache<F, R>(&mut self, image_cache: Option<AnyImageCache>, f: F) -> R
5534 where
5535 F: FnOnce(&mut Self) -> R,
5536 {
5537 if let Some(image_cache) = image_cache {
5538 self.image_cache_stack.push(image_cache);
5539 let result = f(self);
5540 self.image_cache_stack.pop();
5541 result
5542 } else {
5543 f(self)
5544 }
5545 }
5546
5547 pub fn handle_input(
5556 &mut self,
5557 focus_handle: &FocusHandle,
5558 input_handler: impl InputHandler,
5559 cx: &App,
5560 ) {
5561 self.invalidator.debug_assert_paint();
5562
5563 if focus_handle.is_focused(self) {
5564 let cx = self.to_async(cx);
5565 self.next_frame
5566 .input_handlers
5567 .push(Some(PlatformInputHandler::new(cx, Box::new(input_handler))));
5568 }
5569 }
5570
5571 fn apply_text_input_configuration(&mut self, cx: &mut App) {
5576 let configuration = match self.platform_window.take_input_handler() {
5577 Some(mut input_handler) => {
5578 let configuration = input_handler.text_input_configuration(self, cx);
5579 self.platform_window.set_input_handler(input_handler);
5580 configuration
5581 }
5582 None => TextInputConfiguration::default(),
5583 };
5584 if self.last_text_input_configuration.as_ref() != Some(&configuration) {
5585 self.platform_window
5586 .set_text_input_configuration(configuration.clone());
5587 self.last_text_input_configuration = Some(configuration);
5588 }
5589 }
5590
5591 pub fn on_mouse_event<Event: MouseEvent>(
5597 &mut self,
5598 mut listener: impl FnMut(&Event, DispatchPhase, &mut Window, &mut App) + 'static,
5599 ) {
5600 self.invalidator.debug_assert_paint();
5601
5602 self.next_frame.mouse_listeners.push(Some(Box::new(
5603 move |event: &dyn Any, phase: DispatchPhase, window: &mut Window, cx: &mut App| {
5604 if let Some(event) = event.downcast_ref() {
5605 listener(event, phase, window, cx)
5606 }
5607 },
5608 )));
5609 }
5610
5611 pub fn on_key_event<Event: KeyEvent>(
5620 &mut self,
5621 listener: impl Fn(&Event, DispatchPhase, &mut Window, &mut App) + 'static,
5622 ) {
5623 self.invalidator.debug_assert_paint();
5624
5625 self.next_frame.dispatch_tree.on_key_event(Rc::new(
5626 move |event: &dyn Any, phase, window: &mut Window, cx: &mut App| {
5627 if let Some(event) = event.downcast_ref::<Event>() {
5628 listener(event, phase, window, cx)
5629 }
5630 },
5631 ));
5632 }
5633
5634 pub fn on_modifiers_changed(
5641 &mut self,
5642 listener: impl Fn(&ModifiersChangedEvent, &mut Window, &mut App) + 'static,
5643 ) {
5644 self.invalidator.debug_assert_paint();
5645
5646 self.next_frame.dispatch_tree.on_modifiers_changed(Rc::new(
5647 move |event: &ModifiersChangedEvent, window: &mut Window, cx: &mut App| {
5648 listener(event, window, cx)
5649 },
5650 ));
5651 }
5652
5653 pub fn on_focus_in(
5657 &mut self,
5658 handle: &FocusHandle,
5659 cx: &mut App,
5660 mut listener: impl FnMut(&mut Window, &mut App) + 'static,
5661 ) -> Subscription {
5662 let focus_id = handle.id;
5663 let (subscription, activate) =
5664 self.new_focus_listener(Box::new(move |event, window, cx| {
5665 if event.is_focus_in(focus_id) {
5666 listener(window, cx);
5667 }
5668 true
5669 }));
5670 cx.defer(move |_| activate());
5671 subscription
5672 }
5673
5674 pub fn on_focus_out(
5677 &mut self,
5678 handle: &FocusHandle,
5679 cx: &mut App,
5680 mut listener: impl FnMut(FocusOutEvent, &mut Window, &mut App) + 'static,
5681 ) -> Subscription {
5682 let focus_id = handle.id;
5683 let (subscription, activate) =
5684 self.new_focus_listener(Box::new(move |event, window, cx| {
5685 if let Some(blurred_id) = event.previous_focus_path.last().copied()
5686 && event.is_focus_out(focus_id)
5687 {
5688 let event = FocusOutEvent {
5689 blurred: WeakFocusHandle {
5690 id: blurred_id,
5691 handles: Arc::downgrade(&cx.focus_handles),
5692 },
5693 };
5694 listener(event, window, cx)
5695 }
5696 true
5697 }));
5698 cx.defer(move |_| activate());
5699 subscription
5700 }
5701
5702 fn reset_cursor_style(&self, cx: &mut App) {
5703 if self.is_window_hovered() {
5705 let style = self
5706 .rendered_frame
5707 .cursor_style(self)
5708 .unwrap_or(CursorStyle::Arrow);
5709 cx.platform.set_cursor_style(style);
5710 }
5711 }
5712
5713 pub fn dispatch_keystroke(&mut self, keystroke: Keystroke, cx: &mut App) -> bool {
5716 let keystroke = keystroke.with_simulated_ime();
5717 let result = self.dispatch_event(
5718 PlatformInput::KeyDown(KeyDownEvent {
5719 keystroke: keystroke.clone(),
5720 is_held: false,
5721 prefer_character_input: false,
5722 layout: None,
5723 }),
5724 cx,
5725 );
5726 if !result.propagate {
5727 return true;
5728 }
5729
5730 if let Some(input) = keystroke.key_char
5731 && let Some(mut input_handler) = self.platform_window.take_input_handler()
5732 {
5733 input_handler.dispatch_input(&input, self, cx);
5734 self.platform_window.set_input_handler(input_handler);
5735 return true;
5736 }
5737
5738 false
5739 }
5740
5741 pub fn keystroke_text_for(&self, action: &dyn Action) -> String {
5744 self.highest_precedence_binding_for_action(action)
5745 .map(|binding| {
5746 binding
5747 .keystrokes()
5748 .iter()
5749 .map(ToString::to_string)
5750 .collect::<Vec<_>>()
5751 .join(" ")
5752 })
5753 .unwrap_or_else(|| action.name().to_string())
5754 }
5755
5756 #[profiling::function]
5758 pub fn dispatch_event(&mut self, event: PlatformInput, cx: &mut App) -> DispatchEventResult {
5759 #[cfg(feature = "profiler")]
5760 self.window_profiler.begin_input(event.kind_name());
5761 let update_count_before = self.invalidator.update_count();
5762 let old_modality = self.last_input_modality;
5766 self.last_input_modality = match &event {
5767 PlatformInput::KeyDown(_) => InputModality::Keyboard,
5768 PlatformInput::MouseMove(_) | PlatformInput::MouseDown(_) => InputModality::Mouse,
5769 PlatformInput::Touch(_) => InputModality::Touch,
5770 _ => self.last_input_modality,
5771 };
5772 if self.last_input_modality != old_modality {
5773 self.refresh();
5774 }
5775
5776 cx.propagate_event = true;
5778 self.default_prevented = false;
5780
5781 let event = match event {
5782 PlatformInput::MouseMove(mouse_move) => {
5785 self.mouse_position = mouse_move.position;
5786 self.modifiers = mouse_move.modifiers;
5787 PlatformInput::MouseMove(mouse_move)
5788 }
5789 PlatformInput::MouseDown(mouse_down) => {
5790 self.mouse_position = mouse_down.position;
5791 self.modifiers = mouse_down.modifiers;
5792 PlatformInput::MouseDown(mouse_down)
5793 }
5794 PlatformInput::MouseUp(mouse_up) => {
5795 self.mouse_position = mouse_up.position;
5796 self.modifiers = mouse_up.modifiers;
5797 PlatformInput::MouseUp(mouse_up)
5798 }
5799 PlatformInput::MousePressure(mouse_pressure) => {
5800 PlatformInput::MousePressure(mouse_pressure)
5801 }
5802 PlatformInput::MouseExited(mouse_exited) => {
5803 self.modifiers = mouse_exited.modifiers;
5804 PlatformInput::MouseExited(mouse_exited)
5805 }
5806 PlatformInput::ModifiersChanged(modifiers_changed) => {
5807 self.modifiers = modifiers_changed.modifiers;
5808 self.capslock = modifiers_changed.capslock;
5809 PlatformInput::ModifiersChanged(modifiers_changed)
5810 }
5811 PlatformInput::ScrollWheel(scroll_wheel) => {
5812 self.mouse_position = scroll_wheel.position;
5813 self.modifiers = scroll_wheel.modifiers;
5814 PlatformInput::ScrollWheel(scroll_wheel)
5815 }
5816 PlatformInput::Pinch(pinch) => {
5817 self.mouse_position = pinch.position;
5818 self.modifiers = pinch.modifiers;
5819 PlatformInput::Pinch(pinch)
5820 }
5821 PlatformInput::FileDrop(file_drop) => match file_drop {
5824 FileDropEvent::Entered { position, paths } => {
5825 self.mouse_position = position;
5826 let source_window = self.handle.window_id();
5827 if !cx.restore_platform_drag(source_window) && cx.active_drag.is_none() {
5828 cx.active_drag = Some(AnyDrag {
5829 value: Arc::new(paths.clone()),
5830 view: cx.new(|_| paths).into(),
5831 cursor_offset: position,
5832 cursor_style: None,
5833 external_payload_source: None,
5834 });
5835 }
5836 PlatformInput::MouseMove(MouseMoveEvent {
5837 position,
5838 pressed_button: Some(MouseButton::Left),
5839 modifiers: Modifiers::default(),
5840 })
5841 }
5842 FileDropEvent::Pending { position } => {
5843 self.mouse_position = position;
5844 PlatformInput::MouseMove(MouseMoveEvent {
5845 position,
5846 pressed_button: Some(MouseButton::Left),
5847 modifiers: Modifiers::default(),
5848 })
5849 }
5850 FileDropEvent::Submit { position } => {
5851 cx.activate(true);
5852 self.mouse_position = position;
5853 PlatformInput::MouseUp(MouseUpEvent {
5854 button: MouseButton::Left,
5855 position,
5856 modifiers: Modifiers::default(),
5857 click_count: 1,
5858 })
5859 }
5860 FileDropEvent::Exited => {
5861 if !cx.hand_restored_drag_to_platform(self.handle.window_id()) {
5862 cx.active_drag.take();
5863 }
5864 self.refresh();
5865 PlatformInput::FileDrop(FileDropEvent::Exited)
5866 }
5867 FileDropEvent::Ended => {
5868 cx.end_platform_drag(self.handle.window_id());
5869 self.refresh();
5870 PlatformInput::FileDrop(FileDropEvent::Ended)
5871 }
5872 },
5873 PlatformInput::Touch(touch) => PlatformInput::Touch(touch),
5874 PlatformInput::LongPress(long_press) => {
5875 self.mouse_position = if long_press.phase == crate::TouchPhase::Started {
5876 long_press.start_position
5877 } else {
5878 long_press.position
5879 };
5880 if long_press.phase == crate::TouchPhase::Started {
5881 self.long_press_capture = None;
5882 }
5883 PlatformInput::LongPress(long_press)
5884 }
5885 PlatformInput::TouchDrag(touch_drag) => {
5886 self.mouse_position = touch_drag.start_position;
5887 PlatformInput::TouchDrag(touch_drag)
5888 }
5889 PlatformInput::KeyDown(_) | PlatformInput::KeyUp(_) => event,
5890 };
5891
5892 if let Some(any_mouse_event) = event.mouse_event() {
5893 self.dispatch_mouse_event(any_mouse_event, cx);
5894 } else if let Some(any_key_event) = event.keyboard_event() {
5895 self.dispatch_key_event(any_key_event, cx);
5896 } else if let Some(touch_event) = event.touch_event() {
5897 self.dispatch_touch_event(touch_event, cx);
5898 }
5899 if let PlatformInput::LongPress(long_press) = &event {
5900 match long_press.phase {
5901 crate::TouchPhase::Started if !self.default_prevented => {
5902 self.long_press_capture = None;
5903 }
5904 crate::TouchPhase::Ended | crate::TouchPhase::Cancelled => {
5905 self.long_press_capture = None;
5906 }
5907 crate::TouchPhase::Started | crate::TouchPhase::Moved => {}
5908 }
5909 }
5910
5911 self.promote_external_drag_to_platform(&event, cx);
5914
5915 let caused_invalidation = self.invalidator.update_count() > update_count_before;
5916 if caused_invalidation {
5917 self.input_rate_tracker.borrow_mut().record_input();
5918 }
5919 #[cfg(feature = "profiler")]
5920 self.window_profiler.end_input(caused_invalidation);
5921
5922 DispatchEventResult {
5923 propagate: cx.propagate_event,
5924 default_prevented: self.default_prevented,
5925 }
5926 }
5927
5928 fn promote_external_drag_to_platform(&mut self, event: &PlatformInput, cx: &mut App) {
5929 let PlatformInput::MouseMove(mouse_move) = event else {
5930 return;
5931 };
5932 if mouse_move.pressed_button != Some(MouseButton::Left) {
5933 return;
5934 }
5935 if Bounds::new(Point::default(), self.viewport_size).contains(&mouse_move.position) {
5936 return;
5937 }
5938 if !self.platform_window.can_start_external_drag() {
5939 return;
5940 }
5941 let Some(payload_source) = cx
5942 .active_drag
5943 .as_mut()
5944 .and_then(|drag| drag.external_payload_source.take())
5945 else {
5946 return;
5947 };
5948 let Some(payload) = payload_source(self, cx) else {
5949 return;
5950 };
5951 if self.platform_window.start_external_drag(&payload)
5952 && cx.hand_active_drag_to_platform(self.handle.window_id())
5953 {
5954 self.refresh();
5955 }
5956 }
5957
5958 pub fn touch_prediction_enabled(&self) -> bool {
5962 self.touch_prediction_enabled
5963 }
5964
5965 pub fn set_touch_prediction_enabled(&mut self, enabled: bool) {
5969 self.touch_prediction_enabled = enabled;
5970 }
5971
5972 fn dispatch_touch_event(&mut self, event: &TouchEvent, cx: &mut App) {
5976 let mut event = event.clone();
5977 if !self.touch_prediction_enabled {
5978 event.predicted_position = None;
5979 }
5980 let recognized_gestures = self.touch_gestures.handle_event(&event);
5981 if event.phase == crate::TouchPhase::Started
5982 && let Some(touch_drag) = self.touch_gestures.offer_touch_drag(event.id)
5983 {
5984 self.dispatch_recognized_touch_gesture(touch_drag, cx);
5985 }
5986 if event.phase == crate::TouchPhase::Started
5987 && self.touch_gestures.pending_long_press().is_some()
5988 {
5989 self.long_press_capture = None;
5990 }
5991 let mut tapped = false;
5992 for gesture in recognized_gestures {
5993 tapped |= matches!(gesture, RecognizedTouchGesture::Tap { .. });
5994 self.dispatch_recognized_touch_gesture(gesture, cx);
5995 }
5996 if event.phase == crate::TouchPhase::Started {
5997 self.schedule_long_press_timer(cx);
5998 } else if self.touch_gestures.pending_long_press().is_none() {
5999 self.long_press_timer.take();
6000 }
6001 if tapped && self.invalidator.is_dirty() {
6007 self.draw(cx).clear(cx);
6008 }
6009 if self.touch_gestures.has_momentum() {
6010 self.schedule_touch_momentum_tick();
6011 }
6012 }
6013
6014 fn dispatch_recognized_touch_gesture(&mut self, gesture: RecognizedTouchGesture, cx: &mut App) {
6015 match gesture {
6016 RecognizedTouchGesture::Scroll(scroll_wheel) => {
6017 self.mouse_position = scroll_wheel.position;
6018 cx.propagate_event = true;
6019 self.dispatch_mouse_event(&scroll_wheel, cx);
6020 }
6021 RecognizedTouchGesture::Tap { down, up } => {
6022 self.mouse_position = up.position;
6023 cx.propagate_event = true;
6024 self.dispatch_mouse_event(&down, cx);
6025 cx.propagate_event = true;
6026 self.dispatch_mouse_event(&up, cx);
6027 }
6028 RecognizedTouchGesture::TouchDrag(touch_drag) => {
6029 self.mouse_position = touch_drag.start_position;
6030 cx.propagate_event = true;
6031 self.default_prevented = false;
6032 let started = touch_drag.phase == crate::TouchPhase::Started;
6033 self.dispatch_mouse_event(&touch_drag, cx);
6034 if started {
6035 self.touch_gestures
6036 .resolve_touch_drag(self.default_prevented);
6037 }
6038 }
6039 RecognizedTouchGesture::LongPress(long_press) => {
6040 self.mouse_position = if long_press.phase == crate::TouchPhase::Started {
6041 long_press.start_position
6042 } else {
6043 long_press.position
6044 };
6045 cx.propagate_event = true;
6046 self.default_prevented = false;
6047 let started = long_press.phase == crate::TouchPhase::Started;
6048 let ended = matches!(
6049 long_press.phase,
6050 crate::TouchPhase::Ended | crate::TouchPhase::Cancelled
6051 );
6052 self.dispatch_mouse_event(&long_press, cx);
6053 if started {
6054 let claimed = self.default_prevented;
6055 self.touch_gestures.resolve_long_press(claimed);
6056 if !claimed {
6057 self.long_press_capture = None;
6058 }
6059 }
6060 if ended {
6061 self.long_press_capture = None;
6062 }
6063 }
6064 }
6065 }
6066
6067 fn schedule_long_press_timer(&mut self, cx: &mut App) {
6068 self.long_press_timer.take();
6069 let Some((touch_id, duration)) = self.touch_gestures.pending_long_press() else {
6070 return;
6071 };
6072 self.long_press_timer = Some(self.spawn(cx, async move |cx| {
6073 cx.background_executor.timer(duration).await;
6074 cx.update(move |window, cx| {
6075 window.long_press_timer.take();
6076 if let Some(gesture) = window.touch_gestures.offer_long_press(touch_id) {
6077 window.dispatch_recognized_touch_gesture(gesture, cx);
6078 }
6079 })
6080 .log_err();
6081 }));
6082 }
6083
6084 fn schedule_touch_momentum_tick(&mut self) {
6085 self.on_next_frame(|window, cx| {
6086 if let Some(gesture) = window.touch_gestures.tick_momentum() {
6087 window.dispatch_recognized_touch_gesture(gesture, cx);
6088 }
6089 if window.touch_gestures.has_momentum() {
6090 window.schedule_touch_momentum_tick();
6091 }
6092 });
6093 }
6094
6095 fn dispatch_mouse_event(&mut self, event: &dyn Any, cx: &mut App) {
6096 let hit_test = self.rendered_frame.hit_test(self.mouse_position());
6097 if hit_test != self.mouse_hit_test {
6098 self.mouse_hit_test = hit_test;
6099 self.reset_cursor_style(cx);
6100 }
6101
6102 #[cfg(any(feature = "inspector", debug_assertions))]
6103 if self.is_inspector_picking(cx) {
6104 self.handle_inspector_mouse_event(event, cx);
6105 return;
6107 }
6108
6109 let mut mouse_listeners = mem::take(&mut self.rendered_frame.mouse_listeners);
6110
6111 for listener in &mut mouse_listeners {
6114 let listener = listener.as_mut().unwrap();
6115 listener(event, DispatchPhase::Capture, self, cx);
6116 if !cx.propagate_event {
6117 break;
6118 }
6119 }
6120
6121 if cx.propagate_event {
6123 for listener in mouse_listeners.iter_mut().rev() {
6124 let listener = listener.as_mut().unwrap();
6125 listener(event, DispatchPhase::Bubble, self, cx);
6126 if !cx.propagate_event {
6127 break;
6128 }
6129 }
6130 }
6131
6132 self.rendered_frame.mouse_listeners = mouse_listeners;
6133
6134 if cx.has_active_drag() {
6135 if event.is::<MouseMoveEvent>() {
6136 self.refresh();
6139 } else if event.is::<MouseUpEvent>() {
6140 cx.active_drag = None;
6143 self.refresh();
6144 }
6145 }
6146
6147 if event.is::<MouseUpEvent>() && self.captured_hitbox.is_some() {
6149 self.captured_hitbox = None;
6150 }
6151 }
6152
6153 fn dispatch_key_event(&mut self, event: &dyn Any, cx: &mut App) {
6154 if self.invalidator.is_dirty() {
6155 self.draw(cx).clear(cx);
6156 }
6157
6158 let node_id = self.focus_node_id_in_rendered_frame(self.focus);
6159 let dispatch_path = self.rendered_frame.dispatch_tree.dispatch_path(node_id);
6160
6161 let mut keystroke: Option<Keystroke> = None;
6162
6163 if let Some(event) = event.downcast_ref::<ModifiersChangedEvent>() {
6164 if event.modifiers.number_of_modifiers() == 0
6165 && self.pending_modifier.modifiers.number_of_modifiers() == 1
6166 && !self.pending_modifier.saw_other_input
6167 {
6168 let key = match self.pending_modifier.modifiers {
6169 modifiers if modifiers.shift => Some("shift"),
6170 modifiers if modifiers.control => Some("control"),
6171 modifiers if modifiers.alt => Some("alt"),
6172 modifiers if modifiers.platform => Some("platform"),
6173 modifiers if modifiers.function => Some("function"),
6174 _ => None,
6175 };
6176 if let Some(key) = key {
6177 keystroke = Some(Keystroke {
6178 key: key.to_string(),
6179 key_char: None,
6180 modifiers: Modifiers::default(),
6181 });
6182 }
6183 }
6184
6185 if self.pending_modifier.modifiers.number_of_modifiers() == 0
6186 && event.modifiers.number_of_modifiers() == 1
6187 {
6188 self.pending_modifier.saw_other_input = false
6189 } else if event.modifiers.number_of_modifiers() > 1 {
6190 self.pending_modifier.saw_other_input = true
6191 }
6192 self.pending_modifier.modifiers = event.modifiers
6193 } else if let Some(key_down_event) = event.downcast_ref::<KeyDownEvent>() {
6194 self.pending_modifier.saw_other_input = true;
6195 keystroke = Some(key_down_event.keystroke.clone());
6196 if key_down_event.keystroke.key_char.is_some()
6197 && matches!(
6198 cx.cursor_hide_mode,
6199 CursorHideMode::OnTyping | CursorHideMode::OnTypingAndAction
6200 )
6201 {
6202 cx.platform.hide_cursor_until_mouse_moves();
6203 }
6204 }
6205
6206 let Some(keystroke) = keystroke else {
6207 self.finish_dispatch_key_event(event, None, dispatch_path, self.context_stack(), cx);
6208 return;
6209 };
6210
6211 cx.propagate_event = true;
6212 self.dispatch_keystroke_interceptors(&keystroke, self.context_stack(), cx);
6213 if !cx.propagate_event {
6214 self.finish_dispatch_key_event(
6215 event,
6216 Some(&keystroke),
6217 dispatch_path,
6218 self.context_stack(),
6219 cx,
6220 );
6221 return;
6222 }
6223
6224 let mut currently_pending = self.pending_input.take().unwrap_or_default();
6225 if currently_pending.focus.is_some() && currently_pending.focus != self.focus {
6226 currently_pending = PendingInput::default();
6227 }
6228
6229 let match_result = self.rendered_frame.dispatch_tree.dispatch_key(
6230 currently_pending.keystrokes,
6231 keystroke.clone(),
6232 &dispatch_path,
6233 );
6234
6235 if !match_result.to_replay.is_empty() {
6236 self.replay_pending_input(match_result.to_replay, cx);
6237 cx.propagate_event = true;
6238 }
6239
6240 if !match_result.pending.is_empty() {
6241 let previous_timeout = currently_pending.timeout.take();
6242 currently_pending.keystrokes = match_result.pending;
6243 currently_pending.focus = self.focus;
6244
6245 let text_input_requires_timeout = event
6246 .downcast_ref::<KeyDownEvent>()
6247 .filter(|key_down| key_down.keystroke.key_char.is_some())
6248 .and_then(|_| self.platform_window.take_input_handler())
6249 .map_or(false, |mut input_handler| {
6250 let accepts = input_handler.accepts_text_input(self, cx);
6251 self.platform_window.set_input_handler(input_handler);
6252 accepts
6253 });
6254
6255 let needs_timeout = previous_timeout.is_some()
6256 || match_result.pending_has_binding
6257 || text_input_requires_timeout;
6258 currently_pending.timeout = if needs_timeout {
6259 match previous_timeout {
6260 Some(mut timeout) if timeout.is_paused() => {
6261 timeout.reset_duration(PENDING_INPUT_TIMEOUT);
6262 Some(timeout)
6263 }
6264 previous_timeout => {
6265 drop(previous_timeout);
6266 Some(self.new_pending_input_timeout(PENDING_INPUT_TIMEOUT, cx))
6267 }
6268 }
6269 } else {
6270 None
6271 };
6272 self.pending_input = Some(currently_pending);
6273 self.pending_input_changed(cx);
6274 cx.propagate_event = false;
6275 return;
6276 }
6277
6278 let skip_bindings = event
6279 .downcast_ref::<KeyDownEvent>()
6280 .filter(|key_down_event| key_down_event.prefer_character_input)
6281 .map(|_| {
6282 self.platform_window
6283 .take_input_handler()
6284 .map_or(false, |mut input_handler| {
6285 let accepts = input_handler.accepts_text_input(self, cx);
6286 self.platform_window.set_input_handler(input_handler);
6287 accepts
6290 })
6291 })
6292 .unwrap_or(false);
6293
6294 if !skip_bindings {
6295 for binding in match_result.bindings {
6296 self.dispatch_action_on_node(node_id, binding.action.as_ref(), cx);
6297 if !cx.propagate_event {
6298 self.dispatch_keystroke_observers(
6299 &keystroke,
6300 Some(binding.action.as_ref()),
6301 match_result.context_stack,
6302 cx,
6303 );
6304 self.pending_input_changed(cx);
6305 return;
6306 }
6307 }
6308 }
6309
6310 self.finish_dispatch_key_event(
6311 event,
6312 Some(&keystroke),
6313 dispatch_path,
6314 match_result.context_stack,
6315 cx,
6316 );
6317 self.pending_input_changed(cx);
6318 }
6319
6320 fn new_pending_input_timeout(&self, duration: Duration, cx: &App) -> PendingInputTimeout {
6321 let (started_at, task) = self.start_pending_input_timeout(duration, cx);
6322 PendingInputTimeout {
6323 duration,
6324 remaining: duration,
6325 state: PendingInputTimeoutState::Running { started_at, task },
6326 }
6327 }
6328
6329 fn start_pending_input_timeout(&self, remaining: Duration, cx: &App) -> (Instant, Task<()>) {
6330 let started_at = cx.background_executor().now();
6331 let task = self.spawn(cx, async move |cx| {
6332 cx.background_executor.timer(remaining).await;
6333 cx.update(move |window, cx| {
6334 let Some(currently_pending) = window
6335 .pending_input
6336 .take()
6337 .filter(|pending| pending.focus == window.focus)
6338 else {
6339 return;
6340 };
6341
6342 let node_id = window.focus_node_id_in_rendered_frame(window.focus);
6343 let dispatch_path = window.rendered_frame.dispatch_tree.dispatch_path(node_id);
6344
6345 let to_replay = window
6346 .rendered_frame
6347 .dispatch_tree
6348 .flush_dispatch(currently_pending.keystrokes, &dispatch_path);
6349
6350 window.pending_input_changed(cx);
6351 window.replay_pending_input(to_replay, cx)
6352 })
6353 .log_err();
6354 });
6355 (started_at, task)
6356 }
6357
6358 fn finish_dispatch_key_event(
6359 &mut self,
6360 event: &dyn Any,
6361 recognized_keystroke: Option<&Keystroke>,
6362 dispatch_path: SmallVec<[DispatchNodeId; 32]>,
6363 context_stack: Vec<KeyContext>,
6364 cx: &mut App,
6365 ) {
6366 self.dispatch_key_down_up_event(event, &dispatch_path, cx);
6367 if !cx.propagate_event {
6368 return;
6369 }
6370
6371 self.dispatch_modifiers_changed_event(event, &dispatch_path, cx);
6372 if !cx.propagate_event {
6373 return;
6374 }
6375
6376 if let Some(keystroke) = recognized_keystroke {
6377 self.dispatch_keystroke_observers(keystroke, None, context_stack, cx);
6378 }
6379 }
6380
6381 pub(crate) fn pending_input_changed(&mut self, cx: &mut App) {
6382 self.pending_input_observers
6383 .clone()
6384 .retain(&(), |callback| callback(self, cx));
6385 }
6386
6387 fn defer_pending_input_changed(&self, cx: &mut App) {
6388 let window_handle = self.handle;
6391 cx.defer(move |cx| {
6392 window_handle
6393 .update(cx, |_, window, cx| {
6394 window.pending_input_changed(cx);
6395 })
6396 .ok();
6397 });
6398 }
6399
6400 fn dispatch_key_down_up_event(
6401 &mut self,
6402 event: &dyn Any,
6403 dispatch_path: &SmallVec<[DispatchNodeId; 32]>,
6404 cx: &mut App,
6405 ) {
6406 for node_id in dispatch_path {
6408 let node = self.rendered_frame.dispatch_tree.node(*node_id);
6409
6410 for key_listener in node.key_listeners.clone() {
6411 key_listener(event, DispatchPhase::Capture, self, cx);
6412 if !cx.propagate_event {
6413 return;
6414 }
6415 }
6416 }
6417
6418 for node_id in dispatch_path.iter().rev() {
6420 let node = self.rendered_frame.dispatch_tree.node(*node_id);
6422 for key_listener in node.key_listeners.clone() {
6423 key_listener(event, DispatchPhase::Bubble, self, cx);
6424 if !cx.propagate_event {
6425 return;
6426 }
6427 }
6428 }
6429 }
6430
6431 fn dispatch_modifiers_changed_event(
6432 &mut self,
6433 event: &dyn Any,
6434 dispatch_path: &SmallVec<[DispatchNodeId; 32]>,
6435 cx: &mut App,
6436 ) {
6437 let Some(event) = event.downcast_ref::<ModifiersChangedEvent>() else {
6438 return;
6439 };
6440 for node_id in dispatch_path.iter().rev() {
6441 let node = self.rendered_frame.dispatch_tree.node(*node_id);
6442 for listener in node.modifiers_changed_listeners.clone() {
6443 listener(event, self, cx);
6444 if !cx.propagate_event {
6445 return;
6446 }
6447 }
6448 }
6449 }
6450
6451 pub fn has_pending_keystrokes(&self) -> bool {
6453 self.pending_input().is_some()
6454 }
6455
6456 #[cfg(test)]
6457 pub(crate) fn pending_input_is_none(&self) -> bool {
6458 self.pending_input.is_none()
6459 }
6460
6461 pub(crate) fn clear_pending_keystrokes(&mut self, cx: &mut App) {
6462 if self.pending_input.take().is_some() {
6463 self.defer_pending_input_changed(cx);
6464 }
6465 }
6466
6467 pub fn pending_input(&self) -> Option<PendingInputStatus<'_>> {
6470 self.pending_input
6471 .as_ref()
6472 .filter(|pending_input| pending_input.focus == self.focus)
6473 .map(|pending_input| PendingInputStatus {
6474 keystrokes: pending_input.keystrokes.as_slice(),
6475 timeout: pending_input
6476 .timeout
6477 .as_ref()
6478 .map(PendingInputTimeout::status),
6479 })
6480 }
6481
6482 pub fn set_pending_input_timeout_paused<T: 'static>(
6487 &mut self,
6488 owner: &Entity<T>,
6489 paused: bool,
6490 cx: &mut App,
6491 ) -> bool {
6492 let owner_id = owner.entity_id();
6493 if !paused {
6494 return self.resume_pending_input_timeout(owner_id, cx);
6495 }
6496
6497 let timeout = self
6498 .pending_input
6499 .as_ref()
6500 .filter(|pending_input| pending_input.focus == self.focus)
6501 .and_then(|pending_input| pending_input.timeout.as_ref());
6502 let Some(timeout) = timeout else {
6503 return false;
6504 };
6505 if timeout.is_paused() {
6506 return false;
6507 }
6508
6509 let release_subscription = self.observe_release(owner, cx, move |_, window, cx| {
6510 window.resume_pending_input_timeout(owner_id, cx);
6511 });
6512 let now = cx.background_executor().now();
6513 let changed = self
6514 .pending_input
6515 .as_mut()
6516 .filter(|pending_input| pending_input.focus == self.focus)
6517 .and_then(|pending_input| pending_input.timeout.as_mut())
6518 .is_some_and(|timeout| {
6519 timeout.pause(
6520 PendingInputTimeoutPause {
6521 owner_id,
6522 _release_subscription: release_subscription,
6523 },
6524 now,
6525 )
6526 });
6527
6528 if changed {
6529 self.defer_pending_input_changed(cx);
6530 }
6531 changed
6532 }
6533
6534 fn resume_pending_input_timeout(&mut self, owner_id: EntityId, cx: &mut App) -> bool {
6535 let Some(remaining) = self
6536 .pending_input
6537 .as_ref()
6538 .and_then(|pending_input| pending_input.timeout.as_ref())
6539 .filter(|timeout| timeout.pause_owner_id() == Some(owner_id))
6540 .map(|timeout| timeout.remaining)
6541 else {
6542 return false;
6543 };
6544
6545 let (started_at, task) = self.start_pending_input_timeout(remaining, cx);
6546 let changed = self
6547 .pending_input
6548 .as_mut()
6549 .and_then(|pending_input| pending_input.timeout.as_mut())
6550 .is_some_and(|timeout| timeout.resume(owner_id, started_at, task));
6551
6552 if changed {
6553 self.defer_pending_input_changed(cx);
6554 }
6555 changed
6556 }
6557
6558 pub fn pending_input_keystrokes(&self) -> Option<&[Keystroke]> {
6560 self.pending_input()
6561 .map(|pending_input| pending_input.keystrokes())
6562 }
6563
6564 fn replay_pending_input(&mut self, replays: SmallVec<[Replay; 1]>, cx: &mut App) {
6565 let node_id = self.focus_node_id_in_rendered_frame(self.focus);
6566 let dispatch_path = self.rendered_frame.dispatch_tree.dispatch_path(node_id);
6567
6568 'replay: for replay in replays {
6569 let event = KeyDownEvent {
6570 keystroke: replay.keystroke.clone(),
6571 is_held: false,
6572 prefer_character_input: true,
6573 layout: None,
6574 };
6575
6576 cx.propagate_event = true;
6577 for binding in replay.bindings {
6578 self.dispatch_action_on_node(node_id, binding.action.as_ref(), cx);
6579 if !cx.propagate_event {
6580 self.dispatch_keystroke_observers(
6581 &replay.keystroke,
6582 Some(binding.action.as_ref()),
6583 Vec::default(),
6584 cx,
6585 );
6586 continue 'replay;
6587 }
6588 }
6589
6590 self.dispatch_key_down_up_event(&event, &dispatch_path, cx);
6591 if !cx.propagate_event {
6592 continue 'replay;
6593 }
6594 if let Some(input) = replay.keystroke.key_char.as_ref().cloned()
6595 && let Some(mut input_handler) = self.platform_window.take_input_handler()
6596 {
6597 input_handler.dispatch_input(&input, self, cx);
6598 self.platform_window.set_input_handler(input_handler)
6599 }
6600 }
6601 }
6602
6603 fn focus_node_id_in_rendered_frame(&self, focus_id: Option<FocusId>) -> DispatchNodeId {
6604 focus_id
6605 .and_then(|focus_id| {
6606 self.rendered_frame
6607 .dispatch_tree
6608 .focusable_node_id(focus_id)
6609 })
6610 .unwrap_or_else(|| self.rendered_frame.dispatch_tree.root_node_id())
6611 }
6612
6613 fn dispatch_action_on_node(
6614 &mut self,
6615 node_id: DispatchNodeId,
6616 action: &dyn Action,
6617 cx: &mut App,
6618 ) {
6619 self.dispatch_action_on_node_inner(node_id, action, cx);
6620
6621 if !cx.propagate_event
6622 && cx.cursor_hide_mode == CursorHideMode::OnTypingAndAction
6623 && self.last_input_was_keyboard()
6624 {
6625 cx.platform.hide_cursor_until_mouse_moves();
6626 }
6627 }
6628
6629 fn dispatch_action_on_node_inner(
6630 &mut self,
6631 node_id: DispatchNodeId,
6632 action: &dyn Action,
6633 cx: &mut App,
6634 ) {
6635 let dispatch_path = self.rendered_frame.dispatch_tree.dispatch_path(node_id);
6636
6637 cx.propagate_event = true;
6639 if let Some(mut global_listeners) = cx
6640 .global_action_listeners
6641 .remove(&action.as_any().type_id())
6642 {
6643 for listener in &global_listeners {
6644 #[cfg(feature = "profiler")]
6645 self.window_profiler.begin_action_handler(action, cx);
6646 listener(action.as_any(), DispatchPhase::Capture, cx);
6647 #[cfg(feature = "profiler")]
6648 self.window_profiler.end_action_handler();
6649 if !cx.propagate_event {
6650 break;
6651 }
6652 }
6653
6654 global_listeners.extend(
6655 cx.global_action_listeners
6656 .remove(&action.as_any().type_id())
6657 .unwrap_or_default(),
6658 );
6659
6660 cx.global_action_listeners
6661 .insert(action.as_any().type_id(), global_listeners);
6662 }
6663
6664 if !cx.propagate_event {
6665 return;
6666 }
6667
6668 for node_id in &dispatch_path {
6670 let node = self.rendered_frame.dispatch_tree.node(*node_id);
6671 for DispatchActionListener {
6672 action_type,
6673 listener,
6674 } in node.action_listeners.clone()
6675 {
6676 let any_action = action.as_any();
6677 if action_type == any_action.type_id() {
6678 #[cfg(feature = "profiler")]
6679 self.window_profiler.begin_action_handler(action, cx);
6680 listener(any_action, DispatchPhase::Capture, self, cx);
6681 #[cfg(feature = "profiler")]
6682 self.window_profiler.end_action_handler();
6683
6684 if !cx.propagate_event {
6685 return;
6686 }
6687 }
6688 }
6689 }
6690
6691 for node_id in dispatch_path.iter().rev() {
6693 let node = self.rendered_frame.dispatch_tree.node(*node_id);
6694 for DispatchActionListener {
6695 action_type,
6696 listener,
6697 } in node.action_listeners.clone()
6698 {
6699 let any_action = action.as_any();
6700 if action_type == any_action.type_id() {
6701 cx.propagate_event = false; #[cfg(feature = "profiler")]
6703 self.window_profiler.begin_action_handler(action, cx);
6704 listener(any_action, DispatchPhase::Bubble, self, cx);
6705 #[cfg(feature = "profiler")]
6706 self.window_profiler.end_action_handler();
6707
6708 if !cx.propagate_event {
6709 return;
6710 }
6711 }
6712 }
6713 }
6714
6715 if let Some(mut global_listeners) = cx
6717 .global_action_listeners
6718 .remove(&action.as_any().type_id())
6719 {
6720 for listener in global_listeners.iter().rev() {
6721 cx.propagate_event = false; #[cfg(feature = "profiler")]
6724 self.window_profiler.begin_action_handler(action, cx);
6725 listener(action.as_any(), DispatchPhase::Bubble, cx);
6726 #[cfg(feature = "profiler")]
6727 self.window_profiler.end_action_handler();
6728 if !cx.propagate_event {
6729 break;
6730 }
6731 }
6732
6733 global_listeners.extend(
6734 cx.global_action_listeners
6735 .remove(&action.as_any().type_id())
6736 .unwrap_or_default(),
6737 );
6738
6739 cx.global_action_listeners
6740 .insert(action.as_any().type_id(), global_listeners);
6741 }
6742 }
6743
6744 pub fn observe_global<G: Global>(
6747 &mut self,
6748 cx: &mut App,
6749 f: impl Fn(&mut Window, &mut App) + 'static,
6750 ) -> Subscription {
6751 let window_handle = self.handle;
6752 let (subscription, activate) = cx.global_observers.insert(
6753 TypeId::of::<G>(),
6754 Box::new(move |cx| {
6755 window_handle
6756 .update(cx, |_, window, cx| f(window, cx))
6757 .is_ok()
6758 }),
6759 );
6760 cx.defer(move |_| activate());
6761 subscription
6762 }
6763
6764 pub fn activate_window(&self) {
6766 self.platform_window.activate();
6767 }
6768
6769 pub fn request_attention(&self) {
6771 self.platform_window.request_attention();
6772 }
6773
6774 pub fn minimize_window(&self) {
6776 self.platform_window.minimize();
6777 }
6778
6779 pub fn toggle_fullscreen(&self) {
6781 self.platform_window.toggle_fullscreen();
6782 }
6783
6784 pub fn toggle_simple_fullscreen(&self) {
6789 self.platform_window.toggle_simple_fullscreen();
6790 }
6791
6792 pub fn invalidate_character_coordinates(&self) {
6794 self.on_next_frame(|window, cx| {
6795 if let Some(mut input_handler) = window.platform_window.take_input_handler() {
6796 if let Some(bounds) = input_handler.selected_bounds(window, cx) {
6797 window.platform_window.update_ime_position(bounds);
6798 }
6799 window.platform_window.set_input_handler(input_handler);
6800 }
6801 });
6802 }
6803
6804 pub fn prompt<T>(
6808 &mut self,
6809 level: PromptLevel,
6810 message: &str,
6811 detail: Option<&str>,
6812 answers: &[T],
6813 cx: &mut App,
6814 ) -> oneshot::Receiver<usize>
6815 where
6816 T: Clone + Into<PromptButton>,
6817 {
6818 let prompt_builder = cx.prompt_builder.take();
6819 let Some(prompt_builder) = prompt_builder else {
6820 unreachable!("Re-entrant window prompting is not supported by GPUI");
6821 };
6822
6823 let answers = answers
6824 .iter()
6825 .map(|answer| answer.clone().into())
6826 .collect::<Vec<_>>();
6827
6828 let receiver = match &prompt_builder {
6829 PromptBuilder::Default => self
6830 .platform_window
6831 .prompt(level, message, detail, &answers)
6832 .unwrap_or_else(|| {
6833 self.build_custom_prompt(&prompt_builder, level, message, detail, &answers, cx)
6834 }),
6835 PromptBuilder::Custom(_) => {
6836 self.build_custom_prompt(&prompt_builder, level, message, detail, &answers, cx)
6837 }
6838 };
6839
6840 cx.prompt_builder = Some(prompt_builder);
6841
6842 receiver
6843 }
6844
6845 fn build_custom_prompt(
6846 &mut self,
6847 prompt_builder: &PromptBuilder,
6848 level: PromptLevel,
6849 message: &str,
6850 detail: Option<&str>,
6851 answers: &[PromptButton],
6852 cx: &mut App,
6853 ) -> oneshot::Receiver<usize> {
6854 let (sender, receiver) = oneshot::channel();
6855 let handle = PromptHandle::new(sender);
6856 let handle = (prompt_builder)(level, message, detail, answers, handle, self, cx);
6857 self.prompt = Some(handle);
6858 receiver
6859 }
6860
6861 pub fn has_active_prompt(&self) -> bool {
6866 self.prompt.is_some()
6867 }
6868
6869 pub fn context_stack(&self) -> Vec<KeyContext> {
6871 let node_id = self.focus_node_id_in_rendered_frame(self.focus);
6872 let dispatch_tree = &self.rendered_frame.dispatch_tree;
6873 dispatch_tree
6874 .dispatch_path(node_id)
6875 .iter()
6876 .filter_map(move |&node_id| dispatch_tree.node(node_id).context.clone())
6877 .collect()
6878 }
6879
6880 pub fn available_actions(&self, cx: &App) -> Vec<Box<dyn Action>> {
6882 let node_id = self.focus_node_id_in_rendered_frame(self.focus);
6883 let mut actions = self.rendered_frame.dispatch_tree.available_actions(node_id);
6884 for action_type in cx.global_action_listeners.keys() {
6885 if let Err(ix) = actions.binary_search_by_key(action_type, |a| a.as_any().type_id()) {
6886 let action = cx.actions.build_action_type(action_type).ok();
6887 if let Some(action) = action {
6888 actions.insert(ix, action);
6889 }
6890 }
6891 }
6892 actions
6893 }
6894
6895 pub fn bindings_for_action(&self, action: &dyn Action) -> Vec<KeyBinding> {
6898 self.rendered_frame
6899 .dispatch_tree
6900 .bindings_for_action(action, &self.rendered_frame.dispatch_tree.context_stack)
6901 }
6902
6903 pub fn highest_precedence_binding_for_action(&self, action: &dyn Action) -> Option<KeyBinding> {
6906 self.rendered_frame
6907 .dispatch_tree
6908 .highest_precedence_binding_for_action(
6909 action,
6910 &self.rendered_frame.dispatch_tree.context_stack,
6911 )
6912 }
6913
6914 pub fn bindings_for_action_in_context(
6916 &self,
6917 action: &dyn Action,
6918 context: KeyContext,
6919 ) -> Vec<KeyBinding> {
6920 let dispatch_tree = &self.rendered_frame.dispatch_tree;
6921 dispatch_tree.bindings_for_action(action, &[context])
6922 }
6923
6924 pub fn highest_precedence_binding_for_action_in_context(
6927 &self,
6928 action: &dyn Action,
6929 context: KeyContext,
6930 ) -> Option<KeyBinding> {
6931 let dispatch_tree = &self.rendered_frame.dispatch_tree;
6932 dispatch_tree.highest_precedence_binding_for_action(action, &[context])
6933 }
6934
6935 pub fn bindings_for_action_in(
6939 &self,
6940 action: &dyn Action,
6941 focus_handle: &FocusHandle,
6942 ) -> Vec<KeyBinding> {
6943 let dispatch_tree = &self.rendered_frame.dispatch_tree;
6944 let Some(context_stack) = self.context_stack_for_focus_handle(focus_handle) else {
6945 return vec![];
6946 };
6947 dispatch_tree.bindings_for_action(action, &context_stack)
6948 }
6949
6950 pub fn highest_precedence_binding_for_action_in(
6954 &self,
6955 action: &dyn Action,
6956 focus_handle: &FocusHandle,
6957 ) -> Option<KeyBinding> {
6958 let dispatch_tree = &self.rendered_frame.dispatch_tree;
6959 let context_stack = self.context_stack_for_focus_handle(focus_handle)?;
6960 dispatch_tree.highest_precedence_binding_for_action(action, &context_stack)
6961 }
6962
6963 pub fn possible_bindings_for_input(&self, input: &[Keystroke]) -> Vec<KeyBinding> {
6965 self.rendered_frame
6966 .dispatch_tree
6967 .possible_next_bindings_for_input(input, &self.context_stack())
6968 }
6969
6970 fn context_stack_for_focus_handle(
6971 &self,
6972 focus_handle: &FocusHandle,
6973 ) -> Option<Vec<KeyContext>> {
6974 let dispatch_tree = &self.rendered_frame.dispatch_tree;
6975 let node_id = dispatch_tree.focusable_node_id(focus_handle.id)?;
6976 let context_stack: Vec<_> = dispatch_tree
6977 .dispatch_path(node_id)
6978 .into_iter()
6979 .filter_map(|node_id| dispatch_tree.node(node_id).context.clone())
6980 .collect();
6981 Some(context_stack)
6982 }
6983
6984 pub fn listener_for<T: 'static, E>(
6986 &self,
6987 view: &Entity<T>,
6988 f: impl Fn(&mut T, &E, &mut Window, &mut Context<T>) + 'static,
6989 ) -> impl Fn(&E, &mut Window, &mut App) + 'static {
6990 let view = view.downgrade();
6991 move |e: &E, window: &mut Window, cx: &mut App| {
6992 view.update(cx, |view, cx| f(view, e, window, cx)).ok();
6993 }
6994 }
6995
6996 pub fn handler_for<E: 'static, Callback: Fn(&mut E, &mut Window, &mut Context<E>) + 'static>(
6998 &self,
6999 entity: &Entity<E>,
7000 f: Callback,
7001 ) -> impl Fn(&mut Window, &mut App) + 'static {
7002 let entity = entity.downgrade();
7003 move |window: &mut Window, cx: &mut App| {
7004 entity.update(cx, |entity, cx| f(entity, window, cx)).ok();
7005 }
7006 }
7007
7008 pub fn on_window_should_close(
7011 &self,
7012 cx: &App,
7013 f: impl Fn(&mut Window, &mut App) -> bool + 'static,
7014 ) {
7015 let mut cx = self.to_async(cx);
7016 self.platform_window.on_should_close(Box::new(move || {
7017 cx.update(|window, cx| f(window, cx)).unwrap_or(true)
7018 }))
7019 }
7020
7021 pub fn on_action(
7030 &mut self,
7031 action_type: TypeId,
7032 listener: impl Fn(&dyn Any, DispatchPhase, &mut Window, &mut App) + 'static,
7033 ) {
7034 self.invalidator.debug_assert_paint();
7035
7036 self.next_frame
7037 .dispatch_tree
7038 .on_action(action_type, Rc::new(listener));
7039 }
7040
7041 pub fn on_action_when(
7050 &mut self,
7051 condition: bool,
7052 action_type: TypeId,
7053 listener: impl Fn(&dyn Any, DispatchPhase, &mut Window, &mut App) + 'static,
7054 ) {
7055 self.invalidator.debug_assert_paint();
7056
7057 if condition {
7058 self.next_frame
7059 .dispatch_tree
7060 .on_action(action_type, Rc::new(listener));
7061 }
7062 }
7063
7064 pub fn gpu_specs(&self) -> Option<GpuSpecs> {
7067 self.platform_window.gpu_specs()
7068 }
7069
7070 pub fn gpu_time(&self) -> Option<Duration> {
7075 self.platform_window.gpu_time()
7076 }
7077
7078 pub fn titlebar_double_click(&self) {
7081 self.platform_window
7082 .titlebar_double_click(self.is_resizable, self.is_minimizable);
7083 }
7084
7085 pub fn window_title(&self) -> String {
7088 self.platform_window.get_title()
7089 }
7090
7091 pub fn tabbed_windows(&self) -> Option<Vec<SystemWindowTab>> {
7094 self.platform_window.tabbed_windows()
7095 }
7096
7097 pub fn tab_bar_visible(&self) -> bool {
7100 self.platform_window.tab_bar_visible()
7101 }
7102
7103 pub fn merge_all_windows(&self) {
7106 self.platform_window.merge_all_windows()
7107 }
7108
7109 pub fn move_tab_to_new_window(&self) {
7112 self.platform_window.move_tab_to_new_window()
7113 }
7114
7115 pub fn toggle_window_tab_overview(&self) {
7118 self.platform_window.toggle_window_tab_overview()
7119 }
7120
7121 pub fn set_tabbing_identifier(&self, tabbing_identifier: Option<String>) {
7124 self.platform_window
7125 .set_tabbing_identifier(tabbing_identifier)
7126 }
7127
7128 pub fn play_system_bell(&self) {
7131 self.platform_window.play_system_bell()
7132 }
7133
7134 pub fn is_a11y_active(&self) -> bool {
7145 self.a11y.is_active()
7146 }
7147
7148 pub fn debug_a11y_tree_json(&self) -> Option<String> {
7150 self.a11y.debug_tree_json()
7151 }
7152
7153 pub fn on_a11y_action(
7159 &mut self,
7160 node_id: accesskit::NodeId,
7161 action: accesskit::Action,
7162 listener: impl FnMut(Option<&accesskit::ActionData>, &mut Window, &mut App) + 'static,
7163 ) {
7164 self.a11y
7165 .action_listeners
7166 .entry(node_id)
7167 .or_default()
7168 .push((action, Box::new(listener)));
7169 }
7170
7171 #[cfg(not(target_family = "wasm"))]
7172 pub(crate) fn handle_a11y_action(&mut self, request: accesskit::ActionRequest, cx: &mut App) {
7173 if let Some(mut listeners) = self.a11y.action_listeners.remove(&request.target_node) {
7176 let extra_data = request.data.as_ref();
7177 let mut matched = false;
7178 for (action, listener) in &mut listeners {
7179 if *action == request.action {
7180 listener(extra_data, self, cx);
7181 matched = true;
7182 }
7183 }
7184 self.a11y
7185 .action_listeners
7186 .insert(request.target_node, listeners);
7187 if matched {
7188 return;
7189 }
7190 }
7191
7192 match request.action {
7194 accesskit::Action::Click => {
7195 if let Some(bounds) = self.a11y.node_bounds.get(&request.target_node).copied() {
7196 let center = bounds.center();
7197 let mouse_down = PlatformInput::MouseDown(crate::MouseDownEvent {
7198 button: MouseButton::Left,
7199 position: center,
7200 modifiers: Modifiers::default(),
7201 click_count: 1,
7202 first_mouse: false,
7203 });
7204 let mouse_up = PlatformInput::MouseUp(MouseUpEvent {
7205 button: MouseButton::Left,
7206 position: center,
7207 modifiers: Modifiers::default(),
7208 click_count: 1,
7209 });
7210 self.dispatch_event(mouse_down, cx);
7211 self.dispatch_event(mouse_up, cx);
7212 }
7213 }
7214 accesskit::Action::Focus => {
7215 if let Some(focus_id) = self.a11y.focus_ids.get(&request.target_node).copied()
7216 && let Some(handle) = FocusHandle::for_id(focus_id, &cx.focus_handles)
7217 {
7218 self.focus(&handle, cx);
7219 }
7220 }
7221 accesskit::Action::Blur => {
7222 self.blur(cx);
7223 }
7224 _ => {
7225 log::debug!(
7226 "Unhandled a11y action: {:?} on {:?}",
7227 request.action,
7228 request.target_node
7229 );
7230 }
7231 }
7232 }
7233
7234 #[cfg(any(feature = "inspector", debug_assertions))]
7236 pub fn toggle_inspector(&mut self, cx: &mut App) {
7237 self.inspector = match self.inspector {
7238 None => Some(cx.new(|_| Inspector::new())),
7239 Some(_) => {
7240 self.rendered_frame.next_inspector_instance_ids = FxHashMap::default();
7241 self.rendered_frame.inspector_hitboxes = FxHashMap::default();
7242 self.next_frame.next_inspector_instance_ids = FxHashMap::default();
7243 self.next_frame.inspector_hitboxes = FxHashMap::default();
7244 None
7245 }
7246 };
7247 self.refresh();
7248 }
7249
7250 pub fn is_inspector_picking(&self, _cx: &App) -> bool {
7252 #[cfg(any(feature = "inspector", debug_assertions))]
7253 {
7254 if let Some(inspector) = &self.inspector {
7255 return inspector.read(_cx).is_picking();
7256 }
7257 }
7258 false
7259 }
7260
7261 #[cfg(any(feature = "inspector", debug_assertions))]
7263 pub fn with_inspector_state<T: 'static, R>(
7264 &mut self,
7265 inspector_id: Option<&crate::InspectorElementId>,
7266 cx: &mut App,
7267 f: impl FnOnce(&mut Option<T>, &mut Self) -> R,
7268 ) -> Option<R> {
7269 let inspector_id = inspector_id?;
7270 let inspector = self.inspector.as_ref()?;
7271 if inspector.read(cx).active_element_id() != Some(inspector_id) {
7272 return None;
7273 }
7274 let inspector = inspector.clone();
7275 Some(inspector.update(cx, |inspector, _cx| {
7276 inspector.with_active_element_state(self, f)
7277 }))
7278 }
7279
7280 #[cfg(any(feature = "inspector", debug_assertions))]
7281 pub(crate) fn inspector_enabled(&self) -> bool {
7282 self.inspector.is_some()
7283 }
7284
7285 #[cfg(any(feature = "inspector", debug_assertions))]
7286 pub(crate) fn build_inspector_element_id(
7287 &mut self,
7288 path: crate::InspectorElementPath,
7289 ) -> crate::InspectorElementId {
7290 self.invalidator.debug_assert_paint_or_prepaint();
7291 let path = Rc::new(path);
7292 let next_instance_id = self
7293 .next_frame
7294 .next_inspector_instance_ids
7295 .entry(path.clone())
7296 .or_insert(0);
7297 let instance_id = *next_instance_id;
7298 *next_instance_id += 1;
7299 crate::InspectorElementId { path, instance_id }
7300 }
7301
7302 #[cfg(any(feature = "inspector", debug_assertions))]
7303 fn prepaint_inspector(&mut self, inspector_width: Pixels, cx: &mut App) -> Option<AnyElement> {
7304 if let Some(inspector) = self.inspector.take() {
7305 let mut inspector_element = AnyView::from(inspector.clone()).into_any_element();
7306 inspector_element.prepaint_as_root(
7307 point(self.viewport_size.width - inspector_width, px(0.0)),
7308 size(inspector_width, self.viewport_size.height).into(),
7309 self,
7310 cx,
7311 );
7312 self.inspector = Some(inspector);
7313 Some(inspector_element)
7314 } else {
7315 None
7316 }
7317 }
7318
7319 #[cfg(any(feature = "inspector", debug_assertions))]
7320 fn paint_inspector(&mut self, mut inspector_element: Option<AnyElement>, cx: &mut App) {
7321 if let Some(mut inspector_element) = inspector_element {
7322 inspector_element.paint(self, cx);
7323 };
7324 }
7325
7326 #[cfg(any(feature = "inspector", debug_assertions))]
7329 pub fn insert_inspector_hitbox(
7330 &mut self,
7331 hitbox_id: HitboxId,
7332 inspector_id: Option<&crate::InspectorElementId>,
7333 cx: &App,
7334 ) {
7335 self.invalidator.debug_assert_paint_or_prepaint();
7336 if !self.is_inspector_picking(cx) {
7337 return;
7338 }
7339 if let Some(inspector_id) = inspector_id {
7340 self.next_frame
7341 .inspector_hitboxes
7342 .insert(hitbox_id, inspector_id.clone());
7343 }
7344 }
7345
7346 #[cfg(any(feature = "inspector", debug_assertions))]
7347 fn paint_inspector_hitbox(&mut self, cx: &App) {
7348 if let Some(inspector) = self.inspector.as_ref() {
7349 let inspector = inspector.read(cx);
7350 if let Some((hitbox_id, _)) = self.hovered_inspector_hitbox(inspector, &self.next_frame)
7351 && let Some(hitbox) = self
7352 .next_frame
7353 .hitboxes
7354 .iter()
7355 .find(|hitbox| hitbox.id == hitbox_id)
7356 {
7357 self.paint_quad(crate::fill(hitbox.bounds, crate::rgba(0x61afef4d)));
7358 }
7359 }
7360 }
7361
7362 #[cfg(any(feature = "inspector", debug_assertions))]
7363 fn handle_inspector_mouse_event(&mut self, event: &dyn Any, cx: &mut App) {
7364 let Some(inspector) = self.inspector.clone() else {
7365 return;
7366 };
7367 if event.downcast_ref::<MouseMoveEvent>().is_some() {
7368 inspector.update(cx, |inspector, _cx| {
7369 if let Some((_, inspector_id)) =
7370 self.hovered_inspector_hitbox(inspector, &self.rendered_frame)
7371 {
7372 inspector.hover(inspector_id, self);
7373 }
7374 });
7375 } else if event.downcast_ref::<crate::MouseDownEvent>().is_some() {
7376 inspector.update(cx, |inspector, _cx| {
7377 if let Some((_, inspector_id)) =
7378 self.hovered_inspector_hitbox(inspector, &self.rendered_frame)
7379 {
7380 inspector.select(inspector_id, self);
7381 }
7382 });
7383 } else if let Some(event) = event.downcast_ref::<crate::ScrollWheelEvent>() {
7384 const SCROLL_LINES: f32 = 3.0;
7386 const SCROLL_PIXELS_PER_LAYER: f32 = 36.0;
7387 let delta_y = event
7388 .delta
7389 .pixel_delta(px(SCROLL_PIXELS_PER_LAYER / SCROLL_LINES))
7390 .y;
7391 if let Some(inspector) = self.inspector.clone() {
7392 inspector.update(cx, |inspector, _cx| {
7393 if let Some(depth) = inspector.pick_depth.as_mut() {
7394 *depth += f32::from(delta_y) / SCROLL_PIXELS_PER_LAYER;
7395 let max_depth = self.mouse_hit_test.ids.len() as f32 - 0.5;
7396 if *depth < 0.0 {
7397 *depth = 0.0;
7398 } else if *depth > max_depth {
7399 *depth = max_depth;
7400 }
7401 if let Some((_, inspector_id)) =
7402 self.hovered_inspector_hitbox(inspector, &self.rendered_frame)
7403 {
7404 inspector.set_active_element_id(inspector_id, self);
7405 }
7406 }
7407 });
7408 }
7409 }
7410 }
7411
7412 #[cfg(any(feature = "inspector", debug_assertions))]
7413 fn hovered_inspector_hitbox(
7414 &self,
7415 inspector: &Inspector,
7416 frame: &Frame,
7417 ) -> Option<(HitboxId, crate::InspectorElementId)> {
7418 if let Some(pick_depth) = inspector.pick_depth {
7419 let depth = (pick_depth as i64).try_into().unwrap_or(0);
7420 let max_skipped = self.mouse_hit_test.ids.len().saturating_sub(1);
7421 let skip_count = (depth as usize).min(max_skipped);
7422 for hitbox_id in self.mouse_hit_test.ids.iter().skip(skip_count) {
7423 if let Some(inspector_id) = frame.inspector_hitboxes.get(hitbox_id) {
7424 return Some((*hitbox_id, inspector_id.clone()));
7425 }
7426 }
7427 }
7428 None
7429 }
7430
7431 #[cfg(any(test, feature = "test-support"))]
7434 pub fn set_modifiers(&mut self, modifiers: Modifiers) {
7435 self.modifiers = modifiers;
7436 }
7437
7438 #[cfg(any(test, feature = "test-support"))]
7442 pub fn simulate_mouse_move(&mut self, position: Point<Pixels>, cx: &mut App) {
7443 let event = PlatformInput::MouseMove(MouseMoveEvent {
7444 position,
7445 modifiers: self.modifiers,
7446 pressed_button: None,
7447 });
7448 let _ = self.dispatch_event(event, cx);
7449 }
7450
7451 #[inline(never)]
7452 fn take_element_state(
7453 &mut self,
7454 global_id: &GlobalElementId,
7455 state_type: TypeId,
7456 ) -> ((GlobalElementId, TypeId), Option<ElementStateBox>) {
7457 let key = (global_id.clone(), state_type);
7458 self.next_frame.accessed_element_states.push(key.clone());
7459 let state = self
7460 .next_frame
7461 .element_states
7462 .remove(&key)
7463 .or_else(|| self.rendered_frame.element_states.remove(&key));
7464 (key, state)
7465 }
7466
7467 #[inline(never)]
7468 fn insert_element_state(
7469 &mut self,
7470 key: (GlobalElementId, TypeId),
7471 state: ElementStateBox,
7472 ) -> Option<ElementStateBox> {
7473 self.next_frame.element_states.insert(key, state)
7474 }
7475
7476 #[inline(never)]
7477 fn observe_keyed_state<S: 'static>(state: &Entity<S>, current_view: EntityId, cx: &mut App) {
7478 cx.observe(state, move |_, cx| {
7479 cx.notify(current_view);
7480 })
7481 .detach();
7482 }
7483}
7484
7485slotmap::new_key_type! {
7487 pub struct WindowId;
7489}
7490
7491impl WindowId {
7492 pub fn as_u64(&self) -> u64 {
7494 self.0.as_ffi()
7495 }
7496}
7497
7498impl From<u64> for WindowId {
7499 fn from(value: u64) -> Self {
7500 WindowId(slotmap::KeyData::from_ffi(value))
7501 }
7502}
7503
7504#[derive(Deref, DerefMut)]
7507pub struct WindowHandle<V> {
7508 #[deref]
7509 #[deref_mut]
7510 pub(crate) any_handle: AnyWindowHandle,
7511 state_type: PhantomData<fn(V) -> V>,
7512}
7513
7514impl<V> Debug for WindowHandle<V> {
7515 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
7516 f.debug_struct("WindowHandle")
7517 .field("any_handle", &self.any_handle.id.as_u64())
7518 .finish()
7519 }
7520}
7521
7522impl<V: 'static + Render> WindowHandle<V> {
7523 pub fn new(id: WindowId) -> Self {
7526 WindowHandle {
7527 any_handle: AnyWindowHandle {
7528 id,
7529 state_type: TypeId::of::<V>(),
7530 root_entity_type_name: std::any::type_name::<V>(),
7531 },
7532 state_type: PhantomData,
7533 }
7534 }
7535
7536 #[cfg(any(test, feature = "test-support"))]
7540 pub fn root<C>(&self, cx: &mut C) -> Result<Entity<V>>
7541 where
7542 C: AppContext,
7543 {
7544 cx.update_window(self.any_handle, |root_view, _, _| {
7545 root_view
7546 .downcast::<V>()
7547 .map_err(|_| anyhow!("the type of the window's root view has changed"))
7548 })?
7549 }
7550
7551 pub fn update<C, R>(
7555 &self,
7556 cx: &mut C,
7557 update: impl FnOnce(&mut V, &mut Window, &mut Context<V>) -> R,
7558 ) -> Result<R>
7559 where
7560 C: AppContext,
7561 {
7562 cx.update_window(self.any_handle, |root_view, window, cx| {
7563 let view = root_view
7564 .downcast::<V>()
7565 .map_err(|_| anyhow!("the type of the window's root view has changed"))?;
7566
7567 Ok(view.update(cx, |view, cx| update(view, window, cx)))
7568 })?
7569 }
7570
7571 pub fn read<'a>(&self, cx: &'a App) -> Result<&'a V> {
7575 let x = cx
7576 .windows
7577 .get(self.id)
7578 .and_then(|window| {
7579 window
7580 .as_deref()
7581 .and_then(|window| window.root.clone())
7582 .map(|root_view| root_view.downcast::<V>())
7583 })
7584 .context("window not found")?
7585 .map_err(|_| anyhow!("the type of the window's root view has changed"))?;
7586
7587 Ok(x.read(cx))
7588 }
7589
7590 pub fn read_with<C, R>(&self, cx: &C, read_with: impl FnOnce(&V, &App) -> R) -> Result<R>
7594 where
7595 C: AppContext,
7596 {
7597 cx.read_window(self, |root_view, cx| read_with(root_view.read(cx), cx))
7598 }
7599
7600 pub fn entity<C>(&self, cx: &C) -> Result<Entity<V>>
7604 where
7605 C: AppContext,
7606 {
7607 cx.read_window(self, |root_view, _cx| root_view)
7608 }
7609
7610 pub fn is_active(&self, cx: &mut App) -> Option<bool> {
7615 cx.update_window(self.any_handle, |_, window, _| window.is_window_active())
7616 .ok()
7617 }
7618}
7619
7620impl<V> Copy for WindowHandle<V> {}
7621
7622impl<V> Clone for WindowHandle<V> {
7623 fn clone(&self) -> Self {
7624 *self
7625 }
7626}
7627
7628impl<V> PartialEq for WindowHandle<V> {
7629 fn eq(&self, other: &Self) -> bool {
7630 self.any_handle == other.any_handle
7631 }
7632}
7633
7634impl<V> Eq for WindowHandle<V> {}
7635
7636impl<V> Hash for WindowHandle<V> {
7637 fn hash<H: Hasher>(&self, state: &mut H) {
7638 self.any_handle.hash(state);
7639 }
7640}
7641
7642impl<V: 'static> From<WindowHandle<V>> for AnyWindowHandle {
7643 fn from(val: WindowHandle<V>) -> Self {
7644 val.any_handle
7645 }
7646}
7647
7648#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
7650pub struct AnyWindowHandle {
7651 pub(crate) id: WindowId,
7652 state_type: TypeId,
7653 root_entity_type_name: &'static str,
7654}
7655
7656impl AnyWindowHandle {
7657 pub fn window_id(&self) -> WindowId {
7659 self.id
7660 }
7661
7662 pub fn root_entity_type_name(&self) -> &'static str {
7664 self.root_entity_type_name
7665 }
7666
7667 pub fn downcast<T: 'static>(&self) -> Option<WindowHandle<T>> {
7670 if TypeId::of::<T>() == self.state_type {
7671 Some(WindowHandle {
7672 any_handle: *self,
7673 state_type: PhantomData,
7674 })
7675 } else {
7676 None
7677 }
7678 }
7679
7680 pub fn update<C, R>(
7684 self,
7685 cx: &mut C,
7686 update: impl FnOnce(AnyView, &mut Window, &mut App) -> R,
7687 ) -> Result<R>
7688 where
7689 C: AppContext,
7690 {
7691 cx.update_window(self, update)
7692 }
7693
7694 pub fn read<T, C, R>(self, cx: &C, read: impl FnOnce(Entity<T>, &App) -> R) -> Result<R>
7698 where
7699 C: AppContext,
7700 T: 'static,
7701 {
7702 let view = self
7703 .downcast::<T>()
7704 .context("the type of the window's root view has changed")?;
7705
7706 cx.read_window(&view, read)
7707 }
7708}
7709
7710impl HasWindowHandle for Window {
7711 fn window_handle(&self) -> Result<raw_window_handle::WindowHandle<'_>, HandleError> {
7712 self.platform_window.window_handle()
7713 }
7714}
7715
7716impl HasDisplayHandle for Window {
7717 fn display_handle(
7718 &self,
7719 ) -> std::result::Result<raw_window_handle::DisplayHandle<'_>, HandleError> {
7720 self.platform_window.display_handle()
7721 }
7722}
7723
7724#[derive(Clone, Debug, Eq, PartialEq, Hash)]
7729pub enum ElementId {
7730 View(EntityId),
7732 Integer(u64),
7734 Name(SharedString),
7736 Uuid(Uuid),
7738 FocusHandle(FocusId),
7740 NamedInteger(SharedString, u64),
7742 Path(Arc<std::path::Path>),
7744 CodeLocation(core::panic::Location<'static>),
7746 NamedChild(Arc<ElementId>, SharedString),
7748 OpaqueId([u8; 20]),
7750}
7751
7752impl ElementId {
7753 pub fn named_usize(name: impl Into<SharedString>, integer: usize) -> ElementId {
7755 Self::NamedInteger(name.into(), integer as u64)
7756 }
7757}
7758
7759impl Display for ElementId {
7760 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
7761 match self {
7762 ElementId::View(entity_id) => write!(f, "view-{}", entity_id)?,
7763 ElementId::Integer(ix) => write!(f, "{}", ix)?,
7764 ElementId::Name(name) => write!(f, "{}", name)?,
7765 ElementId::FocusHandle(_) => write!(f, "FocusHandle")?,
7766 ElementId::NamedInteger(s, i) => write!(f, "{}-{}", s, i)?,
7767 ElementId::Uuid(uuid) => write!(f, "{}", uuid)?,
7768 ElementId::Path(path) => write!(f, "{}", path.display())?,
7769 ElementId::CodeLocation(location) => write!(f, "{}", location)?,
7770 ElementId::NamedChild(id, name) => write!(f, "{}-{}", id, name)?,
7771 ElementId::OpaqueId(opaque_id) => write!(f, "{:x?}", opaque_id)?,
7772 }
7773
7774 Ok(())
7775 }
7776}
7777
7778impl TryInto<SharedString> for ElementId {
7779 type Error = anyhow::Error;
7780
7781 fn try_into(self) -> anyhow::Result<SharedString> {
7782 if let ElementId::Name(name) = self {
7783 Ok(name)
7784 } else {
7785 anyhow::bail!("element id is not string")
7786 }
7787 }
7788}
7789
7790impl From<usize> for ElementId {
7791 fn from(id: usize) -> Self {
7792 ElementId::Integer(id as u64)
7793 }
7794}
7795
7796impl From<i32> for ElementId {
7797 fn from(id: i32) -> Self {
7798 Self::Integer(id as u64)
7799 }
7800}
7801
7802impl From<SharedString> for ElementId {
7803 fn from(name: SharedString) -> Self {
7804 ElementId::Name(name)
7805 }
7806}
7807
7808impl From<String> for ElementId {
7809 fn from(name: String) -> Self {
7810 ElementId::Name(name.into())
7811 }
7812}
7813
7814impl From<Arc<str>> for ElementId {
7815 fn from(name: Arc<str>) -> Self {
7816 ElementId::Name(name.into())
7817 }
7818}
7819
7820impl From<Arc<std::path::Path>> for ElementId {
7821 fn from(path: Arc<std::path::Path>) -> Self {
7822 ElementId::Path(path)
7823 }
7824}
7825
7826impl From<&'static str> for ElementId {
7827 fn from(name: &'static str) -> Self {
7828 ElementId::Name(SharedString::new_static(name))
7829 }
7830}
7831
7832impl<'a> From<&'a FocusHandle> for ElementId {
7833 fn from(handle: &'a FocusHandle) -> Self {
7834 ElementId::FocusHandle(handle.id)
7835 }
7836}
7837
7838impl From<(&'static str, EntityId)> for ElementId {
7839 fn from((name, id): (&'static str, EntityId)) -> Self {
7840 ElementId::NamedInteger(SharedString::new_static(name), id.as_u64())
7841 }
7842}
7843
7844impl From<(&'static str, usize)> for ElementId {
7845 fn from((name, id): (&'static str, usize)) -> Self {
7846 ElementId::NamedInteger(SharedString::new_static(name), id as u64)
7847 }
7848}
7849
7850impl From<(SharedString, usize)> for ElementId {
7851 fn from((name, id): (SharedString, usize)) -> Self {
7852 ElementId::NamedInteger(name, id as u64)
7853 }
7854}
7855
7856impl From<(&'static str, u64)> for ElementId {
7857 fn from((name, id): (&'static str, u64)) -> Self {
7858 ElementId::NamedInteger(SharedString::new_static(name), id)
7859 }
7860}
7861
7862impl From<Uuid> for ElementId {
7863 fn from(value: Uuid) -> Self {
7864 Self::Uuid(value)
7865 }
7866}
7867
7868impl From<(&'static str, u32)> for ElementId {
7869 fn from((name, id): (&'static str, u32)) -> Self {
7870 ElementId::NamedInteger(SharedString::new_static(name), u64::from(id))
7871 }
7872}
7873
7874impl<T: Into<SharedString>> From<(ElementId, T)> for ElementId {
7875 fn from((id, name): (ElementId, T)) -> Self {
7876 ElementId::NamedChild(Arc::new(id), name.into())
7877 }
7878}
7879
7880impl From<&'static core::panic::Location<'static>> for ElementId {
7881 fn from(location: &'static core::panic::Location<'static>) -> Self {
7882 ElementId::CodeLocation(*location)
7883 }
7884}
7885
7886impl From<[u8; 20]> for ElementId {
7887 fn from(opaque_id: [u8; 20]) -> Self {
7888 ElementId::OpaqueId(opaque_id)
7889 }
7890}
7891
7892#[derive(Clone)]
7895pub struct PaintQuad {
7896 pub bounds: Bounds<Pixels>,
7898 pub corner_radii: Corners<Pixels>,
7900 pub background: Background,
7902 pub border_widths: Edges<Pixels>,
7904 pub border_color: Hsla,
7906 pub border_style: BorderStyle,
7908}
7909
7910impl PaintQuad {
7911 pub fn corner_radii(self, corner_radii: impl Into<Corners<Pixels>>) -> Self {
7913 PaintQuad {
7914 corner_radii: corner_radii.into(),
7915 ..self
7916 }
7917 }
7918
7919 pub fn border_widths(self, border_widths: impl Into<Edges<Pixels>>) -> Self {
7921 PaintQuad {
7922 border_widths: border_widths.into(),
7923 ..self
7924 }
7925 }
7926
7927 pub fn border_color(self, border_color: impl Into<Hsla>) -> Self {
7929 PaintQuad {
7930 border_color: border_color.into(),
7931 ..self
7932 }
7933 }
7934
7935 pub fn background(self, background: impl Into<Background>) -> Self {
7937 PaintQuad {
7938 background: background.into(),
7939 ..self
7940 }
7941 }
7942}
7943
7944pub fn quad(
7946 bounds: Bounds<Pixels>,
7947 corner_radii: impl Into<Corners<Pixels>>,
7948 background: impl Into<Background>,
7949 border_widths: impl Into<Edges<Pixels>>,
7950 border_color: impl Into<Hsla>,
7951 border_style: BorderStyle,
7952) -> PaintQuad {
7953 PaintQuad {
7954 bounds,
7955 corner_radii: corner_radii.into(),
7956 background: background.into(),
7957 border_widths: border_widths.into(),
7958 border_color: border_color.into(),
7959 border_style,
7960 }
7961}
7962
7963pub fn fill(bounds: impl Into<Bounds<Pixels>>, background: impl Into<Background>) -> PaintQuad {
7965 PaintQuad {
7966 bounds: bounds.into(),
7967 corner_radii: (0.).into(),
7968 background: background.into(),
7969 border_widths: (0.).into(),
7970 border_color: transparent_black(),
7971 border_style: BorderStyle::default(),
7972 }
7973}
7974
7975pub fn outline(
7977 bounds: impl Into<Bounds<Pixels>>,
7978 border_color: impl Into<Hsla>,
7979 border_style: BorderStyle,
7980) -> PaintQuad {
7981 PaintQuad {
7982 bounds: bounds.into(),
7983 corner_radii: (0.).into(),
7984 background: transparent_black().into(),
7985 border_widths: (1.).into(),
7986 border_color: border_color.into(),
7987 border_style,
7988 }
7989}
7990
7991#[inline(never)]
7992fn with_element_arena_erased(callback: &mut dyn FnMut(&mut Arena)) -> Result<(), AccessError> {
7993 if let Some(arena_pointer) = CURRENT_ELEMENT_ARENA.try_with(Cell::get)? {
7994 let arena_cell = unsafe { &*arena_pointer };
7997 callback(&mut arena_cell.borrow_mut());
7998 Ok(())
7999 } else {
8000 ELEMENT_ARENA.try_with(|arena| callback(&mut arena.borrow_mut()))
8001 }
8002}
8003
8004#[cfg(test)]
8005mod tests {
8006 use std::{
8007 cell::{Cell, RefCell},
8008 path::PathBuf,
8009 rc::Rc,
8010 time::Duration,
8011 };
8012
8013 use crate::{
8014 AnyWindowHandle, AppContext as _, Bounds, ContentMask, Context, DispatchPhase,
8015 DragMoveEvent, Empty, ExternalDragPayload, ExternalPaths, FileDragPaths, FileDropEvent,
8016 FocusHandle, InputEvent as _, InteractiveElement as _, IntoElement, KeyDownEvent,
8017 Keystroke, LongPressEvent, MouseButton, MouseDownEvent, MouseMoveEvent, ParentElement,
8018 Pixels, PlatformInput, Point, Render, RequestFrameOptions, ScaledPixels,
8019 StatefulInteractiveElement as _, Styled, TestAppContext, TouchDragEvent, TouchEvent,
8020 TouchId, TouchPhase, Underline, UnderlineStyle, Window, WindowAppearance, WindowOptions,
8021 canvas, div, hsla, point, px, size,
8022 };
8023
8024 #[gpui::test]
8028 fn test_window_visibility(cx: &mut TestAppContext) {
8029 use crate::WindowVisibility;
8030
8031 let window = cx.add_window(|_, _| EmptyView);
8032 let observed = Rc::new(RefCell::new(Vec::new()));
8033 let _subscription = window
8034 .update(cx, {
8035 let observed = observed.clone();
8036 move |_, window, _| {
8037 assert_eq!(window.visibility(), WindowVisibility::Visible);
8038 assert!(window.is_visible());
8039 window.observe_window_visibility(move |visibility, window, _| {
8040 assert_eq!(window.visibility(), visibility);
8041 observed.borrow_mut().push(visibility);
8042 })
8043 }
8044 })
8045 .unwrap();
8046 let test_window = cx.test_window(window.into());
8047 let frame_wake_count = test_window.frame_wake_count();
8048
8049 test_window.simulate_visibility_change(WindowVisibility::Hidden);
8050 assert_eq!(*observed.borrow(), [WindowVisibility::Hidden]);
8051 window
8052 .update(cx, |_, window, _| assert!(!window.is_visible()))
8053 .unwrap();
8054
8055 test_window.simulate_visibility_change(WindowVisibility::Hidden);
8057 assert_eq!(observed.borrow().len(), 1);
8058
8059 test_window.simulate_visibility_change(WindowVisibility::Visible);
8060 assert_eq!(
8061 *observed.borrow(),
8062 [WindowVisibility::Hidden, WindowVisibility::Visible]
8063 );
8064 window
8065 .update(cx, |_, window, _| assert!(window.is_visible()))
8066 .unwrap();
8067 assert_eq!(test_window.frame_wake_count(), frame_wake_count);
8068 }
8069
8070 #[gpui::test]
8071 fn test_fully_visible_bounds_preserve_layout_viewport(cx: &mut TestAppContext) {
8072 let window = cx.add_window(|_, _| EmptyView);
8073 let mut platform_window = cx.test_window(window.into());
8074 platform_window.simulate_resize(size(px(400.), px(800.)));
8075 window
8076 .update(cx, |_, window, _| {
8077 assert_eq!(
8078 window.visual_viewport_bounds(),
8079 Bounds::new(Point::default(), size(px(400.), px(800.)))
8080 );
8081 assert_eq!(
8082 window.fully_visible_bounds(),
8083 window.visual_viewport_bounds()
8084 );
8085 })
8086 .unwrap();
8087
8088 platform_window.simulate_frame_request(RequestFrameOptions::default());
8089 let wakes = platform_window.frame_wake_count();
8090 let visual_bounds = Bounds::new(point(px(10.), px(40.)), size(px(380.), px(460.)));
8091 platform_window.simulate_visual_viewport_change(visual_bounds);
8092 assert!(platform_window.frame_wake_count() > wakes);
8093 platform_window.simulate_frame_request(RequestFrameOptions::default());
8094 let wakes = platform_window.frame_wake_count();
8095 platform_window.simulate_insets_change(crate::WindowInsets {
8096 safe_area: crate::Edges {
8097 top: px(60.),
8098 right: px(20.),
8099 bottom: px(30.),
8100 left: px(-10.),
8101 },
8102 ime: crate::Edges {
8103 bottom: px(350.),
8104 ..Default::default()
8105 },
8106 });
8107 assert!(platform_window.frame_wake_count() > wakes);
8108 window
8109 .update(cx, |_, window, _| {
8110 assert_eq!(window.viewport_size(), size(px(400.), px(800.)));
8111 assert_eq!(window.visual_viewport_bounds(), visual_bounds);
8112 assert_eq!(
8113 window.fully_visible_bounds(),
8114 Bounds::new(point(px(10.), px(60.)), size(px(370.), px(390.)))
8115 );
8116 window.request_virtual_keyboard();
8117 window.dismiss_virtual_keyboard();
8118 assert_eq!(window.viewport_size(), size(px(400.), px(800.)));
8119 })
8120 .unwrap();
8121 assert_eq!(platform_window.virtual_keyboard_requests(), 1);
8122 assert_eq!(platform_window.virtual_keyboard_dismissals(), 1);
8123
8124 platform_window.simulate_insets_change(crate::WindowInsets {
8125 safe_area: crate::Edges {
8126 top: px(900.),
8127 left: px(500.),
8128 ..Default::default()
8129 },
8130 ..Default::default()
8131 });
8132 window
8133 .update(cx, |_, window, _| {
8134 assert_eq!(
8135 window.fully_visible_bounds().size,
8136 size(Pixels::ZERO, Pixels::ZERO)
8137 );
8138 })
8139 .unwrap();
8140 }
8141
8142 struct EmptyView;
8143
8144 impl Render for EmptyView {
8145 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
8146 div()
8147 }
8148 }
8149
8150 struct OpensWindowOnPaint {
8151 opened: Rc<Cell<bool>>,
8152 }
8153
8154 impl Render for OpensWindowOnPaint {
8155 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
8156 let opened = self.opened.clone();
8157 div()
8158 .size_full()
8159 .child(canvas(
8160 |_, _, _| {},
8161 move |_, _, _window, cx| {
8162 if !opened.replace(true) {
8163 cx.open_window(WindowOptions::default(), |_, cx| cx.new(|_| EmptyView))
8164 .unwrap();
8165 }
8166 },
8167 ))
8168 .child(div().child("after"))
8172 }
8173 }
8174
8175 #[test]
8181 fn test_window_opened_during_draw_defers_arena_clear() {
8182 let mut cx = TestAppContext::single();
8183
8184 let opened = Rc::new(Cell::new(false));
8185 let window = cx.add_window({
8187 let opened = opened.clone();
8188 move |_, _| OpensWindowOnPaint { opened }
8189 });
8190
8191 assert!(opened.get());
8192 assert_eq!(cx.windows().len(), 2);
8193
8194 cx.update_window(window.into(), |_, window, cx| window.draw(cx).clear(cx))
8197 .unwrap();
8198 }
8199
8200 #[test]
8201 fn test_scale_factor_change_preserves_bounds_and_survives_resize() {
8202 let mut cx = TestAppContext::single();
8203 let window = cx.add_window(|_, _| EmptyView);
8204 let handle: AnyWindowHandle = window.into();
8205 let window_state = |cx: &mut TestAppContext| {
8206 cx.update_window(handle, |_, window, _| {
8207 (
8208 window.scale_factor(),
8209 window.bounds(),
8210 window.viewport_size(),
8211 )
8212 })
8213 .unwrap()
8214 };
8215
8216 let (scale_factor, mut expected_bounds, _) = window_state(&mut cx);
8217 assert_eq!(scale_factor, 2.0);
8218
8219 for (scale_factor, resized_size) in [
8220 (1.0, size(px(800.), px(600.))),
8221 (1.25, size(px(640.), px(480.))),
8222 (2.0, size(px(1024.), px(768.))),
8223 ] {
8224 cx.simulate_window_scale_factor_change(handle, scale_factor);
8225 assert_eq!(
8226 window_state(&mut cx),
8227 (scale_factor, expected_bounds, expected_bounds.size)
8228 );
8229
8230 cx.simulate_window_resize(handle, resized_size);
8231 expected_bounds.size = resized_size;
8232 assert_eq!(
8233 window_state(&mut cx),
8234 (scale_factor, expected_bounds, resized_size)
8235 );
8236 }
8237 }
8238
8239 #[gpui::test]
8244 fn test_frame_waker_fires_on_frame_demand(cx: &mut TestAppContext) {
8245 let window = cx.add_window(|_, _| EmptyView);
8246 let test_window = cx.test_window(window.into());
8247
8248 assert!(
8252 test_window.frame_wake_count() >= 1,
8253 "opening a window must wake the frame source for the initial frame"
8254 );
8255
8256 test_window.simulate_frame_request(RequestFrameOptions::default());
8258
8259 let baseline = test_window.frame_wake_count();
8262 test_window.simulate_frame_request(RequestFrameOptions::default());
8263 window.update(cx, |_, _, _| {}).unwrap();
8264 assert_eq!(
8265 test_window.frame_wake_count(),
8266 baseline,
8267 "clean frames and non-notifying updates must not wake the frame source"
8268 );
8269
8270 window.update(cx, |_, _, cx| cx.notify()).unwrap();
8272 assert!(
8273 test_window.frame_wake_count() > baseline,
8274 "notifying a view in an idle window must wake the frame source"
8275 );
8276
8277 test_window.simulate_frame_request(RequestFrameOptions::default());
8279 let baseline = test_window.frame_wake_count();
8280 test_window.simulate_frame_request(RequestFrameOptions::default());
8281 assert_eq!(
8282 test_window.frame_wake_count(),
8283 baseline,
8284 "serving demand must return the window to idle"
8285 );
8286
8287 window
8289 .update(cx, |_, window, _| window.on_next_frame(|_, _| {}))
8290 .unwrap();
8291 assert!(
8292 test_window.frame_wake_count() > baseline,
8293 "scheduling a next-frame callback in an idle window must wake the frame source"
8294 );
8295 }
8296
8297 #[gpui::test]
8302 fn test_pending_next_frame_callbacks_are_not_stranded(cx: &mut TestAppContext) {
8303 let window = cx.add_window(|_, _| EmptyView);
8304 let test_window = cx.test_window(window.into());
8305 test_window.simulate_frame_request(RequestFrameOptions::default());
8308
8309 let callback_ran = Rc::new(Cell::new(false));
8310 window
8311 .update(cx, {
8312 let callback_ran = callback_ran.clone();
8313 move |_, window, _| {
8314 window.on_next_frame(move |_, _| callback_ran.set(true));
8315 }
8316 })
8317 .unwrap();
8318
8319 let baseline = test_window.frame_wake_count();
8320 test_window.simulate_frame_request(RequestFrameOptions::default());
8321 assert!(
8328 test_window.frame_wake_count() > baseline || callback_ran.get(),
8329 "a frame request with pending next-frame callbacks must either run them or re-arm the frame source"
8330 );
8331 }
8332
8333 #[gpui::test]
8334 fn test_window_reports_no_raw_handle_instead_of_panicking(cx: &mut TestAppContext) {
8335 use raw_window_handle::{HandleError, HasDisplayHandle as _, HasWindowHandle as _};
8336
8337 let window = cx.add_window(|_, _| EmptyView);
8338 window
8339 .update(cx, |_, window, _| {
8340 assert!(matches!(
8341 window.window_handle(),
8342 Err(HandleError::NotSupported)
8343 ));
8344 assert!(matches!(
8345 window.display_handle(),
8346 Err(HandleError::NotSupported)
8347 ));
8348 })
8349 .unwrap();
8350 }
8351
8352 #[gpui::test]
8353 fn test_appearance_change_runs_after_app_update(cx: &mut TestAppContext) {
8354 let window = cx.add_window(|_, _| EmptyView);
8355 let observed_appearance = Rc::new(Cell::new(None));
8356 let _subscription = window
8357 .update(cx, {
8358 let observed_appearance = observed_appearance.clone();
8359 move |_, window, _| {
8360 window.observe_window_appearance(move |window, _| {
8361 observed_appearance.set(Some(window.appearance()));
8362 })
8363 }
8364 })
8365 .unwrap();
8366 let test_window = cx.test_window(window.into());
8367
8368 cx.update(|_| {
8369 test_window.simulate_appearance_change(WindowAppearance::Dark);
8370 assert_eq!(observed_appearance.get(), None);
8371 });
8372 cx.run_until_parked();
8373
8374 assert_eq!(observed_appearance.get(), Some(WindowAppearance::Dark));
8375 }
8376
8377 #[gpui::test]
8378 fn queued_frame_callback_wakes_a_parked_render_loop(cx: &mut TestAppContext) {
8379 let window = cx.add_window(|_, _| Empty);
8380 let test_window = cx.test_window(window.into());
8381
8382 assert!(test_window.simulate_scheduled_frame());
8383 assert!(test_window.simulate_scheduled_frame());
8384 assert!(!test_window.frame_scheduled());
8385
8386 cx.update_window(window.into(), |_, window, _| {
8387 window.active.set(true);
8388 window.on_next_frame(|_, _| {});
8389 })
8390 .unwrap();
8391 assert!(
8392 test_window.frame_scheduled(),
8393 "queuing work on a parked window must wake the render loop"
8394 );
8395
8396 assert!(test_window.simulate_scheduled_frame());
8397 assert!(
8398 test_window.frame_scheduled(),
8399 "presenting the frame must await one compositor callback"
8400 );
8401 assert!(test_window.simulate_scheduled_frame());
8402 assert!(!test_window.frame_scheduled());
8403 }
8404
8405 #[gpui::test]
8406 fn pending_presentation_wakes_a_parked_render_loop(cx: &mut TestAppContext) {
8407 let window = cx.add_window(|_, _| Empty);
8408 let test_window = cx.test_window(window.into());
8409
8410 assert!(test_window.simulate_scheduled_frame());
8411 assert!(test_window.simulate_scheduled_frame());
8412 assert!(!test_window.frame_scheduled());
8413
8414 cx.update_window(window.into(), |_, window, cx| window.draw(cx).clear(cx))
8415 .unwrap();
8416
8417 assert!(
8418 test_window.frame_scheduled(),
8419 "a rendered scene awaiting presentation must wake the render loop"
8420 );
8421 }
8422
8423 #[gpui::test]
8424 fn callback_queued_during_a_frame_requests_a_follow_up(cx: &mut TestAppContext) {
8425 let window = cx.add_window(|_, _| Empty);
8426 let test_window = cx.test_window(window.into());
8427
8428 let callback_ran = Rc::new(Cell::new(false));
8429 cx.update_window(window.into(), |_, window, _| {
8430 window.active.set(true);
8433 let callback_ran = callback_ran.clone();
8434 window.on_next_frame(move |window, _| {
8435 window.on_next_frame(move |_, _| callback_ran.set(true));
8436 });
8437 })
8438 .unwrap();
8439
8440 assert!(test_window.simulate_scheduled_frame());
8441 assert!(!callback_ran.get());
8442 assert!(
8443 test_window.frame_scheduled(),
8444 "a callback queued mid-frame must schedule a follow-up before the loop parks"
8445 );
8446
8447 assert!(test_window.simulate_scheduled_frame());
8448 assert!(callback_ran.get());
8449 }
8450
8451 struct RootView {
8452 explicit_size: bool,
8453 child_bounds: Rc<Cell<Bounds<Pixels>>>,
8454 }
8455
8456 impl Render for RootView {
8457 fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
8458 let child_bounds = self.child_bounds.clone();
8459 let root = div().flex().flex_col().child(
8460 canvas(
8461 move |bounds, _, _| child_bounds.set(bounds),
8462 |_, _, _, _| {},
8463 )
8464 .size_full(),
8465 );
8466 if self.explicit_size {
8467 root.w(px(300.)).h(px(200.))
8468 } else {
8469 root
8470 }
8471 }
8472 }
8473
8474 #[test]
8475 fn auto_sized_window_root_fills_the_window() {
8476 let mut cx = TestAppContext::single();
8477 let child_bounds = Rc::new(Cell::new(Bounds::default()));
8478 let window = cx.add_window({
8479 let child_bounds = child_bounds.clone();
8480 move |_, _| RootView {
8481 explicit_size: false,
8482 child_bounds,
8483 }
8484 });
8485
8486 let viewport_size = cx
8487 .update_window(window.into(), |_, window, cx| {
8488 window.draw(cx).clear(cx);
8489 window.viewport_size()
8490 })
8491 .unwrap();
8492
8493 assert_eq!(child_bounds.get().size, viewport_size);
8494 }
8495
8496 #[test]
8497 fn explicitly_sized_window_root_keeps_its_size() {
8498 let mut cx = TestAppContext::single();
8499 let child_bounds = Rc::new(Cell::new(Bounds::default()));
8500 let window = cx.add_window({
8501 let child_bounds = child_bounds.clone();
8502 move |_, _| RootView {
8503 explicit_size: true,
8504 child_bounds,
8505 }
8506 });
8507
8508 cx.update_window(window.into(), |_, window, cx| {
8509 window.draw(cx).clear(cx);
8510 })
8511 .unwrap();
8512
8513 assert_eq!(child_bounds.get().size, size(px(300.), px(200.)));
8514 }
8515
8516 struct FileDragView {
8517 path: PathBuf,
8518 observed_drag_moves: Rc<RefCell<Vec<Point<Pixels>>>>,
8519 observed_drops: Rc<RefCell<Vec<PathBuf>>>,
8520 }
8521
8522 struct FileDropExitView(Rc<Cell<usize>>);
8523
8524 impl Render for FileDropExitView {
8525 fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
8526 div().size_full().on_file_drop_exit({
8527 let observed_file_drop_exit = self.0.clone();
8528 move |_, _, _| observed_file_drop_exit.set(observed_file_drop_exit.get() + 1)
8529 })
8530 }
8531 }
8532
8533 impl Render for FileDragView {
8534 fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
8535 div()
8536 .id("file-drag")
8537 .size_full()
8538 .on_drag(self.path.clone(), |_, _, _, cx| cx.new(|_| Empty))
8539 .external_drag_payload(|path: &PathBuf, _, _| {
8540 Some(ExternalDragPayload::Files(FileDragPaths::new([(
8541 path.clone(),
8542 true,
8543 )])))
8544 })
8545 .on_drag_move({
8546 let observed_drag_moves = self.observed_drag_moves.clone();
8547 move |event: &DragMoveEvent<PathBuf>, _, _| {
8548 observed_drag_moves.borrow_mut().push(event.event.position);
8549 }
8550 })
8551 .on_drop({
8552 let observed_drops = self.observed_drops.clone();
8553 move |path: &PathBuf, _, _| observed_drops.borrow_mut().push(path.clone())
8554 })
8555 }
8556 }
8557
8558 #[gpui::test]
8559 fn file_drag_is_promoted_once_and_restored_in_source_window(cx: &mut TestAppContext) {
8560 struct Drag {
8561 window: AnyWindowHandle,
8562 observed_drag_moves: Rc<RefCell<Vec<Point<Pixels>>>>,
8563 observed_drops: Rc<RefCell<Vec<PathBuf>>>,
8564 }
8565
8566 fn start_drag(cx: &mut TestAppContext, path: PathBuf, platform_result: bool) -> Drag {
8567 let observed_drag_moves = Rc::new(RefCell::new(Vec::new()));
8568 let observed_drops = Rc::new(RefCell::new(Vec::new()));
8569 let window: AnyWindowHandle = cx
8570 .add_window({
8571 let observed_drag_moves = observed_drag_moves.clone();
8572 let observed_drops = observed_drops.clone();
8573 move |_, _| FileDragView {
8574 path,
8575 observed_drag_moves,
8576 observed_drops,
8577 }
8578 })
8579 .into();
8580 cx.test_window(window)
8581 .set_start_external_drag_result(platform_result);
8582
8583 let update_result = cx.update_window(window, |_, window, cx| {
8584 window.draw(cx).clear(cx);
8585 window.dispatch_event(
8586 MouseDownEvent {
8587 position: point(px(10.), px(10.)),
8588 button: MouseButton::Left,
8589 modifiers: Default::default(),
8590 click_count: 1,
8591 first_mouse: false,
8592 }
8593 .to_platform_input(),
8594 cx,
8595 );
8596 window.dispatch_event(
8597 MouseMoveEvent {
8598 position: point(px(20.), px(20.)),
8599 pressed_button: Some(MouseButton::Left),
8600 modifiers: Default::default(),
8601 }
8602 .to_platform_input(),
8603 cx,
8604 );
8605 assert!(cx.active_drag.is_some());
8606 });
8607 assert!(
8608 update_result.is_ok(),
8609 "failed to start drag: {update_result:?}"
8610 );
8611
8612 assert!(cx.test_window(window).external_drag_files().is_empty());
8613 Drag {
8614 window,
8615 observed_drag_moves,
8616 observed_drops,
8617 }
8618 }
8619
8620 let successful_path = PathBuf::from("/tmp/successful-drag");
8621 let successful = start_drag(cx, successful_path.clone(), true);
8622 let outside_position = point(px(-1.), px(20.));
8623 let update_result = cx.update_window(successful.window, |_, window, cx| {
8624 window.dispatch_event(
8625 MouseMoveEvent {
8626 position: outside_position,
8627 pressed_button: Some(MouseButton::Left),
8628 modifiers: Default::default(),
8629 }
8630 .to_platform_input(),
8631 cx,
8632 );
8633 assert!(cx.active_drag.is_none());
8634 });
8635 assert!(
8636 update_result.is_ok(),
8637 "failed to promote drag: {update_result:?}"
8638 );
8639 assert_eq!(
8640 cx.test_window(successful.window).external_drag_files(),
8641 [(successful_path.clone(), true)]
8642 );
8643 assert_eq!(
8646 successful.observed_drag_moves.borrow().last(),
8647 Some(&outside_position)
8648 );
8649
8650 let first_destination_exit_count = Rc::new(Cell::new(0));
8651 let first_destination: AnyWindowHandle = cx
8652 .add_window({
8653 let first_destination_exit_count = first_destination_exit_count.clone();
8654 move |_, _| FileDropExitView(first_destination_exit_count)
8655 })
8656 .into();
8657 let second_destination_exit_count = Rc::new(Cell::new(0));
8658 let second_destination: AnyWindowHandle = cx
8659 .add_window({
8660 let second_destination_exit_count = second_destination_exit_count.clone();
8661 move |_, _| FileDropExitView(second_destination_exit_count)
8662 })
8663 .into();
8664 let reentry_position = point(px(30.), px(30.));
8665 let external_paths = || ExternalPaths([successful_path.clone()].into_iter().collect());
8666 let update_result = cx.update_window(first_destination, |_, window, cx| {
8667 window.draw(cx).clear(cx);
8668 window.dispatch_event(
8669 FileDropEvent::Entered {
8670 position: reentry_position,
8671 paths: external_paths(),
8672 }
8673 .to_platform_input(),
8674 cx,
8675 );
8676 assert!(
8677 cx.active_drag
8678 .as_ref()
8679 .is_some_and(|drag| drag.value.downcast_ref::<ExternalPaths>().is_some())
8680 );
8681 window.dispatch_event(FileDropEvent::Exited.to_platform_input(), cx);
8682 assert!(cx.active_drag.is_none());
8683 assert_eq!(first_destination_exit_count.get(), 1);
8684 assert_eq!(second_destination_exit_count.get(), 0);
8685 });
8686 assert!(
8687 update_result.is_ok(),
8688 "failed to handle drag in first destination window: {update_result:?}"
8689 );
8690
8691 let update_result = cx.update_window(second_destination, |_, window, cx| {
8692 window.draw(cx).clear(cx);
8693 window.dispatch_event(
8694 PlatformInput::KeyDown(KeyDownEvent {
8695 keystroke: Keystroke::parse("down").expect("valid keystroke"),
8696 is_held: false,
8697 prefer_character_input: false,
8698 layout: None,
8699 }),
8700 cx,
8701 );
8702 window.dispatch_event(
8703 FileDropEvent::Entered {
8704 position: reentry_position,
8705 paths: external_paths(),
8706 }
8707 .to_platform_input(),
8708 cx,
8709 );
8710 assert!(
8711 cx.active_drag
8712 .as_ref()
8713 .is_some_and(|drag| drag.value.downcast_ref::<ExternalPaths>().is_some())
8714 );
8715 assert_eq!(first_destination_exit_count.get(), 1);
8716 assert_eq!(second_destination_exit_count.get(), 0);
8717
8718 window.dispatch_event(FileDropEvent::Exited.to_platform_input(), cx);
8719 assert!(cx.active_drag.is_none());
8720 assert_eq!(first_destination_exit_count.get(), 1);
8721 assert_eq!(second_destination_exit_count.get(), 1);
8722 });
8723 assert!(
8724 update_result.is_ok(),
8725 "failed to handle drag in second destination window: {update_result:?}"
8726 );
8727
8728 let update_result = cx.update_window(successful.window, |_, window, cx| {
8729 window.dispatch_event(
8730 FileDropEvent::Entered {
8731 position: reentry_position,
8732 paths: external_paths(),
8733 }
8734 .to_platform_input(),
8735 cx,
8736 );
8737 assert!(
8738 cx.active_drag
8739 .as_ref()
8740 .is_some_and(|drag| drag.value.downcast_ref::<PathBuf>().is_some())
8741 );
8742 assert_eq!(
8743 successful.observed_drag_moves.borrow().last(),
8744 Some(&reentry_position)
8745 );
8746
8747 window.dispatch_event(FileDropEvent::Exited.to_platform_input(), cx);
8748 assert!(cx.active_drag.is_none());
8749
8750 window.dispatch_event(
8751 FileDropEvent::Entered {
8752 position: reentry_position,
8753 paths: external_paths(),
8754 }
8755 .to_platform_input(),
8756 cx,
8757 );
8758 assert!(
8759 cx.active_drag
8760 .as_ref()
8761 .is_some_and(|drag| drag.value.downcast_ref::<PathBuf>().is_some())
8762 );
8763
8764 window.dispatch_event(
8765 FileDropEvent::Submit {
8766 position: reentry_position,
8767 }
8768 .to_platform_input(),
8769 cx,
8770 );
8771 assert_eq!(
8772 successful.observed_drops.borrow().as_slice(),
8773 std::slice::from_ref(&successful_path)
8774 );
8775 assert!(cx.active_drag.is_none());
8776
8777 window.dispatch_event(FileDropEvent::Exited.to_platform_input(), cx);
8778 assert!(cx.active_drag.is_none());
8779 window.dispatch_event(FileDropEvent::Ended.to_platform_input(), cx);
8780 assert!(cx.active_drag.is_none());
8781
8782 window.dispatch_event(
8783 FileDropEvent::Entered {
8784 position: reentry_position,
8785 paths: external_paths(),
8786 }
8787 .to_platform_input(),
8788 cx,
8789 );
8790 assert!(
8791 cx.active_drag
8792 .as_ref()
8793 .is_some_and(|drag| drag.value.downcast_ref::<ExternalPaths>().is_some())
8794 );
8795 window.dispatch_event(FileDropEvent::Exited.to_platform_input(), cx);
8796 });
8797 assert!(
8798 update_result.is_ok(),
8799 "failed to restore drag in source window: {update_result:?}"
8800 );
8801
8802 let cancelled_path = PathBuf::from("/tmp/cancelled-drag");
8803 let cancelled = start_drag(cx, cancelled_path.clone(), true);
8804 let update_result = cx.update_window(cancelled.window, |_, window, cx| {
8805 window.dispatch_event(
8806 MouseMoveEvent {
8807 position: outside_position,
8808 pressed_button: Some(MouseButton::Left),
8809 modifiers: Default::default(),
8810 }
8811 .to_platform_input(),
8812 cx,
8813 );
8814 assert!(cx.active_drag.is_none());
8815
8816 window.dispatch_event(
8817 FileDropEvent::Entered {
8818 position: reentry_position,
8819 paths: ExternalPaths([cancelled_path].into_iter().collect()),
8820 }
8821 .to_platform_input(),
8822 cx,
8823 );
8824 assert!(
8825 cx.active_drag
8826 .as_ref()
8827 .is_some_and(|drag| drag.value.downcast_ref::<PathBuf>().is_some())
8828 );
8829 assert!(cx.stop_active_drag(window));
8830 assert!(cx.active_drag.is_none());
8831 });
8832 assert!(
8833 update_result.is_ok(),
8834 "failed to cancel restored drag: {update_result:?}"
8835 );
8836 assert!(!cx.update(|cx| cx.end_platform_drag(cancelled.window.window_id())));
8837
8838 let removed_path = PathBuf::from("/tmp/removed-window-drag");
8839 let removed = start_drag(cx, removed_path, true);
8840 let removed_window_id = removed.window.window_id();
8841 let update_result = cx.update_window(removed.window, |_, window, cx| {
8842 window.dispatch_event(
8843 MouseMoveEvent {
8844 position: outside_position,
8845 pressed_button: Some(MouseButton::Left),
8846 modifiers: Default::default(),
8847 }
8848 .to_platform_input(),
8849 cx,
8850 );
8851 assert!(cx.active_drag.is_none());
8852 window.remove_window();
8853 });
8854 assert!(
8855 update_result.is_ok(),
8856 "failed to remove drag source window: {update_result:?}"
8857 );
8858 assert!(!cx.update(|cx| cx.end_platform_drag(removed_window_id)));
8859
8860 let failed_path = PathBuf::from("/tmp/failed-drag");
8861 let failed = start_drag(cx, failed_path.clone(), false);
8862 let update_result = cx.update_window(failed.window, |_, window, cx| {
8863 for x_position in [-1., -2.] {
8864 window.dispatch_event(
8865 MouseMoveEvent {
8866 position: point(px(x_position), px(20.)),
8867 pressed_button: Some(MouseButton::Left),
8868 modifiers: Default::default(),
8869 }
8870 .to_platform_input(),
8871 cx,
8872 );
8873 }
8874 assert!(cx.active_drag.is_some());
8875 });
8876 assert!(
8877 update_result.is_ok(),
8878 "failed to retain drag after platform failure: {update_result:?}"
8879 );
8880 assert_eq!(
8881 cx.test_window(failed.window).external_drag_files(),
8882 [(failed_path, true)]
8883 );
8884 }
8885
8886 struct FocusForwarder {
8887 a: FocusHandle,
8888 b: FocusHandle,
8889 }
8890
8891 impl Render for FocusForwarder {
8892 fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
8893 div()
8894 .size_full()
8895 .child(div().w(px(50.)).h(px(50.)).track_focus(&self.a))
8896 .child(div().w(px(50.)).h(px(50.)).track_focus(&self.b))
8897 }
8898 }
8899
8900 #[gpui::test]
8904 fn test_focus_moved_by_focus_listener_is_dispatched(cx: &mut TestAppContext) {
8905 let b_focus_count = Rc::new(Cell::new(0));
8906 let window = cx.add_window({
8907 let b_focus_count = b_focus_count.clone();
8908 move |window, cx| {
8909 let a = cx.focus_handle();
8910 let b = cx.focus_handle();
8911 cx.on_focus(&a, window, |this: &mut FocusForwarder, window, cx| {
8912 let b = this.b.clone();
8913 window.focus(&b, cx);
8914 })
8915 .detach();
8916 cx.on_focus(&b, window, move |_, _, _| {
8917 b_focus_count.set(b_focus_count.get() + 1);
8918 })
8919 .detach();
8920 FocusForwarder { a, b }
8921 }
8922 });
8923
8924 window
8925 .update(cx, |_, window, _| window.activate_window())
8926 .unwrap();
8927 cx.executor().run_until_parked();
8928
8929 window
8930 .update(cx, |this, window, cx| {
8931 let a = this.a.clone();
8932 window.focus(&a, cx);
8933 })
8934 .unwrap();
8935 cx.executor().run_until_parked();
8936
8937 window
8938 .update(cx, |this, window, _| {
8939 assert!(this.b.is_focused(window));
8940 })
8941 .unwrap();
8942 assert_eq!(b_focus_count.get(), 1);
8943 }
8944
8945 #[gpui::test]
8946 fn claimed_touch_drag_receives_movement_and_release(cx: &mut TestAppContext) {
8947 let events = Rc::new(RefCell::new(Vec::new()));
8948 let window = cx.add_window({
8949 let events = events.clone();
8950 move |_, _| TouchDragListener { events }
8951 });
8952 let touch = TouchId(1);
8953
8954 dispatch_touch(window, cx, touch, TouchPhase::Started, 10.);
8955 dispatch_touch(window, cx, touch, TouchPhase::Moved, 30.);
8956 dispatch_touch(window, cx, touch, TouchPhase::Ended, 40.);
8957
8958 assert_eq!(
8959 events.borrow().as_slice(),
8960 [
8961 (TouchPhase::Started, px(10.)),
8962 (TouchPhase::Moved, px(30.)),
8963 (TouchPhase::Ended, px(40.)),
8964 ]
8965 );
8966 }
8967
8968 struct TouchDragListener {
8969 events: Rc<RefCell<Vec<(TouchPhase, Pixels)>>>,
8970 }
8971
8972 impl Render for TouchDragListener {
8973 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
8974 let events = self.events.clone();
8975 canvas(
8976 |_, _, _| {},
8977 move |_, _, window, _| {
8978 window.on_mouse_event(move |event: &TouchDragEvent, phase, window, _cx| {
8979 if phase != DispatchPhase::Bubble {
8980 return;
8981 }
8982 events.borrow_mut().push((event.phase, event.position.x));
8983 if event.phase == TouchPhase::Started {
8984 window.prevent_default();
8985 }
8986 });
8987 },
8988 )
8989 }
8990 }
8991
8992 #[gpui::test]
8993 fn long_press_is_claimed_only_when_started_prevents_default(cx: &mut TestAppContext) {
8994 for response in [
8995 LongPressResponse::PreventDefault,
8996 LongPressResponse::StopPropagation,
8997 LongPressResponse::None,
8998 ] {
8999 let phases = Rc::new(RefCell::new(Vec::new()));
9000 let window = cx.add_window({
9001 let phases = phases.clone();
9002 move |_, _| LongPressListener { phases, response }
9003 });
9004 dispatch_touch(window, cx, TouchId(1), TouchPhase::Started, 0.);
9005 cx.executor().advance_clock(Duration::from_millis(501));
9006 cx.executor().run_until_parked();
9007 window
9008 .update(cx, |_, window, _| {
9009 assert_eq!(
9010 window.long_press_capture.is_some(),
9011 response == LongPressResponse::PreventDefault
9012 );
9013 })
9014 .unwrap();
9015 dispatch_touch(window, cx, TouchId(1), TouchPhase::Moved, 2.);
9016 dispatch_touch(window, cx, TouchId(1), TouchPhase::Ended, 2.);
9017 window
9018 .update(cx, |_, window, _| {
9019 assert!(window.long_press_capture.is_none());
9020 })
9021 .unwrap();
9022
9023 let phases = phases.borrow();
9024 if response == LongPressResponse::PreventDefault {
9025 assert_eq!(
9026 phases.as_slice(),
9027 [TouchPhase::Started, TouchPhase::Moved, TouchPhase::Ended]
9028 );
9029 } else {
9030 assert_eq!(phases.as_slice(), [TouchPhase::Started]);
9031 }
9032 }
9033 }
9034
9035 #[gpui::test]
9036 fn stale_default_prevention_does_not_claim_long_press(cx: &mut TestAppContext) {
9037 let phases = Rc::new(RefCell::new(Vec::new()));
9038 let window = cx.add_window({
9039 let phases = phases.clone();
9040 move |_, _| LongPressListener {
9041 phases,
9042 response: LongPressResponse::None,
9043 }
9044 });
9045 window
9046 .update(cx, |_, window, _| {
9047 window.prevent_default();
9048 })
9049 .unwrap();
9050
9051 dispatch_touch(window, cx, TouchId(1), TouchPhase::Started, 0.);
9052 cx.executor().advance_clock(Duration::from_millis(501));
9053 cx.executor().run_until_parked();
9054 dispatch_touch(window, cx, TouchId(1), TouchPhase::Moved, 2.);
9055
9056 assert_eq!(phases.borrow().as_slice(), [TouchPhase::Started]);
9057 }
9058
9059 #[gpui::test]
9060 fn resolved_touch_cancels_scheduled_long_press(cx: &mut TestAppContext) {
9061 for (phase, position) in [
9062 (TouchPhase::Ended, 0.),
9063 (TouchPhase::Cancelled, 0.),
9064 (TouchPhase::Moved, 20.),
9065 ] {
9066 let phases = Rc::new(RefCell::new(Vec::new()));
9067 let window = cx.add_window({
9068 let phases = phases.clone();
9069 move |_, _| LongPressListener {
9070 phases,
9071 response: LongPressResponse::PreventDefault,
9072 }
9073 });
9074 dispatch_touch(window, cx, TouchId(1), TouchPhase::Started, 0.);
9075 dispatch_touch(window, cx, TouchId(1), phase, position);
9076 cx.executor().advance_clock(Duration::from_millis(501));
9077 cx.executor().run_until_parked();
9078
9079 assert!(phases.borrow().is_empty(), "{phase:?} allowed long press");
9080 }
9081 }
9082
9083 #[gpui::test]
9084 fn stale_long_press_timer_cannot_affect_replacement_touch(cx: &mut TestAppContext) {
9085 let phases = Rc::new(RefCell::new(Vec::new()));
9086 let window = cx.add_window({
9087 let phases = phases.clone();
9088 move |_, _| LongPressListener {
9089 phases,
9090 response: LongPressResponse::PreventDefault,
9091 }
9092 });
9093 let first_touch = TouchId(1);
9094 dispatch_touch(window, cx, first_touch, TouchPhase::Started, 0.);
9095 cx.executor().advance_clock(Duration::from_millis(250));
9096 dispatch_touch(window, cx, first_touch, TouchPhase::Cancelled, 0.);
9097 dispatch_touch(window, cx, TouchId(2), TouchPhase::Started, 10.);
9098
9099 cx.executor().advance_clock(Duration::from_millis(251));
9100 cx.executor().run_until_parked();
9101 assert!(phases.borrow().is_empty());
9102
9103 cx.executor().advance_clock(Duration::from_millis(250));
9104 cx.executor().run_until_parked();
9105 assert_eq!(phases.borrow().as_slice(), [TouchPhase::Started]);
9106 }
9107
9108 #[gpui::test]
9109 fn test_underline_exclusions_preserve_device_geometry(cx: &mut TestAppContext) {
9110 test_underline_paint_at_scales(cx, |window| {
9111 let (numerator, denominator) = match window.scale_factor() {
9112 1.0 => (1, 1),
9113 1.25 => (5, 4),
9114 1.5 => (3, 2),
9115 2.0 => (2, 1),
9116 3.0 => (3, 1),
9117 scale => panic!("unexpected scale {scale}"),
9118 };
9119 let snap = |quarters: i32| {
9120 let scaled = quarters * numerator;
9121 let divisor = 4 * denominator;
9122 let rounded =
9123 scaled.abs() / divisor + i32::from(2 * (scaled.abs() % divisor) > divisor);
9124 ScaledPixels((scaled.signum() * rounded) as f32)
9125 };
9126 let stroke = |quarters| {
9127 if quarters == 0 {
9128 ScaledPixels(0.)
9129 } else {
9130 snap(quarters).max(ScaledPixels(1.))
9131 }
9132 };
9133
9134 for origin in [-101, -3, -2, -1, 0, 1, 2, 3, 101] {
9135 for width in [0, 1, 3, 84] {
9136 for thickness in [0, 1, 4, 7] {
9137 for wavy in [false, true] {
9138 let style = UnderlineStyle {
9139 thickness: px(thickness as f32 / 4.),
9140 color: Some(hsla(0.25, 0.5, 0.75, 0.5)),
9141 wavy,
9142 };
9143 let bounds = Bounds::new(
9144 point(snap(origin), snap(-origin)),
9145 size(
9146 stroke(width),
9147 stroke(thickness) * if wavy { 3. } else { 1. },
9148 ),
9149 );
9150 let origin = point(px(origin as f32 / 4.), px(-origin as f32 / 4.));
9151 let width = px(width as f32 / 4.);
9152 assert_eq!(window.underline_bounds(origin, width, &style), bounds);
9153 let original = paint_test_underlines(window, |window| {
9154 window.paint_underline(origin, width, &style);
9155 })
9156 .to_vec();
9157 assert_eq!(original.len(), usize::from(!bounds.is_empty()));
9158 if let Some(underline) = original.first() {
9159 assert_eq!(underline.bounds, bounds);
9160 assert_eq!(underline.thickness, stroke(thickness));
9161 assert_eq!(underline.wavy, wavy.into());
9162 assert_eq!(underline.color, hsla(0.25, 0.5, 0.75, 0.5));
9163 }
9164
9165 let underlines = paint_test_underlines(window, |window| {
9166 window.paint_underline_with_exclusions(origin, width, &style, &[]);
9167 });
9168 assert_eq!(underlines.len(), original.len());
9169 for (actual, original) in underlines.iter().zip(&original) {
9170 assert_same_underline_geometry(actual, original);
9171 assert_eq!(actual.content_mask, original.content_mask);
9172 }
9173
9174 let left = bounds.left().0 as i32;
9175 let right = bounds.right().0 as i32;
9176 let exclusions = [
9177 (15, 25),
9178 (3, 7),
9179 (5, 10),
9180 (10, 12),
9181 (0, 0),
9182 (4, 2),
9183 (-50, -1),
9184 (70, 100),
9185 ]
9186 .map(|(start, end)| {
9187 ScaledPixels((left + start) as f32)
9188 ..ScaledPixels((left + end) as f32)
9189 });
9190 let underlines = paint_test_underlines(window, |window| {
9191 window.paint_underline_with_exclusions(
9192 origin,
9193 width,
9194 &style,
9195 &exclusions,
9196 );
9197 });
9198 let expected = (left..right)
9199 .filter(|column| {
9200 !bounds.is_empty()
9201 && !exclusions.iter().any(|span| {
9202 span.contains(&ScaledPixels(*column as f32))
9203 })
9204 })
9205 .collect::<Vec<_>>();
9206 assert_eq!(underline_device_columns(underlines), expected);
9207 for underline in underlines {
9208 assert_same_underline_geometry(underline, &original[0]);
9209 }
9210 }
9211 }
9212 }
9213 }
9214 });
9215 }
9216
9217 #[gpui::test]
9218 fn test_underline_exclusions_preserve_helvetica_warning_edge(cx: &mut TestAppContext) {
9219 test_underline_paint_at_scales(cx, |window| {
9220 if window.scale_factor() != 2.0 {
9221 return;
9222 }
9223 let style = UnderlineStyle {
9224 thickness: px(1.),
9225 color: None,
9226 wavy: true,
9227 };
9228 let origin = point(px(2.888_183_8), px(15.357_917));
9229 let width = px(23.848_145) - origin.x;
9230 let original = paint_test_underlines(window, |window| {
9231 window.paint_underline(origin, width, &style);
9232 })[0];
9233 assert_eq!(original.bounds.left(), ScaledPixels(6.));
9234 assert_eq!(original.bounds.right(), ScaledPixels(48.));
9235 let point_bounds = window.underline_bounds(origin, px(10.829_102), &style);
9236 assert_eq!(point_bounds.left(), ScaledPixels(6.));
9237 assert_eq!(point_bounds.right(), ScaledPixels(28.));
9238
9239 let underlines = paint_test_underlines(window, |window| {
9240 window.paint_underline_with_exclusions(
9241 origin,
9242 width,
9243 &style,
9244 &[point_bounds.left()..point_bounds.right()],
9245 );
9246 });
9247 assert_eq!(underlines.len(), 1);
9248 assert_same_underline_geometry(&underlines[0], &original);
9249 assert_eq!(
9250 underline_device_columns(underlines),
9251 (28..48).collect::<Vec<_>>()
9252 );
9253 });
9254 }
9255
9256 #[gpui::test]
9257 fn test_underline_exclusions_preserve_content_mask_and_opacity(cx: &mut TestAppContext) {
9258 test_underline_paint_at_scales(cx, |window| {
9259 let scale = window.scale_factor();
9260 let original_mask = window.content_mask();
9261 let original_opacity = window.element_opacity();
9262 let mask = ContentMask::new(Bounds::from_corners(
9263 point(px(4.), px(10.)),
9264 point(px(16.), px(12.)),
9265 ));
9266 let style = UnderlineStyle {
9267 thickness: px(2.),
9268 color: Some(hsla(0.25, 0.5, 0.75, 0.5)),
9269 wavy: true,
9270 };
9271 let origin = point(px(-1.25), px(9.25));
9272 let width = px(24.);
9273 window.with_content_mask(Some(mask), |window| {
9274 window.with_element_opacity(Some(0.5), |window| {
9275 window.with_element_opacity(Some(0.5), |window| {
9276 let original = paint_test_underlines(window, |window| {
9277 window.paint_underline(origin, width, &style);
9278 })[0];
9279 assert_eq!(original.color, hsla(0.25, 0.5, 0.75, 0.125));
9280 let underlines = paint_test_underlines(window, |window| {
9281 window.paint_underline_with_exclusions(
9282 origin,
9283 width,
9284 &style,
9285 &[ScaledPixels(6. * scale)..ScaledPixels(8. * scale)],
9286 );
9287 });
9288 assert_eq!(underlines.len(), 2);
9289 let expected = [(4. * scale, 6. * scale), (8. * scale, 16. * scale)].map(
9290 |(left, right)| {
9291 Bounds::from_corners(
9292 point(ScaledPixels(left), ScaledPixels((10. * scale).floor())),
9293 point(ScaledPixels(right), ScaledPixels((12. * scale).ceil())),
9294 )
9295 },
9296 );
9297 assert_eq!(
9298 underlines
9299 .iter()
9300 .map(|underline| underline.content_mask.bounds)
9301 .collect::<Vec<_>>(),
9302 expected
9303 );
9304 for underline in underlines {
9305 assert_same_underline_geometry(underline, &original);
9306 }
9307 });
9308 });
9309 });
9310 assert_eq!(window.content_mask(), original_mask);
9311 assert_eq!(window.element_opacity(), original_opacity);
9312 });
9313 }
9314
9315 #[gpui::test]
9316 fn test_underline_exclusions_adversarial_permutations(cx: &mut TestAppContext) {
9317 test_underline_paint_at_scales(cx, |window| {
9318 let style = UnderlineStyle {
9319 thickness: px(1.),
9320 color: None,
9321 wavy: true,
9322 };
9323 let origin = point(px(-4.), px(-1.));
9324 let width = px(8.);
9325 let left = (-4. * window.scale_factor()) as i32;
9326 let right = (4. * window.scale_factor()) as i32;
9327 let endpoints = [-16, -8, -1, 0, 1, 8, 16];
9328 for first_start in endpoints {
9329 for first_end in endpoints {
9330 for second_start in endpoints {
9331 for second_end in endpoints {
9332 let exclusions = [first_start..first_end, second_start..second_end];
9333 let expected = (left..right)
9334 .filter(|column| {
9335 !exclusions.iter().any(|span| span.contains(column))
9336 })
9337 .collect::<Vec<_>>();
9338 let exclusions = exclusions.map(|span| {
9339 ScaledPixels(span.start as f32)..ScaledPixels(span.end as f32)
9340 });
9341 let underlines = paint_test_underlines(window, |window| {
9342 window.paint_underline_with_exclusions(
9343 origin,
9344 width,
9345 &style,
9346 &exclusions,
9347 );
9348 });
9349 assert_eq!(
9350 underline_device_columns(underlines),
9351 expected,
9352 "{exclusions:?}"
9353 );
9354 }
9355 }
9356 }
9357 }
9358 });
9359 }
9360
9361 #[derive(Clone, Copy, PartialEq)]
9362 enum LongPressResponse {
9363 PreventDefault,
9364 StopPropagation,
9365 None,
9366 }
9367
9368 struct LongPressListener {
9369 phases: Rc<RefCell<Vec<TouchPhase>>>,
9370 response: LongPressResponse,
9371 }
9372
9373 impl Render for LongPressListener {
9374 fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
9375 let entity = cx.entity();
9376 let phases = self.phases.clone();
9377 let response = self.response;
9378 canvas(
9379 |_, _, _| {},
9380 move |_, _, window, _| {
9381 window.on_mouse_event(move |event: &LongPressEvent, phase, window, cx| {
9382 if phase != DispatchPhase::Bubble {
9383 return;
9384 }
9385 phases.borrow_mut().push(event.phase);
9386 match response {
9387 LongPressResponse::PreventDefault => {
9388 window.capture_long_press(&entity);
9389 window.prevent_default();
9390 }
9391 LongPressResponse::StopPropagation => cx.stop_propagation(),
9392 LongPressResponse::None => {}
9393 }
9394 });
9395 },
9396 )
9397 }
9398 }
9399
9400 struct UnderlineTestView(Rc<dyn Fn(&mut Window)>);
9401
9402 impl Render for UnderlineTestView {
9403 fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
9404 let paint = self.0.clone();
9405 canvas(
9406 |_, _, _| {},
9407 move |_, _, window, _| {
9408 window
9409 .content_mask_stack
9410 .push(ContentMask::new(Bounds::from_corners(
9411 point(px(-1000.), px(-1000.)),
9412 point(px(1000.), px(1000.)),
9413 )));
9414 paint(window);
9415 window.content_mask_stack.pop();
9416 },
9417 )
9418 .size_full()
9419 }
9420 }
9421
9422 fn test_underline_paint_at_scales(
9423 cx: &mut TestAppContext,
9424 paint: impl Fn(&mut Window) + 'static,
9425 ) {
9426 let window = cx.add_window(move |_, _| UnderlineTestView(Rc::new(paint)));
9427 for scale in [1., 1.25, 1.5, 2., 3.] {
9428 cx.simulate_window_scale_factor_change(window.into(), scale);
9429 cx.update_window(window.into(), |_, window, cx| window.draw(cx).clear(cx))
9430 .unwrap();
9431 }
9432 }
9433
9434 fn paint_test_underlines(window: &mut Window, paint: impl FnOnce(&mut Window)) -> &[Underline] {
9435 window.next_frame.scene.clear();
9436 paint(window);
9437 &window.next_frame.scene.underlines
9438 }
9439
9440 fn assert_same_underline_geometry(actual: &Underline, expected: &Underline) {
9441 assert_eq!(actual.bounds, expected.bounds);
9442 assert_eq!(actual.thickness, expected.thickness);
9443 assert_eq!(actual.wavy, expected.wavy);
9444 assert_eq!(actual.color, expected.color);
9445 assert_eq!(actual.pad, expected.pad);
9446 }
9447
9448 fn underline_device_columns(underlines: &[Underline]) -> Vec<i32> {
9449 underlines
9450 .iter()
9451 .flat_map(|underline| {
9452 let bounds = underline.bounds.intersect(&underline.content_mask.bounds);
9453 bounds.left().0 as i32..bounds.right().0 as i32
9454 })
9455 .collect()
9456 }
9457
9458 fn dispatch_touch<T: 'static>(
9459 window: crate::WindowHandle<T>,
9460 cx: &mut TestAppContext,
9461 id: TouchId,
9462 phase: TouchPhase,
9463 x: f32,
9464 ) {
9465 window
9466 .update(cx, |_, window, cx| {
9467 window.dispatch_event(
9468 TouchEvent {
9469 id,
9470 phase,
9471 position: point(px(x), px(0.)),
9472 predicted_position: None,
9473 force: None,
9474 }
9475 .to_platform_input(),
9476 cx,
9477 );
9478 })
9479 .unwrap();
9480 }
9481}
9482
9483#[cfg(all(test, any(feature = "inspector", debug_assertions)))]
9484mod inspector_tests {
9485 use super::*;
9486 use crate::{
9487 DivInspectorState, InspectorElementId, MouseDownEvent, StyleRefinement, TestAppContext, div,
9488 };
9489
9490 #[gpui::test]
9491 fn inspector_only_tracks_its_open_window(cx: &mut TestAppContext) {
9492 let windows = [
9493 cx.add_window(|_, cx| InspectorTestRoot {
9494 child: cx.new(|_| InspectorTestView::default()),
9495 }),
9496 cx.add_window(|_, cx| InspectorTestRoot {
9497 child: cx.new(|_| InspectorTestView::default()),
9498 }),
9499 ];
9500 for window in windows {
9501 assert_closed_inspector(window.into(), cx);
9502 }
9503 for _ in 0..2 {
9504 cx.update_window(windows[0].into(), |root, window, cx| {
9505 let root = root.downcast::<InspectorTestRoot>().expect("test root");
9506 let child_widths = root.read(cx).child.read(cx).child_widths.clone();
9507 window.toggle_inspector(cx);
9508 window.draw(cx).clear(cx);
9509 assert_eq!(child_widths.borrow().as_slice(), &[px(10.); 3]);
9510 let path = window
9511 .rendered_frame
9512 .next_inspector_instance_ids
9513 .iter()
9514 .find_map(|(path, count)| (*count == 3).then(|| path.clone()))
9515 .expect("anonymous siblings share an inspector path");
9516 let selected_id = InspectorElementId {
9517 path,
9518 instance_id: 1,
9519 };
9520 let position = window
9521 .rendered_frame
9522 .hitboxes
9523 .iter()
9524 .find(|hitbox| {
9525 window.rendered_frame.inspector_hitboxes.get(&hitbox.id)
9526 == Some(&selected_id)
9527 })
9528 .expect("middle sibling is pickable")
9529 .bounds
9530 .center();
9531 window.simulate_mouse_move(position, cx);
9532 window.dispatch_event(
9533 PlatformInput::MouseDown(MouseDownEvent {
9534 position,
9535 button: MouseButton::Left,
9536 modifiers: Modifiers::default(),
9537 click_count: 1,
9538 first_mouse: false,
9539 }),
9540 cx,
9541 );
9542 window.dispatch_event(
9543 PlatformInput::MouseUp(MouseUpEvent {
9544 position,
9545 button: MouseButton::Left,
9546 modifiers: Modifiers::default(),
9547 click_count: 1,
9548 }),
9549 cx,
9550 );
9551 assert!(!window.is_inspector_picking(cx));
9552 assert_eq!(
9553 window
9554 .inspector
9555 .as_ref()
9556 .expect("open inspector")
9557 .read(cx)
9558 .active_element_id(),
9559 Some(&selected_id)
9560 );
9561 window.draw(cx).clear(cx);
9562 window.with_inspector_state::<DivInspectorState, _>(
9563 Some(&selected_id),
9564 cx,
9565 |state, _| {
9566 let state = state.as_mut().expect("selected div has style state");
9567 assert_eq!(
9568 state.base_style.size.width,
9569 Some(crate::Length::from(px(10.)))
9570 );
9571 state.base_style.size.width = Some(crate::Length::from(px(25.)));
9572 },
9573 );
9574 window.refresh();
9575 window.draw(cx).clear(cx);
9576 assert_eq!(
9577 child_widths.borrow().as_slice(),
9578 &[px(10.), px(25.), px(10.)]
9579 );
9580 })
9581 .expect("pick and edit a cached child");
9582 assert_closed_inspector(windows[1].into(), cx);
9583 windows[0]
9584 .update(cx, |_, window, cx| window.toggle_inspector(cx))
9585 .expect("close inspector");
9586 assert_closed_inspector(windows[0].into(), cx);
9587 }
9588 }
9589
9590 struct InspectorTestRoot {
9591 child: Entity<InspectorTestView>,
9592 }
9593
9594 impl Render for InspectorTestRoot {
9595 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
9596 self.child
9597 .clone()
9598 .cached(StyleRefinement::default().size(px(100.)))
9599 }
9600 }
9601
9602 #[derive(Default)]
9603 struct InspectorTestView {
9604 child_widths: Rc<RefCell<Vec<Pixels>>>,
9605 }
9606
9607 impl Render for InspectorTestView {
9608 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
9609 let child_widths = self.child_widths.clone();
9610 div()
9611 .on_children_prepainted(move |bounds, _, _| {
9612 *child_widths.borrow_mut() =
9613 bounds.iter().map(|bounds| bounds.size.width).collect();
9614 })
9615 .with_dynamic_prepaint_order(|_, _| SmallVec::from_iter([2, 0, 1]))
9616 .id("inspector-root")
9617 .flex()
9618 .children((0..3).map(|_| div().size(px(10.)).flex_shrink_0()))
9619 }
9620 }
9621
9622 fn assert_closed_inspector(window: AnyWindowHandle, cx: &mut TestAppContext) {
9623 cx.update_window(window, |root, window, cx| {
9624 window.draw(cx).clear(cx);
9625 window.draw(cx).clear(cx);
9626 let root = root.downcast::<InspectorTestRoot>().expect("test root");
9627 assert_eq!(
9628 root.read(cx)
9629 .child
9630 .read(cx)
9631 .child_widths
9632 .borrow()
9633 .as_slice(),
9634 &[px(10.); 3]
9635 );
9636 for frame in [&window.rendered_frame, &window.next_frame] {
9637 assert_eq!(frame.next_inspector_instance_ids.capacity(), 0);
9638 assert_eq!(frame.inspector_hitboxes.capacity(), 0);
9639 }
9640 })
9641 .expect("closed inspector has no bookkeeping and no style overrides");
9642 }
9643}