1#[cfg(any(feature = "inspector", debug_assertions))]
2use crate::Inspector;
3use crate::{
4 Action, AnyDrag, AnyElement, AnyImageCache, AnyTooltip, AnyView, App, AppContext, Arena, Asset,
5 AsyncWindowContext, AvailableSpace, Background, BorderStyle, Bounds, BoxShadow, Capslock,
6 Context, Corners, CursorStyle, Decorations, DevicePixels, DispatchActionListener,
7 DispatchNodeId, DispatchTree, DisplayId, Edges, Effect, Entity, EntityId, EventEmitter,
8 FileDropEvent, FontId, Global, GlobalElementId, GlyphId, GpuSpecs, Hsla, InputHandler, IsZero,
9 KeyBinding, KeyContext, KeyDownEvent, KeyEvent, Keystroke, KeystrokeEvent, LayoutId,
10 LineLayoutIndex, Modifiers, ModifiersChangedEvent, MonochromeSprite, MouseButton, MouseEvent,
11 MouseMoveEvent, MouseUpEvent, Path, Pixels, PlatformAtlas, PlatformDisplay, PlatformInput,
12 PlatformInputHandler, PlatformWindow, Point, PolychromeSprite, Priority, PromptButton,
13 PromptLevel, Quad, Render, RenderGlyphParams, RenderImage, RenderImageParams, RenderSvgParams,
14 Replay, ResizeEdge, SMOOTH_SVG_SCALE_FACTOR, SUBPIXEL_VARIANTS_X, SUBPIXEL_VARIANTS_Y,
15 ScaledPixels, Scene, Shadow, SharedString, Size, StrikethroughStyle, Style, SubpixelSprite,
16 SubscriberSet, Subscription, SystemWindowTab, SystemWindowTabController, TabStopMap,
17 TaffyLayoutEngine, Task, TextRenderingMode, TextStyle, TextStyleRefinement, ThermalState,
18 TransformationMatrix, Underline, UnderlineStyle, WindowAppearance, WindowBackgroundAppearance,
19 WindowBounds, WindowControls, WindowDecorations, WindowOptions, WindowParams, WindowTextSystem,
20 point, prelude::*, px, rems, size, transparent_black,
21};
22use anyhow::{Context as _, Result, anyhow};
23use collections::{FxHashMap, FxHashSet};
24#[cfg(target_os = "macos")]
25use core_video::pixel_buffer::CVPixelBuffer;
26use derive_more::{Deref, DerefMut};
27use futures::FutureExt;
28use futures::channel::oneshot;
29use gpui_util::post_inc;
30use gpui_util::{ResultExt, measure};
31#[cfg(feature = "input-latency-histogram")]
32use hdrhistogram::Histogram;
33use itertools::FoldWhile::{Continue, Done};
34use itertools::Itertools;
35use parking_lot::RwLock;
36use raw_window_handle::{HandleError, HasDisplayHandle, HasWindowHandle};
37use refineable::Refineable;
38use scheduler::Instant;
39use slotmap::SlotMap;
40use smallvec::SmallVec;
41use std::{
42 any::{Any, TypeId},
43 borrow::Cow,
44 cell::{Cell, RefCell},
45 cmp,
46 fmt::{Debug, Display},
47 hash::{Hash, Hasher},
48 marker::PhantomData,
49 mem,
50 ops::{DerefMut, Range},
51 rc::Rc,
52 sync::{
53 Arc, Weak,
54 atomic::{AtomicUsize, Ordering::SeqCst},
55 },
56 time::Duration,
57};
58use uuid::Uuid;
59
60mod prompts;
61
62use crate::util::atomic_incr_if_not_zero;
63pub use prompts::*;
64
65/// Default window size used when no explicit size is provided.
66pub const DEFAULT_WINDOW_SIZE: Size<Pixels> = size(px(1536.), px(1095.));
67
68/// A 6:5 aspect ratio minimum window size to be used for functional,
69/// additional-to-main-Zed windows, like the settings and rules library windows.
70pub const DEFAULT_ADDITIONAL_WINDOW_SIZE: Size<Pixels> = Size {
71 width: Pixels(900.),
72 height: Pixels(750.),
73};
74
75/// Represents the two different phases when dispatching events.
76#[derive(Default, Copy, Clone, Debug, Eq, PartialEq)]
77pub enum DispatchPhase {
78 /// After the capture phase comes the bubble phase, in which mouse event listeners are
79 /// invoked front to back and keyboard event listeners are invoked from the focused element
80 /// to the root of the element tree. This is the phase you'll most commonly want to use when
81 /// registering event listeners.
82 #[default]
83 Bubble,
84 /// During the initial capture phase, mouse event listeners are invoked back to front, and keyboard
85 /// listeners are invoked from the root of the tree downward toward the focused element. This phase
86 /// is used for special purposes such as clearing the "pressed" state for click events. If
87 /// you stop event propagation during this phase, you need to know what you're doing. Handlers
88 /// outside of the immediate region may rely on detecting non-local events during this phase.
89 Capture,
90}
91
92impl DispatchPhase {
93 /// Returns true if this represents the "bubble" phase.
94 #[inline]
95 pub fn bubble(self) -> bool {
96 self == DispatchPhase::Bubble
97 }
98
99 /// Returns true if this represents the "capture" phase.
100 #[inline]
101 pub fn capture(self) -> bool {
102 self == DispatchPhase::Capture
103 }
104}
105
106struct WindowInvalidatorInner {
107 pub dirty: bool,
108 pub draw_phase: DrawPhase,
109 pub dirty_views: FxHashSet<EntityId>,
110 pub update_count: usize,
111}
112
113#[derive(Clone)]
114pub(crate) struct WindowInvalidator {
115 inner: Rc<RefCell<WindowInvalidatorInner>>,
116}
117
118impl WindowInvalidator {
119 pub fn new() -> Self {
120 WindowInvalidator {
121 inner: Rc::new(RefCell::new(WindowInvalidatorInner {
122 dirty: true,
123 draw_phase: DrawPhase::None,
124 dirty_views: FxHashSet::default(),
125 update_count: 0,
126 })),
127 }
128 }
129
130 pub fn invalidate_view(&self, entity: EntityId, cx: &mut App) -> bool {
131 let mut inner = self.inner.borrow_mut();
132 inner.update_count += 1;
133 inner.dirty_views.insert(entity);
134 if inner.draw_phase == DrawPhase::None {
135 inner.dirty = true;
136 cx.push_effect(Effect::Notify { emitter: entity });
137 true
138 } else {
139 false
140 }
141 }
142
143 pub fn is_dirty(&self) -> bool {
144 self.inner.borrow().dirty
145 }
146
147 pub fn set_dirty(&self, dirty: bool) {
148 let mut inner = self.inner.borrow_mut();
149 inner.dirty = dirty;
150 if dirty {
151 inner.update_count += 1;
152 }
153 }
154
155 pub fn set_phase(&self, phase: DrawPhase) {
156 self.inner.borrow_mut().draw_phase = phase
157 }
158
159 pub fn update_count(&self) -> usize {
160 self.inner.borrow().update_count
161 }
162
163 pub fn take_views(&self) -> FxHashSet<EntityId> {
164 mem::take(&mut self.inner.borrow_mut().dirty_views)
165 }
166
167 pub fn replace_views(&self, views: FxHashSet<EntityId>) {
168 self.inner.borrow_mut().dirty_views = views;
169 }
170
171 pub fn not_drawing(&self) -> bool {
172 self.inner.borrow().draw_phase == DrawPhase::None
173 }
174
175 #[track_caller]
176 pub fn debug_assert_paint(&self) {
177 debug_assert!(
178 matches!(self.inner.borrow().draw_phase, DrawPhase::Paint),
179 "this method can only be called during paint"
180 );
181 }
182
183 #[track_caller]
184 pub fn debug_assert_prepaint(&self) {
185 debug_assert!(
186 matches!(self.inner.borrow().draw_phase, DrawPhase::Prepaint),
187 "this method can only be called during request_layout, or prepaint"
188 );
189 }
190
191 #[track_caller]
192 pub fn debug_assert_paint_or_prepaint(&self) {
193 debug_assert!(
194 matches!(
195 self.inner.borrow().draw_phase,
196 DrawPhase::Paint | DrawPhase::Prepaint
197 ),
198 "this method can only be called during request_layout, prepaint, or paint"
199 );
200 }
201}
202
203type AnyObserver = Box<dyn FnMut(&mut Window, &mut App) -> bool + 'static>;
204
205pub(crate) type AnyWindowFocusListener =
206 Box<dyn FnMut(&WindowFocusEvent, &mut Window, &mut App) -> bool + 'static>;
207
208pub(crate) struct WindowFocusEvent {
209 pub(crate) previous_focus_path: SmallVec<[FocusId; 8]>,
210 pub(crate) current_focus_path: SmallVec<[FocusId; 8]>,
211}
212
213impl WindowFocusEvent {
214 pub fn is_focus_in(&self, focus_id: FocusId) -> bool {
215 !self.previous_focus_path.contains(&focus_id) && self.current_focus_path.contains(&focus_id)
216 }
217
218 pub fn is_focus_out(&self, focus_id: FocusId) -> bool {
219 self.previous_focus_path.contains(&focus_id) && !self.current_focus_path.contains(&focus_id)
220 }
221}
222
223/// This is provided when subscribing for `Context::on_focus_out` events.
224pub struct FocusOutEvent {
225 /// A weak focus handle representing what was blurred.
226 pub blurred: WeakFocusHandle,
227}
228
229slotmap::new_key_type! {
230 /// A globally unique identifier for a focusable element.
231 pub struct FocusId;
232}
233
234thread_local! {
235 /// Fallback arena used when no app-specific arena is active.
236 /// In production, each window draw sets CURRENT_ELEMENT_ARENA to the app's arena.
237 pub(crate) static ELEMENT_ARENA: RefCell<Arena> = RefCell::new(Arena::new(1024 * 1024));
238
239 /// Points to the current App's element arena during draw operations.
240 /// This allows multiple test Apps to have isolated arenas, preventing
241 /// cross-session corruption when the scheduler interleaves their tasks.
242 static CURRENT_ELEMENT_ARENA: Cell<Option<*const RefCell<Arena>>> = const { Cell::new(None) };
243}
244
245/// Allocates an element in the current arena. Uses the app-specific arena if one
246/// is active (during draw), otherwise falls back to the thread-local ELEMENT_ARENA.
247pub(crate) fn with_element_arena<R>(f: impl FnOnce(&mut Arena) -> R) -> R {
248 CURRENT_ELEMENT_ARENA.with(|current| {
249 if let Some(arena_ptr) = current.get() {
250 // SAFETY: The pointer is valid for the duration of the draw operation
251 // that set it, and we're being called during that same draw.
252 let arena_cell = unsafe { &*arena_ptr };
253 f(&mut arena_cell.borrow_mut())
254 } else {
255 ELEMENT_ARENA.with_borrow_mut(f)
256 }
257 })
258}
259
260/// RAII guard that sets CURRENT_ELEMENT_ARENA for the duration of a draw operation.
261/// When dropped, restores the previous arena (supporting nested draws).
262pub(crate) struct ElementArenaScope {
263 previous: Option<*const RefCell<Arena>>,
264}
265
266impl ElementArenaScope {
267 /// Enter a scope where element allocations use the given arena.
268 pub(crate) fn enter(arena: &RefCell<Arena>) -> Self {
269 let previous = CURRENT_ELEMENT_ARENA.with(|current| {
270 let prev = current.get();
271 current.set(Some(arena as *const RefCell<Arena>));
272 prev
273 });
274 Self { previous }
275 }
276}
277
278impl Drop for ElementArenaScope {
279 fn drop(&mut self) {
280 CURRENT_ELEMENT_ARENA.with(|current| {
281 current.set(self.previous);
282 });
283 }
284}
285
286/// Returned when the element arena has been used and so must be cleared before the next draw.
287#[must_use]
288pub struct ArenaClearNeeded {
289 arena: *const RefCell<Arena>,
290}
291
292impl ArenaClearNeeded {
293 /// Create a new ArenaClearNeeded that will clear the given arena.
294 pub(crate) fn new(arena: &RefCell<Arena>) -> Self {
295 Self {
296 arena: arena as *const RefCell<Arena>,
297 }
298 }
299
300 /// Clear the element arena.
301 pub fn clear(self) {
302 // SAFETY: The arena pointer is valid because ArenaClearNeeded is created
303 // at the end of draw() and must be cleared before the next draw.
304 let arena_cell = unsafe { &*self.arena };
305 arena_cell.borrow_mut().clear();
306 }
307}
308
309pub(crate) type FocusMap = RwLock<SlotMap<FocusId, FocusRef>>;
310pub(crate) struct FocusRef {
311 pub(crate) ref_count: AtomicUsize,
312 pub(crate) tab_index: isize,
313 pub(crate) tab_stop: bool,
314}
315
316impl FocusId {
317 /// Obtains whether the element associated with this handle is currently focused.
318 pub fn is_focused(&self, window: &Window) -> bool {
319 window.focus == Some(*self)
320 }
321
322 /// Obtains whether the element associated with this handle contains the focused
323 /// element or is itself focused.
324 pub fn contains_focused(&self, window: &Window, cx: &App) -> bool {
325 window
326 .focused(cx)
327 .is_some_and(|focused| self.contains(focused.id, window))
328 }
329
330 /// Obtains whether the element associated with this handle is contained within the
331 /// focused element or is itself focused.
332 pub fn within_focused(&self, window: &Window, cx: &App) -> bool {
333 let focused = window.focused(cx);
334 focused.is_some_and(|focused| focused.id.contains(*self, window))
335 }
336
337 /// Obtains whether this handle contains the given handle in the most recently rendered frame.
338 pub(crate) fn contains(&self, other: Self, window: &Window) -> bool {
339 window
340 .rendered_frame
341 .dispatch_tree
342 .focus_contains(*self, other)
343 }
344}
345
346/// A handle which can be used to track and manipulate the focused element in a window.
347pub struct FocusHandle {
348 pub(crate) id: FocusId,
349 handles: Arc<FocusMap>,
350 /// The index of this element in the tab order.
351 pub tab_index: isize,
352 /// Whether this element can be focused by tab navigation.
353 pub tab_stop: bool,
354}
355
356impl std::fmt::Debug for FocusHandle {
357 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
358 f.write_fmt(format_args!("FocusHandle({:?})", self.id))
359 }
360}
361
362impl FocusHandle {
363 pub(crate) fn new(handles: &Arc<FocusMap>) -> Self {
364 let id = handles.write().insert(FocusRef {
365 ref_count: AtomicUsize::new(1),
366 tab_index: 0,
367 tab_stop: false,
368 });
369
370 Self {
371 id,
372 tab_index: 0,
373 tab_stop: false,
374 handles: handles.clone(),
375 }
376 }
377
378 pub(crate) fn for_id(id: FocusId, handles: &Arc<FocusMap>) -> Option<Self> {
379 let lock = handles.read();
380 let focus = lock.get(id)?;
381 if atomic_incr_if_not_zero(&focus.ref_count) == 0 {
382 return None;
383 }
384 Some(Self {
385 id,
386 tab_index: focus.tab_index,
387 tab_stop: focus.tab_stop,
388 handles: handles.clone(),
389 })
390 }
391
392 /// Sets the tab index of the element associated with this handle.
393 pub fn tab_index(mut self, index: isize) -> Self {
394 self.tab_index = index;
395 if let Some(focus) = self.handles.write().get_mut(self.id) {
396 focus.tab_index = index;
397 }
398 self
399 }
400
401 /// Sets whether the element associated with this handle is a tab stop.
402 ///
403 /// When `false`, the element will not be included in the tab order.
404 pub fn tab_stop(mut self, tab_stop: bool) -> Self {
405 self.tab_stop = tab_stop;
406 if let Some(focus) = self.handles.write().get_mut(self.id) {
407 focus.tab_stop = tab_stop;
408 }
409 self
410 }
411
412 /// Converts this focus handle into a weak variant, which does not prevent it from being released.
413 pub fn downgrade(&self) -> WeakFocusHandle {
414 WeakFocusHandle {
415 id: self.id,
416 handles: Arc::downgrade(&self.handles),
417 }
418 }
419
420 /// Moves the focus to the element associated with this handle.
421 pub fn focus(&self, window: &mut Window, cx: &mut App) {
422 window.focus(self, cx)
423 }
424
425 /// Obtains whether the element associated with this handle is currently focused.
426 pub fn is_focused(&self, window: &Window) -> bool {
427 self.id.is_focused(window)
428 }
429
430 /// Obtains whether the element associated with this handle contains the focused
431 /// element or is itself focused.
432 pub fn contains_focused(&self, window: &Window, cx: &App) -> bool {
433 self.id.contains_focused(window, cx)
434 }
435
436 /// Obtains whether the element associated with this handle is contained within the
437 /// focused element or is itself focused.
438 pub fn within_focused(&self, window: &Window, cx: &mut App) -> bool {
439 self.id.within_focused(window, cx)
440 }
441
442 /// Obtains whether this handle contains the given handle in the most recently rendered frame.
443 pub fn contains(&self, other: &Self, window: &Window) -> bool {
444 self.id.contains(other.id, window)
445 }
446
447 /// Dispatch an action on the element that rendered this focus handle
448 pub fn dispatch_action(&self, action: &dyn Action, window: &mut Window, cx: &mut App) {
449 if let Some(node_id) = window
450 .rendered_frame
451 .dispatch_tree
452 .focusable_node_id(self.id)
453 {
454 window.dispatch_action_on_node(node_id, action, cx)
455 }
456 }
457}
458
459impl Clone for FocusHandle {
460 fn clone(&self) -> Self {
461 Self::for_id(self.id, &self.handles).unwrap()
462 }
463}
464
465impl PartialEq for FocusHandle {
466 fn eq(&self, other: &Self) -> bool {
467 self.id == other.id
468 }
469}
470
471impl Eq for FocusHandle {}
472
473impl Drop for FocusHandle {
474 fn drop(&mut self) {
475 self.handles
476 .read()
477 .get(self.id)
478 .unwrap()
479 .ref_count
480 .fetch_sub(1, SeqCst);
481 }
482}
483
484/// A weak reference to a focus handle.
485#[derive(Clone, Debug)]
486pub struct WeakFocusHandle {
487 pub(crate) id: FocusId,
488 pub(crate) handles: Weak<FocusMap>,
489}
490
491impl WeakFocusHandle {
492 /// Attempts to upgrade the [WeakFocusHandle] to a [FocusHandle].
493 pub fn upgrade(&self) -> Option<FocusHandle> {
494 let handles = self.handles.upgrade()?;
495 FocusHandle::for_id(self.id, &handles)
496 }
497}
498
499impl PartialEq for WeakFocusHandle {
500 fn eq(&self, other: &WeakFocusHandle) -> bool {
501 self.id == other.id
502 }
503}
504
505impl Eq for WeakFocusHandle {}
506
507impl PartialEq<FocusHandle> for WeakFocusHandle {
508 fn eq(&self, other: &FocusHandle) -> bool {
509 self.id == other.id
510 }
511}
512
513impl PartialEq<WeakFocusHandle> for FocusHandle {
514 fn eq(&self, other: &WeakFocusHandle) -> bool {
515 self.id == other.id
516 }
517}
518
519/// Focusable allows users of your view to easily
520/// focus it (using window.focus_view(cx, view))
521pub trait Focusable: 'static {
522 /// Returns the focus handle associated with this view.
523 fn focus_handle(&self, cx: &App) -> FocusHandle;
524}
525
526impl<V: Focusable> Focusable for Entity<V> {
527 fn focus_handle(&self, cx: &App) -> FocusHandle {
528 self.read(cx).focus_handle(cx)
529 }
530}
531
532/// ManagedView is a view (like a Modal, Popover, Menu, etc.)
533/// where the lifecycle of the view is handled by another view.
534pub trait ManagedView: Focusable + EventEmitter<DismissEvent> + Render {}
535
536impl<M: Focusable + EventEmitter<DismissEvent> + Render> ManagedView for M {}
537
538/// Emitted by implementers of [`ManagedView`] to indicate the view should be dismissed, such as when a view is presented as a modal.
539pub struct DismissEvent;
540
541type FrameCallback = Box<dyn FnOnce(&mut Window, &mut App)>;
542
543pub(crate) type AnyMouseListener =
544 Box<dyn FnMut(&dyn Any, DispatchPhase, &mut Window, &mut App) + 'static>;
545
546#[derive(Clone)]
547pub(crate) struct CursorStyleRequest {
548 pub(crate) hitbox_id: Option<HitboxId>,
549 pub(crate) style: CursorStyle,
550}
551
552#[derive(Default, Eq, PartialEq)]
553pub(crate) struct HitTest {
554 pub(crate) ids: SmallVec<[HitboxId; 8]>,
555 pub(crate) hover_hitbox_count: usize,
556}
557
558/// A type of window control area that corresponds to the platform window.
559#[derive(Clone, Copy, Debug, Eq, PartialEq)]
560pub enum WindowControlArea {
561 /// An area that allows dragging of the platform window.
562 Drag,
563 /// An area that allows closing of the platform window.
564 Close,
565 /// An area that allows maximizing of the platform window.
566 Max,
567 /// An area that allows minimizing of the platform window.
568 Min,
569}
570
571/// An identifier for a [Hitbox] which also includes [HitboxBehavior].
572#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
573pub struct HitboxId(u64);
574
575#[cfg(feature = "test-support")]
576impl HitboxId {
577 /// A placeholder HitboxId exclusively for integration testing API's that
578 /// need a hitbox but where the value of the hitbox does not matter. The
579 /// alternative is to make the Hitbox optional but that complicates the
580 /// implementation.
581 pub const fn placeholder() -> Self {
582 Self(0)
583 }
584}
585
586impl HitboxId {
587 /// Checks if the hitbox with this ID is currently hovered. Returns `false` during keyboard
588 /// input modality so that keyboard navigation suppresses hover highlights. Except when handling
589 /// `ScrollWheelEvent`, this is typically what you want when determining whether to handle mouse
590 /// events or paint hover styles.
591 ///
592 /// See [`Hitbox::is_hovered`] for details.
593 pub fn is_hovered(self, window: &Window) -> bool {
594 // If this hitbox has captured the pointer, it's always considered hovered
595 if window.captured_hitbox == Some(self) {
596 return true;
597 }
598 if window.last_input_was_keyboard() {
599 return false;
600 }
601 let hit_test = &window.mouse_hit_test;
602 for id in hit_test.ids.iter().take(hit_test.hover_hitbox_count) {
603 if self == *id {
604 return true;
605 }
606 }
607 false
608 }
609
610 /// Checks if the hitbox with this ID contains the mouse and should handle scroll events.
611 /// Typically this should only be used when handling `ScrollWheelEvent`, and otherwise
612 /// `is_hovered` should be used. See the documentation of `Hitbox::is_hovered` for details about
613 /// this distinction.
614 pub fn should_handle_scroll(self, window: &Window) -> bool {
615 window.mouse_hit_test.ids.contains(&self)
616 }
617
618 fn next(mut self) -> HitboxId {
619 HitboxId(self.0.wrapping_add(1))
620 }
621}
622
623/// A rectangular region that potentially blocks hitboxes inserted prior.
624/// See [Window::insert_hitbox] for more details.
625#[derive(Clone, Debug, Deref)]
626pub struct Hitbox {
627 /// A unique identifier for the hitbox.
628 pub id: HitboxId,
629 /// The bounds of the hitbox.
630 #[deref]
631 pub bounds: Bounds<Pixels>,
632 /// The content mask when the hitbox was inserted.
633 pub content_mask: ContentMask<Pixels>,
634 /// Flags that specify hitbox behavior.
635 pub behavior: HitboxBehavior,
636}
637
638impl Hitbox {
639 /// Checks if the hitbox is currently hovered. Returns `false` during keyboard input modality
640 /// so that keyboard navigation suppresses hover highlights. Except when handling
641 /// `ScrollWheelEvent`, this is typically what you want when determining whether to handle mouse
642 /// events or paint hover styles.
643 ///
644 /// This can return `false` even when the hitbox contains the mouse, if a hitbox in front of
645 /// this sets `HitboxBehavior::BlockMouse` (`InteractiveElement::occlude`) or
646 /// `HitboxBehavior::BlockMouseExceptScroll` (`InteractiveElement::block_mouse_except_scroll`),
647 /// or if the current input modality is keyboard (see [`Window::last_input_was_keyboard`]).
648 ///
649 /// Handling of `ScrollWheelEvent` should typically use `should_handle_scroll` instead.
650 /// Concretely, this is due to use-cases like overlays that cause the elements under to be
651 /// non-interactive while still allowing scrolling. More abstractly, this is because
652 /// `is_hovered` is about element interactions directly under the mouse - mouse moves, clicks,
653 /// hover styling, etc. In contrast, scrolling is about finding the current outer scrollable
654 /// container.
655 pub fn is_hovered(&self, window: &Window) -> bool {
656 self.id.is_hovered(window)
657 }
658
659 /// Checks if the hitbox contains the mouse and should handle scroll events. Typically this
660 /// should only be used when handling `ScrollWheelEvent`, and otherwise `is_hovered` should be
661 /// used. See the documentation of `Hitbox::is_hovered` for details about this distinction.
662 ///
663 /// This can return `false` even when the hitbox contains the mouse, if a hitbox in front of
664 /// this sets `HitboxBehavior::BlockMouse` (`InteractiveElement::occlude`).
665 pub fn should_handle_scroll(&self, window: &Window) -> bool {
666 self.id.should_handle_scroll(window)
667 }
668}
669
670/// How the hitbox affects mouse behavior.
671#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
672pub enum HitboxBehavior {
673 /// Normal hitbox mouse behavior, doesn't affect mouse handling for other hitboxes.
674 #[default]
675 Normal,
676
677 /// All hitboxes behind this hitbox will be ignored and so will have `hitbox.is_hovered() ==
678 /// false` and `hitbox.should_handle_scroll() == false`. Typically for elements this causes
679 /// skipping of all mouse events, hover styles, and tooltips. This flag is set by
680 /// [`InteractiveElement::occlude`].
681 ///
682 /// For mouse handlers that check those hitboxes, this behaves the same as registering a
683 /// bubble-phase handler for every mouse event type:
684 ///
685 /// ```ignore
686 /// window.on_mouse_event(move |_: &EveryMouseEventTypeHere, phase, window, cx| {
687 /// if phase == DispatchPhase::Capture && hitbox.is_hovered(window) {
688 /// cx.stop_propagation();
689 /// }
690 /// })
691 /// ```
692 ///
693 /// This has effects beyond event handling - any use of hitbox checking, such as hover
694 /// styles and tooltips. These other behaviors are the main point of this mechanism. An
695 /// alternative might be to not affect mouse event handling - but this would allow
696 /// inconsistent UI where clicks and moves interact with elements that are not considered to
697 /// be hovered.
698 BlockMouse,
699
700 /// All hitboxes behind this hitbox will have `hitbox.is_hovered() == false`, even when
701 /// `hitbox.should_handle_scroll() == true`. Typically for elements this causes all mouse
702 /// interaction except scroll events to be ignored - see the documentation of
703 /// [`Hitbox::is_hovered`] for details. This flag is set by
704 /// [`InteractiveElement::block_mouse_except_scroll`].
705 ///
706 /// For mouse handlers that check those hitboxes, this behaves the same as registering a
707 /// bubble-phase handler for every mouse event type **except** `ScrollWheelEvent`:
708 ///
709 /// ```ignore
710 /// window.on_mouse_event(move |_: &EveryMouseEventTypeExceptScroll, phase, window, cx| {
711 /// if phase == DispatchPhase::Bubble && hitbox.should_handle_scroll(window) {
712 /// cx.stop_propagation();
713 /// }
714 /// })
715 /// ```
716 ///
717 /// See the documentation of [`Hitbox::is_hovered`] for details of why `ScrollWheelEvent` is
718 /// handled differently than other mouse events. If also blocking these scroll events is
719 /// desired, then a `cx.stop_propagation()` handler like the one above can be used.
720 ///
721 /// This has effects beyond event handling - this affects any use of `is_hovered`, such as
722 /// hover styles and tooltips. These other behaviors are the main point of this mechanism.
723 /// An alternative might be to not affect mouse event handling - but this would allow
724 /// inconsistent UI where clicks and moves interact with elements that are not considered to
725 /// be hovered.
726 BlockMouseExceptScroll,
727}
728
729/// An identifier for a tooltip.
730#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
731pub struct TooltipId(usize);
732
733impl TooltipId {
734 /// Checks if the tooltip is currently hovered.
735 pub fn is_hovered(&self, window: &Window) -> bool {
736 window
737 .tooltip_bounds
738 .as_ref()
739 .is_some_and(|tooltip_bounds| {
740 tooltip_bounds.id == *self
741 && tooltip_bounds.bounds.contains(&window.mouse_position())
742 })
743 }
744}
745
746pub(crate) struct TooltipBounds {
747 id: TooltipId,
748 bounds: Bounds<Pixels>,
749}
750
751#[derive(Clone)]
752pub(crate) struct TooltipRequest {
753 id: TooltipId,
754 tooltip: AnyTooltip,
755}
756
757pub(crate) struct DeferredDraw {
758 current_view: EntityId,
759 priority: usize,
760 parent_node: DispatchNodeId,
761 element_id_stack: SmallVec<[ElementId; 32]>,
762 text_style_stack: Vec<TextStyleRefinement>,
763 content_mask: Option<ContentMask<Pixels>>,
764 rem_size: Pixels,
765 element: Option<AnyElement>,
766 absolute_offset: Point<Pixels>,
767 prepaint_range: Range<PrepaintStateIndex>,
768 paint_range: Range<PaintIndex>,
769}
770
771pub(crate) struct Frame {
772 pub(crate) focus: Option<FocusId>,
773 pub(crate) window_active: bool,
774 pub(crate) element_states: FxHashMap<(GlobalElementId, TypeId), ElementStateBox>,
775 accessed_element_states: Vec<(GlobalElementId, TypeId)>,
776 pub(crate) mouse_listeners: Vec<Option<AnyMouseListener>>,
777 pub(crate) dispatch_tree: DispatchTree,
778 pub(crate) scene: Scene,
779 pub(crate) hitboxes: Vec<Hitbox>,
780 pub(crate) window_control_hitboxes: Vec<(WindowControlArea, Hitbox)>,
781 pub(crate) deferred_draws: Vec<DeferredDraw>,
782 pub(crate) input_handlers: Vec<Option<PlatformInputHandler>>,
783 pub(crate) tooltip_requests: Vec<Option<TooltipRequest>>,
784 pub(crate) cursor_styles: Vec<CursorStyleRequest>,
785 #[cfg(any(test, feature = "test-support"))]
786 pub(crate) debug_bounds: FxHashMap<String, Bounds<Pixels>>,
787 #[cfg(any(feature = "inspector", debug_assertions))]
788 pub(crate) next_inspector_instance_ids: FxHashMap<Rc<crate::InspectorElementPath>, usize>,
789 #[cfg(any(feature = "inspector", debug_assertions))]
790 pub(crate) inspector_hitboxes: FxHashMap<HitboxId, crate::InspectorElementId>,
791 pub(crate) tab_stops: TabStopMap,
792}
793
794#[derive(Clone, Default)]
795pub(crate) struct PrepaintStateIndex {
796 hitboxes_index: usize,
797 tooltips_index: usize,
798 deferred_draws_index: usize,
799 dispatch_tree_index: usize,
800 accessed_element_states_index: usize,
801 line_layout_index: LineLayoutIndex,
802}
803
804#[derive(Clone, Default)]
805pub(crate) struct PaintIndex {
806 scene_index: usize,
807 mouse_listeners_index: usize,
808 input_handlers_index: usize,
809 cursor_styles_index: usize,
810 accessed_element_states_index: usize,
811 tab_handle_index: usize,
812 line_layout_index: LineLayoutIndex,
813}
814
815impl Frame {
816 pub(crate) fn new(dispatch_tree: DispatchTree) -> Self {
817 Frame {
818 focus: None,
819 window_active: false,
820 element_states: FxHashMap::default(),
821 accessed_element_states: Vec::new(),
822 mouse_listeners: Vec::new(),
823 dispatch_tree,
824 scene: Scene::default(),
825 hitboxes: Vec::new(),
826 window_control_hitboxes: Vec::new(),
827 deferred_draws: Vec::new(),
828 input_handlers: Vec::new(),
829 tooltip_requests: Vec::new(),
830 cursor_styles: Vec::new(),
831
832 #[cfg(any(test, feature = "test-support"))]
833 debug_bounds: FxHashMap::default(),
834
835 #[cfg(any(feature = "inspector", debug_assertions))]
836 next_inspector_instance_ids: FxHashMap::default(),
837
838 #[cfg(any(feature = "inspector", debug_assertions))]
839 inspector_hitboxes: FxHashMap::default(),
840 tab_stops: TabStopMap::default(),
841 }
842 }
843
844 pub(crate) fn clear(&mut self) {
845 self.element_states.clear();
846 self.accessed_element_states.clear();
847 self.mouse_listeners.clear();
848 self.dispatch_tree.clear();
849 self.scene.clear();
850 self.input_handlers.clear();
851 self.tooltip_requests.clear();
852 self.cursor_styles.clear();
853 self.hitboxes.clear();
854 self.window_control_hitboxes.clear();
855 self.deferred_draws.clear();
856 self.tab_stops.clear();
857 self.focus = None;
858
859 #[cfg(any(test, feature = "test-support"))]
860 {
861 self.debug_bounds.clear();
862 }
863
864 #[cfg(any(feature = "inspector", debug_assertions))]
865 {
866 self.next_inspector_instance_ids.clear();
867 self.inspector_hitboxes.clear();
868 }
869 }
870
871 pub(crate) fn cursor_style(&self, window: &Window) -> Option<CursorStyle> {
872 self.cursor_styles
873 .iter()
874 .rev()
875 .fold_while(None, |style, request| match request.hitbox_id {
876 None => Done(Some(request.style)),
877 Some(hitbox_id) => Continue(
878 style.or_else(|| hitbox_id.is_hovered(window).then_some(request.style)),
879 ),
880 })
881 .into_inner()
882 }
883
884 pub(crate) fn hit_test(&self, position: Point<Pixels>) -> HitTest {
885 let mut set_hover_hitbox_count = false;
886 let mut hit_test = HitTest::default();
887 for hitbox in self.hitboxes.iter().rev() {
888 let bounds = hitbox.bounds.intersect(&hitbox.content_mask.bounds);
889 if bounds.contains(&position) {
890 hit_test.ids.push(hitbox.id);
891 if !set_hover_hitbox_count
892 && hitbox.behavior == HitboxBehavior::BlockMouseExceptScroll
893 {
894 hit_test.hover_hitbox_count = hit_test.ids.len();
895 set_hover_hitbox_count = true;
896 }
897 if hitbox.behavior == HitboxBehavior::BlockMouse {
898 break;
899 }
900 }
901 }
902 if !set_hover_hitbox_count {
903 hit_test.hover_hitbox_count = hit_test.ids.len();
904 }
905 hit_test
906 }
907
908 pub(crate) fn focus_path(&self) -> SmallVec<[FocusId; 8]> {
909 self.focus
910 .map(|focus_id| self.dispatch_tree.focus_path(focus_id))
911 .unwrap_or_default()
912 }
913
914 pub(crate) fn finish(&mut self, prev_frame: &mut Self) {
915 for element_state_key in &self.accessed_element_states {
916 if let Some((element_state_key, element_state)) =
917 prev_frame.element_states.remove_entry(element_state_key)
918 {
919 self.element_states.insert(element_state_key, element_state);
920 }
921 }
922
923 self.scene.finish();
924 }
925}
926
927#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
928enum InputModality {
929 Mouse,
930 Keyboard,
931}
932
933/// Holds the state for a specific window.
934pub struct Window {
935 pub(crate) handle: AnyWindowHandle,
936 pub(crate) invalidator: WindowInvalidator,
937 pub(crate) removed: bool,
938 pub(crate) platform_window: Box<dyn PlatformWindow>,
939 display_id: Option<DisplayId>,
940 sprite_atlas: Arc<dyn PlatformAtlas>,
941 text_system: Arc<WindowTextSystem>,
942 text_rendering_mode: Rc<Cell<TextRenderingMode>>,
943 rem_size: Pixels,
944 /// The stack of override values for the window's rem size.
945 ///
946 /// This is used by `with_rem_size` to allow rendering an element tree with
947 /// a given rem size.
948 rem_size_override_stack: SmallVec<[Pixels; 8]>,
949 pub(crate) viewport_size: Size<Pixels>,
950 layout_engine: Option<TaffyLayoutEngine>,
951 pub(crate) root: Option<AnyView>,
952 pub(crate) element_id_stack: SmallVec<[ElementId; 32]>,
953 pub(crate) text_style_stack: Vec<TextStyleRefinement>,
954 pub(crate) rendered_entity_stack: Vec<EntityId>,
955 pub(crate) element_offset_stack: Vec<Point<Pixels>>,
956 pub(crate) element_opacity: f32,
957 pub(crate) content_mask_stack: Vec<ContentMask<Pixels>>,
958 pub(crate) requested_autoscroll: Option<Bounds<Pixels>>,
959 pub(crate) image_cache_stack: Vec<AnyImageCache>,
960 pub(crate) rendered_frame: Frame,
961 pub(crate) next_frame: Frame,
962 next_hitbox_id: HitboxId,
963 pub(crate) next_tooltip_id: TooltipId,
964 pub(crate) tooltip_bounds: Option<TooltipBounds>,
965 next_frame_callbacks: Rc<RefCell<Vec<FrameCallback>>>,
966 pub(crate) dirty_views: FxHashSet<EntityId>,
967 focus_listeners: SubscriberSet<(), AnyWindowFocusListener>,
968 pub(crate) focus_lost_listeners: SubscriberSet<(), AnyObserver>,
969 default_prevented: bool,
970 mouse_position: Point<Pixels>,
971 mouse_hit_test: HitTest,
972 modifiers: Modifiers,
973 capslock: Capslock,
974 scale_factor: f32,
975 pub(crate) bounds_observers: SubscriberSet<(), AnyObserver>,
976 appearance: WindowAppearance,
977 pub(crate) appearance_observers: SubscriberSet<(), AnyObserver>,
978 pub(crate) button_layout_observers: SubscriberSet<(), AnyObserver>,
979 active: Rc<Cell<bool>>,
980 hovered: Rc<Cell<bool>>,
981 pub(crate) needs_present: Rc<Cell<bool>>,
982 /// Tracks recent input event timestamps to determine if input is arriving at a high rate.
983 /// Used to selectively enable VRR optimization only when input rate exceeds 60fps.
984 pub(crate) input_rate_tracker: Rc<RefCell<InputRateTracker>>,
985 #[cfg(feature = "input-latency-histogram")]
986 input_latency_tracker: InputLatencyTracker,
987 last_input_modality: InputModality,
988 pub(crate) refreshing: bool,
989 pub(crate) activation_observers: SubscriberSet<(), AnyObserver>,
990 pub(crate) focus: Option<FocusId>,
991 focus_enabled: bool,
992 pending_input: Option<PendingInput>,
993 pending_modifier: ModifierState,
994 pub(crate) pending_input_observers: SubscriberSet<(), AnyObserver>,
995 prompt: Option<RenderablePromptHandle>,
996 pub(crate) client_inset: Option<Pixels>,
997 /// The hitbox that has captured the pointer, if any.
998 /// While captured, mouse events route to this hitbox regardless of hit testing.
999 captured_hitbox: Option<HitboxId>,
1000 #[cfg(any(feature = "inspector", debug_assertions))]
1001 inspector: Option<Entity<Inspector>>,
1002}
1003
1004#[derive(Clone, Debug, Default)]
1005struct ModifierState {
1006 modifiers: Modifiers,
1007 saw_keystroke: bool,
1008}
1009
1010/// Tracks input event timestamps to determine if input is arriving at a high rate.
1011/// Used for selective VRR (Variable Refresh Rate) optimization.
1012#[derive(Clone, Debug)]
1013pub(crate) struct InputRateTracker {
1014 timestamps: Vec<Instant>,
1015 window: Duration,
1016 inputs_per_second: u32,
1017 sustain_until: Instant,
1018 sustain_duration: Duration,
1019}
1020
1021impl Default for InputRateTracker {
1022 fn default() -> Self {
1023 Self {
1024 timestamps: Vec::new(),
1025 window: Duration::from_millis(100),
1026 inputs_per_second: 60,
1027 sustain_until: Instant::now(),
1028 sustain_duration: Duration::from_secs(1),
1029 }
1030 }
1031}
1032
1033impl InputRateTracker {
1034 pub fn record_input(&mut self) {
1035 let now = Instant::now();
1036 self.timestamps.push(now);
1037 self.prune_old_timestamps(now);
1038
1039 let min_events = self.inputs_per_second as u128 * self.window.as_millis() / 1000;
1040 if self.timestamps.len() as u128 >= min_events {
1041 self.sustain_until = now + self.sustain_duration;
1042 }
1043 }
1044
1045 pub fn is_high_rate(&self) -> bool {
1046 Instant::now() < self.sustain_until
1047 }
1048
1049 fn prune_old_timestamps(&mut self, now: Instant) {
1050 self.timestamps
1051 .retain(|&t| now.duration_since(t) <= self.window);
1052 }
1053}
1054
1055/// A point-in-time snapshot of the input-latency histograms for a window,
1056/// suitable for external formatting.
1057#[cfg(feature = "input-latency-histogram")]
1058pub struct InputLatencySnapshot {
1059 /// Histogram of input-to-frame latency samples, in nanoseconds.
1060 pub latency_histogram: Histogram<u64>,
1061 /// Histogram of input events coalesced per rendered frame.
1062 pub events_per_frame_histogram: Histogram<u64>,
1063 /// Count of input events that arrived mid-draw and were excluded from
1064 /// latency recording.
1065 pub mid_draw_events_dropped: u64,
1066}
1067
1068/// Records the time between when the first input event in a frame is dispatched
1069/// and when the resulting frame is presented, capturing worst-case latency when
1070/// multiple events are coalesced into a single frame.
1071#[cfg(feature = "input-latency-histogram")]
1072struct InputLatencyTracker {
1073 /// Timestamp of the first unrendered input event in the current frame;
1074 /// cleared when a frame is presented.
1075 first_input_at: Option<Instant>,
1076 /// Count of input events received since the last frame was presented.
1077 pending_input_count: u64,
1078 /// Histogram of input-to-frame latency samples, in nanoseconds.
1079 latency_histogram: Histogram<u64>,
1080 /// Histogram of input events coalesced per rendered frame.
1081 events_per_frame_histogram: Histogram<u64>,
1082 /// Count of input events that arrived mid-draw and were excluded from
1083 /// latency recording because their effects won't appear until the next frame.
1084 mid_draw_events_dropped: u64,
1085}
1086
1087#[cfg(feature = "input-latency-histogram")]
1088impl InputLatencyTracker {
1089 fn new() -> Result<Self> {
1090 Ok(Self {
1091 first_input_at: None,
1092 pending_input_count: 0,
1093 latency_histogram: Histogram::new(3)
1094 .map_err(|e| anyhow!("Failed to create input latency histogram: {e}"))?,
1095 events_per_frame_histogram: Histogram::new(3)
1096 .map_err(|e| anyhow!("Failed to create events per frame histogram: {e}"))?,
1097 mid_draw_events_dropped: 0,
1098 })
1099 }
1100
1101 /// Record that an input event was dispatched at the given time.
1102 /// Only the first event's timestamp per frame is retained (worst-case latency).
1103 fn record_input(&mut self, dispatch_time: Instant) {
1104 self.first_input_at.get_or_insert(dispatch_time);
1105 self.pending_input_count += 1;
1106 }
1107
1108 /// Record that an input event arrived during a draw phase and was excluded
1109 /// from latency tracking.
1110 fn record_mid_draw_input(&mut self) {
1111 self.mid_draw_events_dropped += 1;
1112 }
1113
1114 /// Record that a frame was presented, flushing pending latency and coalescing samples.
1115 fn record_frame_presented(&mut self) {
1116 if let Some(first_input_at) = self.first_input_at.take() {
1117 let latency_nanos = first_input_at.elapsed().as_nanos() as u64;
1118 self.latency_histogram.record(latency_nanos).ok();
1119 }
1120 if self.pending_input_count > 0 {
1121 self.events_per_frame_histogram
1122 .record(self.pending_input_count)
1123 .ok();
1124 self.pending_input_count = 0;
1125 }
1126 }
1127
1128 fn snapshot(&self) -> InputLatencySnapshot {
1129 InputLatencySnapshot {
1130 latency_histogram: self.latency_histogram.clone(),
1131 events_per_frame_histogram: self.events_per_frame_histogram.clone(),
1132 mid_draw_events_dropped: self.mid_draw_events_dropped,
1133 }
1134 }
1135}
1136
1137#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1138pub(crate) enum DrawPhase {
1139 None,
1140 Prepaint,
1141 Paint,
1142 Focus,
1143}
1144
1145#[derive(Default, Debug)]
1146struct PendingInput {
1147 keystrokes: SmallVec<[Keystroke; 1]>,
1148 focus: Option<FocusId>,
1149 timer: Option<Task<()>>,
1150 needs_timeout: bool,
1151}
1152
1153pub(crate) struct ElementStateBox {
1154 pub(crate) inner: Box<dyn Any>,
1155 #[cfg(debug_assertions)]
1156 pub(crate) type_name: &'static str,
1157}
1158
1159fn default_bounds(display_id: Option<DisplayId>, cx: &mut App) -> WindowBounds {
1160 // TODO, BUG: if you open a window with the currently active window
1161 // on the stack, this will erroneously fallback to `None`
1162 //
1163 // TODO these should be the initial window bounds not considering maximized/fullscreen
1164 let active_window_bounds = cx
1165 .active_window()
1166 .and_then(|w| w.update(cx, |_, window, _| window.window_bounds()).ok());
1167
1168 const CASCADE_OFFSET: f32 = 25.0;
1169
1170 let display = display_id
1171 .map(|id| cx.find_display(id))
1172 .unwrap_or_else(|| cx.primary_display());
1173
1174 let default_placement = || Bounds::new(point(px(0.), px(0.)), DEFAULT_WINDOW_SIZE);
1175
1176 // Use visible_bounds to exclude taskbar/dock areas
1177 let display_bounds = display
1178 .as_ref()
1179 .map(|d| d.visible_bounds())
1180 .unwrap_or_else(default_placement);
1181
1182 let (
1183 Bounds {
1184 origin: base_origin,
1185 size: base_size,
1186 },
1187 window_bounds_ctor,
1188 ): (_, fn(Bounds<Pixels>) -> WindowBounds) = match active_window_bounds {
1189 Some(bounds) => match bounds {
1190 WindowBounds::Windowed(bounds) => (bounds, WindowBounds::Windowed),
1191 WindowBounds::Maximized(bounds) => (bounds, WindowBounds::Maximized),
1192 WindowBounds::Fullscreen(bounds) => (bounds, WindowBounds::Fullscreen),
1193 },
1194 None => (
1195 display
1196 .as_ref()
1197 .map(|d| d.default_bounds())
1198 .unwrap_or_else(default_placement),
1199 WindowBounds::Windowed,
1200 ),
1201 };
1202
1203 let cascade_offset = point(px(CASCADE_OFFSET), px(CASCADE_OFFSET));
1204 let proposed_origin = base_origin + cascade_offset;
1205 let proposed_bounds = Bounds::new(proposed_origin, base_size);
1206
1207 let display_right = display_bounds.origin.x + display_bounds.size.width;
1208 let display_bottom = display_bounds.origin.y + display_bounds.size.height;
1209 let window_right = proposed_bounds.origin.x + proposed_bounds.size.width;
1210 let window_bottom = proposed_bounds.origin.y + proposed_bounds.size.height;
1211
1212 let fits_horizontally = window_right <= display_right;
1213 let fits_vertically = window_bottom <= display_bottom;
1214
1215 let final_origin = match (fits_horizontally, fits_vertically) {
1216 (true, true) => proposed_origin,
1217 (false, true) => point(display_bounds.origin.x, base_origin.y),
1218 (true, false) => point(base_origin.x, display_bounds.origin.y),
1219 (false, false) => display_bounds.origin,
1220 };
1221 window_bounds_ctor(Bounds::new(final_origin, base_size))
1222}
1223
1224impl Window {
1225 pub(crate) fn new(
1226 handle: AnyWindowHandle,
1227 options: WindowOptions,
1228 cx: &mut App,
1229 ) -> Result<Self> {
1230 let WindowOptions {
1231 window_bounds,
1232 titlebar,
1233 focus,
1234 show,
1235 kind,
1236 is_movable,
1237 is_resizable,
1238 is_minimizable,
1239 display_id,
1240 window_background,
1241 app_id,
1242 window_min_size,
1243 window_decorations,
1244 #[cfg_attr(
1245 not(any(target_os = "linux", target_os = "freebsd")),
1246 allow(unused_variables)
1247 )]
1248 icon,
1249 #[cfg_attr(not(target_os = "macos"), allow(unused_variables))]
1250 tabbing_identifier,
1251 } = options;
1252
1253 let window_bounds = window_bounds.unwrap_or_else(|| default_bounds(display_id, cx));
1254 let mut platform_window = cx.platform.open_window(
1255 handle,
1256 WindowParams {
1257 bounds: window_bounds.get_bounds(),
1258 titlebar,
1259 kind,
1260 is_movable,
1261 is_resizable,
1262 is_minimizable,
1263 focus,
1264 show,
1265 display_id,
1266 window_min_size,
1267 icon,
1268 #[cfg(target_os = "macos")]
1269 tabbing_identifier,
1270 },
1271 )?;
1272
1273 let tab_bar_visible = platform_window.tab_bar_visible();
1274 SystemWindowTabController::init_visible(cx, tab_bar_visible);
1275 if let Some(tabs) = platform_window.tabbed_windows() {
1276 SystemWindowTabController::add_tab(cx, handle.window_id(), tabs);
1277 }
1278
1279 let display_id = platform_window.display().map(|display| display.id());
1280 let sprite_atlas = platform_window.sprite_atlas();
1281 let mouse_position = platform_window.mouse_position();
1282 let modifiers = platform_window.modifiers();
1283 let capslock = platform_window.capslock();
1284 let content_size = platform_window.content_size();
1285 let scale_factor = platform_window.scale_factor();
1286 let appearance = platform_window.appearance();
1287 let text_system = Arc::new(WindowTextSystem::new(cx.text_system().clone()));
1288 let invalidator = WindowInvalidator::new();
1289 let active = Rc::new(Cell::new(platform_window.is_active()));
1290 let hovered = Rc::new(Cell::new(platform_window.is_hovered()));
1291 let needs_present = Rc::new(Cell::new(false));
1292 let next_frame_callbacks: Rc<RefCell<Vec<FrameCallback>>> = Default::default();
1293 let input_rate_tracker = Rc::new(RefCell::new(InputRateTracker::default()));
1294 let last_frame_time = Rc::new(Cell::new(None));
1295
1296 platform_window
1297 .request_decorations(window_decorations.unwrap_or(WindowDecorations::Server));
1298 platform_window.set_background_appearance(window_background);
1299
1300 match window_bounds {
1301 WindowBounds::Fullscreen(_) => platform_window.toggle_fullscreen(),
1302 WindowBounds::Maximized(_) => platform_window.zoom(),
1303 WindowBounds::Windowed(_) => {}
1304 }
1305
1306 platform_window.on_close(Box::new({
1307 let window_id = handle.window_id();
1308 let mut cx = cx.to_async();
1309 move || {
1310 let _ = handle.update(&mut cx, |_, window, _| window.remove_window());
1311 let _ = cx.update(|cx| {
1312 SystemWindowTabController::remove_tab(cx, window_id);
1313 });
1314 }
1315 }));
1316 platform_window.on_request_frame(Box::new({
1317 let mut cx = cx.to_async();
1318 let invalidator = invalidator.clone();
1319 let active = active.clone();
1320 let needs_present = needs_present.clone();
1321 let next_frame_callbacks = next_frame_callbacks.clone();
1322 let input_rate_tracker = input_rate_tracker.clone();
1323 move |request_frame_options| {
1324 let thermal_state = handle
1325 .update(&mut cx, |_, _, cx| cx.thermal_state())
1326 .log_err();
1327
1328 // Throttle frame rate based on conditions:
1329 // - Thermal pressure (Serious/Critical): cap to ~60fps
1330 // - Inactive window (not focused): cap to ~30fps to save energy
1331 let min_frame_interval = if !request_frame_options.force_render
1332 && !request_frame_options.require_presentation
1333 && next_frame_callbacks.borrow().is_empty()
1334 {
1335 None
1336 } else if !active.get() {
1337 Some(Duration::from_micros(33333))
1338 } else if let Some(ThermalState::Critical | ThermalState::Serious) = thermal_state {
1339 Some(Duration::from_micros(16667))
1340 } else {
1341 None
1342 };
1343
1344 let now = Instant::now();
1345 if let Some(min_interval) = min_frame_interval {
1346 if let Some(last_frame) = last_frame_time.get()
1347 && now.duration_since(last_frame) < min_interval
1348 {
1349 // Must still complete the frame on platforms that require it.
1350 // On Wayland, `surface.frame()` was already called to request the
1351 // next frame callback, so we must call `surface.commit()` (via
1352 // `complete_frame`) or the compositor won't send another callback.
1353 handle
1354 .update(&mut cx, |_, window, _| window.complete_frame())
1355 .log_err();
1356 return;
1357 }
1358 }
1359 last_frame_time.set(Some(now));
1360
1361 let next_frame_callbacks = next_frame_callbacks.take();
1362 if !next_frame_callbacks.is_empty() {
1363 handle
1364 .update(&mut cx, |_, window, cx| {
1365 for callback in next_frame_callbacks {
1366 callback(window, cx);
1367 }
1368 })
1369 .log_err();
1370 }
1371
1372 // Keep presenting if input was recently arriving at a high rate (>= 60fps).
1373 // Once high-rate input is detected, we sustain presentation for 1 second
1374 // to prevent display underclocking during active input.
1375 let needs_present = request_frame_options.require_presentation
1376 || needs_present.get()
1377 || (active.get() && input_rate_tracker.borrow_mut().is_high_rate());
1378
1379 if invalidator.is_dirty() || request_frame_options.force_render {
1380 measure("frame duration", || {
1381 handle
1382 .update(&mut cx, |_, window, cx| {
1383 let arena_clear_needed = window.draw(cx);
1384 window.present();
1385 arena_clear_needed.clear();
1386 })
1387 .log_err();
1388 })
1389 } else if needs_present {
1390 handle
1391 .update(&mut cx, |_, window, _| window.present())
1392 .log_err();
1393 }
1394
1395 handle
1396 .update(&mut cx, |_, window, _| {
1397 window.complete_frame();
1398 })
1399 .log_err();
1400 }
1401 }));
1402 platform_window.on_resize(Box::new({
1403 let mut cx = cx.to_async();
1404 move |_, _| {
1405 handle
1406 .update(&mut cx, |_, window, cx| window.bounds_changed(cx))
1407 .log_err();
1408 }
1409 }));
1410 platform_window.on_moved(Box::new({
1411 let mut cx = cx.to_async();
1412 move || {
1413 handle
1414 .update(&mut cx, |_, window, cx| window.bounds_changed(cx))
1415 .log_err();
1416 }
1417 }));
1418 platform_window.on_appearance_changed(Box::new({
1419 let mut cx = cx.to_async();
1420 move || {
1421 handle
1422 .update(&mut cx, |_, window, cx| window.appearance_changed(cx))
1423 .log_err();
1424 }
1425 }));
1426 platform_window.on_button_layout_changed(Box::new({
1427 let mut cx = cx.to_async();
1428 move || {
1429 handle
1430 .update(&mut cx, |_, window, cx| window.button_layout_changed(cx))
1431 .log_err();
1432 }
1433 }));
1434 platform_window.on_active_status_change(Box::new({
1435 let mut cx = cx.to_async();
1436 move |active| {
1437 handle
1438 .update(&mut cx, |_, window, cx| {
1439 window.active.set(active);
1440 window.modifiers = window.platform_window.modifiers();
1441 window.capslock = window.platform_window.capslock();
1442 window
1443 .activation_observers
1444 .clone()
1445 .retain(&(), |callback| callback(window, cx));
1446
1447 window.bounds_changed(cx);
1448 window.refresh();
1449
1450 SystemWindowTabController::update_last_active(cx, window.handle.id);
1451 })
1452 .log_err();
1453 }
1454 }));
1455 platform_window.on_hover_status_change(Box::new({
1456 let mut cx = cx.to_async();
1457 move |active| {
1458 handle
1459 .update(&mut cx, |_, window, _| {
1460 window.hovered.set(active);
1461 window.refresh();
1462 })
1463 .log_err();
1464 }
1465 }));
1466 platform_window.on_input({
1467 let mut cx = cx.to_async();
1468 Box::new(move |event| {
1469 handle
1470 .update(&mut cx, |_, window, cx| window.dispatch_event(event, cx))
1471 .log_err()
1472 .unwrap_or(DispatchEventResult::default())
1473 })
1474 });
1475 platform_window.on_hit_test_window_control({
1476 let mut cx = cx.to_async();
1477 Box::new(move || {
1478 handle
1479 .update(&mut cx, |_, window, _cx| {
1480 for (area, hitbox) in &window.rendered_frame.window_control_hitboxes {
1481 if window.mouse_hit_test.ids.contains(&hitbox.id) {
1482 return Some(*area);
1483 }
1484 }
1485 None
1486 })
1487 .log_err()
1488 .unwrap_or(None)
1489 })
1490 });
1491 platform_window.on_move_tab_to_new_window({
1492 let mut cx = cx.to_async();
1493 Box::new(move || {
1494 handle
1495 .update(&mut cx, |_, _window, cx| {
1496 SystemWindowTabController::move_tab_to_new_window(cx, handle.window_id());
1497 })
1498 .log_err();
1499 })
1500 });
1501 platform_window.on_merge_all_windows({
1502 let mut cx = cx.to_async();
1503 Box::new(move || {
1504 handle
1505 .update(&mut cx, |_, _window, cx| {
1506 SystemWindowTabController::merge_all_windows(cx, handle.window_id());
1507 })
1508 .log_err();
1509 })
1510 });
1511 platform_window.on_select_next_tab({
1512 let mut cx = cx.to_async();
1513 Box::new(move || {
1514 handle
1515 .update(&mut cx, |_, _window, cx| {
1516 SystemWindowTabController::select_next_tab(cx, handle.window_id());
1517 })
1518 .log_err();
1519 })
1520 });
1521 platform_window.on_select_previous_tab({
1522 let mut cx = cx.to_async();
1523 Box::new(move || {
1524 handle
1525 .update(&mut cx, |_, _window, cx| {
1526 SystemWindowTabController::select_previous_tab(cx, handle.window_id())
1527 })
1528 .log_err();
1529 })
1530 });
1531 platform_window.on_toggle_tab_bar({
1532 let mut cx = cx.to_async();
1533 Box::new(move || {
1534 handle
1535 .update(&mut cx, |_, window, cx| {
1536 let tab_bar_visible = window.platform_window.tab_bar_visible();
1537 SystemWindowTabController::set_visible(cx, tab_bar_visible);
1538 })
1539 .log_err();
1540 })
1541 });
1542
1543 if let Some(app_id) = app_id {
1544 platform_window.set_app_id(&app_id);
1545 }
1546
1547 platform_window.map_window().unwrap();
1548
1549 Ok(Window {
1550 handle,
1551 invalidator,
1552 removed: false,
1553 platform_window,
1554 display_id,
1555 sprite_atlas,
1556 text_system,
1557 text_rendering_mode: cx.text_rendering_mode.clone(),
1558 rem_size: px(16.),
1559 rem_size_override_stack: SmallVec::new(),
1560 viewport_size: content_size,
1561 layout_engine: Some(TaffyLayoutEngine::new()),
1562 root: None,
1563 element_id_stack: SmallVec::default(),
1564 text_style_stack: Vec::new(),
1565 rendered_entity_stack: Vec::new(),
1566 element_offset_stack: Vec::new(),
1567 content_mask_stack: Vec::new(),
1568 element_opacity: 1.0,
1569 requested_autoscroll: None,
1570 rendered_frame: Frame::new(DispatchTree::new(cx.keymap.clone(), cx.actions.clone())),
1571 next_frame: Frame::new(DispatchTree::new(cx.keymap.clone(), cx.actions.clone())),
1572 next_frame_callbacks,
1573 next_hitbox_id: HitboxId(0),
1574 next_tooltip_id: TooltipId::default(),
1575 tooltip_bounds: None,
1576 dirty_views: FxHashSet::default(),
1577 focus_listeners: SubscriberSet::new(),
1578 focus_lost_listeners: SubscriberSet::new(),
1579 default_prevented: true,
1580 mouse_position,
1581 mouse_hit_test: HitTest::default(),
1582 modifiers,
1583 capslock,
1584 scale_factor,
1585 bounds_observers: SubscriberSet::new(),
1586 appearance,
1587 appearance_observers: SubscriberSet::new(),
1588 button_layout_observers: SubscriberSet::new(),
1589 active,
1590 hovered,
1591 needs_present,
1592 input_rate_tracker,
1593 #[cfg(feature = "input-latency-histogram")]
1594 input_latency_tracker: InputLatencyTracker::new()?,
1595 last_input_modality: InputModality::Mouse,
1596 refreshing: false,
1597 activation_observers: SubscriberSet::new(),
1598 focus: None,
1599 focus_enabled: true,
1600 pending_input: None,
1601 pending_modifier: ModifierState::default(),
1602 pending_input_observers: SubscriberSet::new(),
1603 prompt: None,
1604 client_inset: None,
1605 image_cache_stack: Vec::new(),
1606 captured_hitbox: None,
1607 #[cfg(any(feature = "inspector", debug_assertions))]
1608 inspector: None,
1609 })
1610 }
1611
1612 pub(crate) fn new_focus_listener(
1613 &self,
1614 value: AnyWindowFocusListener,
1615 ) -> (Subscription, impl FnOnce() + use<>) {
1616 self.focus_listeners.insert((), value)
1617 }
1618}
1619
1620#[derive(Clone, Debug, Default, PartialEq, Eq)]
1621#[expect(missing_docs)]
1622pub struct DispatchEventResult {
1623 pub propagate: bool,
1624 pub default_prevented: bool,
1625}
1626
1627/// Indicates which region of the window is visible. Content falling outside of this mask will not be
1628/// rendered. Currently, only rectangular content masks are supported, but we give the mask its own type
1629/// to leave room to support more complex shapes in the future.
1630#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
1631#[repr(C)]
1632pub struct ContentMask<P: Clone + Debug + Default + PartialEq> {
1633 /// The bounds
1634 pub bounds: Bounds<P>,
1635}
1636
1637impl ContentMask<Pixels> {
1638 /// Scale the content mask's pixel units by the given scaling factor.
1639 pub fn scale(&self, factor: f32) -> ContentMask<ScaledPixels> {
1640 ContentMask {
1641 bounds: self.bounds.scale(factor),
1642 }
1643 }
1644
1645 /// Intersect the content mask with the given content mask.
1646 pub fn intersect(&self, other: &Self) -> Self {
1647 let bounds = self.bounds.intersect(&other.bounds);
1648 ContentMask { bounds }
1649 }
1650}
1651
1652impl Window {
1653 fn mark_view_dirty(&mut self, view_id: EntityId) {
1654 // Mark ancestor views as dirty. If already in the `dirty_views` set, then all its ancestors
1655 // should already be dirty.
1656 for view_id in self
1657 .rendered_frame
1658 .dispatch_tree
1659 .view_path_reversed(view_id)
1660 {
1661 if !self.dirty_views.insert(view_id) {
1662 break;
1663 }
1664 }
1665 }
1666
1667 /// Registers a callback to be invoked when the window appearance changes.
1668 pub fn observe_window_appearance(
1669 &self,
1670 mut callback: impl FnMut(&mut Window, &mut App) + 'static,
1671 ) -> Subscription {
1672 let (subscription, activate) = self.appearance_observers.insert(
1673 (),
1674 Box::new(move |window, cx| {
1675 callback(window, cx);
1676 true
1677 }),
1678 );
1679 activate();
1680 subscription
1681 }
1682
1683 /// Registers a callback to be invoked when the window button layout changes.
1684 pub fn observe_button_layout_changed(
1685 &self,
1686 mut callback: impl FnMut(&mut Window, &mut App) + 'static,
1687 ) -> Subscription {
1688 let (subscription, activate) = self.button_layout_observers.insert(
1689 (),
1690 Box::new(move |window, cx| {
1691 callback(window, cx);
1692 true
1693 }),
1694 );
1695 activate();
1696 subscription
1697 }
1698
1699 /// Replaces the root entity of the window with a new one.
1700 pub fn replace_root<E>(
1701 &mut self,
1702 cx: &mut App,
1703 build_view: impl FnOnce(&mut Window, &mut Context<E>) -> E,
1704 ) -> Entity<E>
1705 where
1706 E: 'static + Render,
1707 {
1708 let view = cx.new(|cx| build_view(self, cx));
1709 self.root = Some(view.clone().into());
1710 self.refresh();
1711 view
1712 }
1713
1714 /// Returns the root entity of the window, if it has one.
1715 pub fn root<E>(&self) -> Option<Option<Entity<E>>>
1716 where
1717 E: 'static + Render,
1718 {
1719 self.root
1720 .as_ref()
1721 .map(|view| view.clone().downcast::<E>().ok())
1722 }
1723
1724 /// Obtain a handle to the window that belongs to this context.
1725 pub fn window_handle(&self) -> AnyWindowHandle {
1726 self.handle
1727 }
1728
1729 /// Mark the window as dirty, scheduling it to be redrawn on the next frame.
1730 pub fn refresh(&mut self) {
1731 if self.invalidator.not_drawing() {
1732 self.refreshing = true;
1733 self.invalidator.set_dirty(true);
1734 }
1735 }
1736
1737 /// Close this window.
1738 pub fn remove_window(&mut self) {
1739 self.removed = true;
1740 }
1741
1742 /// Obtain the currently focused [`FocusHandle`]. If no elements are focused, returns `None`.
1743 pub fn focused(&self, cx: &App) -> Option<FocusHandle> {
1744 self.focus
1745 .and_then(|id| FocusHandle::for_id(id, &cx.focus_handles))
1746 }
1747
1748 /// Move focus to the element associated with the given [`FocusHandle`].
1749 pub fn focus(&mut self, handle: &FocusHandle, cx: &mut App) {
1750 if !self.focus_enabled || self.focus == Some(handle.id) {
1751 return;
1752 }
1753
1754 self.focus = Some(handle.id);
1755 self.clear_pending_keystrokes();
1756
1757 // Avoid re-entrant entity updates by deferring observer notifications to the end of the
1758 // current effect cycle, and only for this window.
1759 let window_handle = self.handle;
1760 cx.defer(move |cx| {
1761 window_handle
1762 .update(cx, |_, window, cx| {
1763 window.pending_input_changed(cx);
1764 })
1765 .ok();
1766 });
1767
1768 self.refresh();
1769 }
1770
1771 /// Remove focus from all elements within this context's window.
1772 pub fn blur(&mut self) {
1773 if !self.focus_enabled {
1774 return;
1775 }
1776
1777 self.focus = None;
1778 self.refresh();
1779 }
1780
1781 /// Blur the window and don't allow anything in it to be focused again.
1782 pub fn disable_focus(&mut self) {
1783 self.blur();
1784 self.focus_enabled = false;
1785 }
1786
1787 /// Move focus to next tab stop.
1788 pub fn focus_next(&mut self, cx: &mut App) {
1789 if !self.focus_enabled {
1790 return;
1791 }
1792
1793 if let Some(handle) = self.rendered_frame.tab_stops.next(self.focus.as_ref()) {
1794 self.focus(&handle, cx)
1795 }
1796 }
1797
1798 /// Move focus to previous tab stop.
1799 pub fn focus_prev(&mut self, cx: &mut App) {
1800 if !self.focus_enabled {
1801 return;
1802 }
1803
1804 if let Some(handle) = self.rendered_frame.tab_stops.prev(self.focus.as_ref()) {
1805 self.focus(&handle, cx)
1806 }
1807 }
1808
1809 /// Accessor for the text system.
1810 pub fn text_system(&self) -> &Arc<WindowTextSystem> {
1811 &self.text_system
1812 }
1813
1814 /// The current text style. Which is composed of all the style refinements provided to `with_text_style`.
1815 pub fn text_style(&self) -> TextStyle {
1816 let mut style = TextStyle::default();
1817 for refinement in &self.text_style_stack {
1818 style.refine(refinement);
1819 }
1820 style
1821 }
1822
1823 /// Check if the platform window is maximized.
1824 ///
1825 /// On some platforms (namely Windows) this is different than the bounds being the size of the display
1826 pub fn is_maximized(&self) -> bool {
1827 self.platform_window.is_maximized()
1828 }
1829
1830 /// request a certain window decoration (Wayland)
1831 pub fn request_decorations(&self, decorations: WindowDecorations) {
1832 self.platform_window.request_decorations(decorations);
1833 }
1834
1835 /// Start a window resize operation (Wayland)
1836 pub fn start_window_resize(&self, edge: ResizeEdge) {
1837 self.platform_window.start_window_resize(edge);
1838 }
1839
1840 /// Return the `WindowBounds` to indicate that how a window should be opened
1841 /// after it has been closed
1842 pub fn window_bounds(&self) -> WindowBounds {
1843 self.platform_window.window_bounds()
1844 }
1845
1846 /// Return the `WindowBounds` excluding insets (Wayland and X11)
1847 pub fn inner_window_bounds(&self) -> WindowBounds {
1848 self.platform_window.inner_window_bounds()
1849 }
1850
1851 /// Dispatch the given action on the currently focused element.
1852 pub fn dispatch_action(&mut self, action: Box<dyn Action>, cx: &mut App) {
1853 let focus_id = self.focused(cx).map(|handle| handle.id);
1854
1855 let window = self.handle;
1856 cx.defer(move |cx| {
1857 window
1858 .update(cx, |_, window, cx| {
1859 let node_id = window.focus_node_id_in_rendered_frame(focus_id);
1860 window.dispatch_action_on_node(node_id, action.as_ref(), cx);
1861 })
1862 .log_err();
1863 })
1864 }
1865
1866 pub(crate) fn dispatch_keystroke_observers(
1867 &mut self,
1868 event: &dyn Any,
1869 action: Option<Box<dyn Action>>,
1870 context_stack: Vec<KeyContext>,
1871 cx: &mut App,
1872 ) {
1873 let Some(key_down_event) = event.downcast_ref::<KeyDownEvent>() else {
1874 return;
1875 };
1876
1877 cx.keystroke_observers.clone().retain(&(), move |callback| {
1878 (callback)(
1879 &KeystrokeEvent {
1880 keystroke: key_down_event.keystroke.clone(),
1881 action: action.as_ref().map(|action| action.boxed_clone()),
1882 context_stack: context_stack.clone(),
1883 },
1884 self,
1885 cx,
1886 )
1887 });
1888 }
1889
1890 pub(crate) fn dispatch_keystroke_interceptors(
1891 &mut self,
1892 event: &dyn Any,
1893 context_stack: Vec<KeyContext>,
1894 cx: &mut App,
1895 ) {
1896 let Some(key_down_event) = event.downcast_ref::<KeyDownEvent>() else {
1897 return;
1898 };
1899
1900 cx.keystroke_interceptors
1901 .clone()
1902 .retain(&(), move |callback| {
1903 (callback)(
1904 &KeystrokeEvent {
1905 keystroke: key_down_event.keystroke.clone(),
1906 action: None,
1907 context_stack: context_stack.clone(),
1908 },
1909 self,
1910 cx,
1911 )
1912 });
1913 }
1914
1915 /// Schedules the given function to be run at the end of the current effect cycle, allowing entities
1916 /// that are currently on the stack to be returned to the app.
1917 pub fn defer(&self, cx: &mut App, f: impl FnOnce(&mut Window, &mut App) + 'static) {
1918 let handle = self.handle;
1919 cx.defer(move |cx| {
1920 handle.update(cx, |_, window, cx| f(window, cx)).ok();
1921 });
1922 }
1923
1924 /// Subscribe to events emitted by a entity.
1925 /// The entity to which you're subscribing must implement the [`EventEmitter`] trait.
1926 /// The callback will be invoked a handle to the emitting entity, the event, and a window context for the current window.
1927 pub fn observe<T: 'static>(
1928 &mut self,
1929 observed: &Entity<T>,
1930 cx: &mut App,
1931 mut on_notify: impl FnMut(Entity<T>, &mut Window, &mut App) + 'static,
1932 ) -> Subscription {
1933 let entity_id = observed.entity_id();
1934 let observed = observed.downgrade();
1935 let window_handle = self.handle;
1936 cx.new_observer(
1937 entity_id,
1938 Box::new(move |cx| {
1939 window_handle
1940 .update(cx, |_, window, cx| {
1941 if let Some(handle) = observed.upgrade() {
1942 on_notify(handle, window, cx);
1943 true
1944 } else {
1945 false
1946 }
1947 })
1948 .unwrap_or(false)
1949 }),
1950 )
1951 }
1952
1953 /// Subscribe to events emitted by a entity.
1954 /// The entity to which you're subscribing must implement the [`EventEmitter`] trait.
1955 /// The callback will be invoked a handle to the emitting entity, the event, and a window context for the current window.
1956 pub fn subscribe<Emitter, Evt>(
1957 &mut self,
1958 entity: &Entity<Emitter>,
1959 cx: &mut App,
1960 mut on_event: impl FnMut(Entity<Emitter>, &Evt, &mut Window, &mut App) + 'static,
1961 ) -> Subscription
1962 where
1963 Emitter: EventEmitter<Evt>,
1964 Evt: 'static,
1965 {
1966 let entity_id = entity.entity_id();
1967 let handle = entity.downgrade();
1968 let window_handle = self.handle;
1969 cx.new_subscription(
1970 entity_id,
1971 (
1972 TypeId::of::<Evt>(),
1973 Box::new(move |event, cx| {
1974 window_handle
1975 .update(cx, |_, window, cx| {
1976 if let Some(entity) = handle.upgrade() {
1977 let event = event.downcast_ref().expect("invalid event type");
1978 on_event(entity, event, window, cx);
1979 true
1980 } else {
1981 false
1982 }
1983 })
1984 .unwrap_or(false)
1985 }),
1986 ),
1987 )
1988 }
1989
1990 /// Register a callback to be invoked when the given `Entity` is released.
1991 pub fn observe_release<T>(
1992 &self,
1993 entity: &Entity<T>,
1994 cx: &mut App,
1995 mut on_release: impl FnOnce(&mut T, &mut Window, &mut App) + 'static,
1996 ) -> Subscription
1997 where
1998 T: 'static,
1999 {
2000 let entity_id = entity.entity_id();
2001 let window_handle = self.handle;
2002 let (subscription, activate) = cx.release_listeners.insert(
2003 entity_id,
2004 Box::new(move |entity, cx| {
2005 let entity = entity.downcast_mut().expect("invalid entity type");
2006 let _ = window_handle.update(cx, |_, window, cx| on_release(entity, window, cx));
2007 }),
2008 );
2009 activate();
2010 subscription
2011 }
2012
2013 /// Creates an [`AsyncWindowContext`], which has a static lifetime and can be held across
2014 /// await points in async code.
2015 pub fn to_async(&self, cx: &App) -> AsyncWindowContext {
2016 AsyncWindowContext::new_context(cx.to_async(), self.handle)
2017 }
2018
2019 /// Schedule the given closure to be run directly after the current frame is rendered.
2020 pub fn on_next_frame(&self, callback: impl FnOnce(&mut Window, &mut App) + 'static) {
2021 RefCell::borrow_mut(&self.next_frame_callbacks).push(Box::new(callback));
2022 }
2023
2024 /// Schedule a frame to be drawn on the next animation frame.
2025 ///
2026 /// This is useful for elements that need to animate continuously, such as a video player or an animated GIF.
2027 /// It will cause the window to redraw on the next frame, even if no other changes have occurred.
2028 ///
2029 /// If called from within a view, it will notify that view on the next frame. Otherwise, it will refresh the entire window.
2030 pub fn request_animation_frame(&self) {
2031 let entity = self.current_view();
2032 self.on_next_frame(move |_, cx| cx.notify(entity));
2033 }
2034
2035 /// Spawn the future returned by the given closure on the application thread pool.
2036 /// The closure is provided a handle to the current window and an `AsyncWindowContext` for
2037 /// use within your future.
2038 #[track_caller]
2039 pub fn spawn<AsyncFn, R>(&self, cx: &App, f: AsyncFn) -> Task<R>
2040 where
2041 R: 'static,
2042 AsyncFn: AsyncFnOnce(&mut AsyncWindowContext) -> R + 'static,
2043 {
2044 let handle = self.handle;
2045 cx.spawn(async move |app| {
2046 let mut async_window_cx = AsyncWindowContext::new_context(app.clone(), handle);
2047 f(&mut async_window_cx).await
2048 })
2049 }
2050
2051 /// Spawn the future returned by the given closure on the application thread
2052 /// pool, with the given priority. The closure is provided a handle to the
2053 /// current window and an `AsyncWindowContext` for use within your future.
2054 #[track_caller]
2055 pub fn spawn_with_priority<AsyncFn, R>(
2056 &self,
2057 priority: Priority,
2058 cx: &App,
2059 f: AsyncFn,
2060 ) -> Task<R>
2061 where
2062 R: 'static,
2063 AsyncFn: AsyncFnOnce(&mut AsyncWindowContext) -> R + 'static,
2064 {
2065 let handle = self.handle;
2066 cx.spawn_with_priority(priority, async move |app| {
2067 let mut async_window_cx = AsyncWindowContext::new_context(app.clone(), handle);
2068 f(&mut async_window_cx).await
2069 })
2070 }
2071
2072 /// Notify the window that its bounds have changed.
2073 ///
2074 /// This updates internal state like `viewport_size` and `scale_factor` from
2075 /// the platform window, then notifies observers. Normally called automatically
2076 /// by the platform's resize callback, but exposed publicly for test infrastructure.
2077 pub fn bounds_changed(&mut self, cx: &mut App) {
2078 self.scale_factor = self.platform_window.scale_factor();
2079 self.viewport_size = self.platform_window.content_size();
2080 self.display_id = self.platform_window.display().map(|display| display.id());
2081
2082 self.refresh();
2083
2084 self.bounds_observers
2085 .clone()
2086 .retain(&(), |callback| callback(self, cx));
2087 }
2088
2089 /// Returns the bounds of the current window in the global coordinate space, which could span across multiple displays.
2090 pub fn bounds(&self) -> Bounds<Pixels> {
2091 self.platform_window.bounds()
2092 }
2093
2094 /// Renders the current frame's scene to a texture and returns the pixel data as an RGBA image.
2095 /// This does not present the frame to screen - useful for visual testing where we want
2096 /// to capture what would be rendered without displaying it or requiring the window to be visible.
2097 #[cfg(any(test, feature = "test-support"))]
2098 pub fn render_to_image(&self) -> anyhow::Result<image::RgbaImage> {
2099 self.platform_window
2100 .render_to_image(&self.rendered_frame.scene)
2101 }
2102
2103 /// Set the content size of the window.
2104 pub fn resize(&mut self, size: Size<Pixels>) {
2105 self.platform_window.resize(size);
2106 }
2107
2108 /// Returns whether or not the window is currently fullscreen
2109 pub fn is_fullscreen(&self) -> bool {
2110 self.platform_window.is_fullscreen()
2111 }
2112
2113 pub(crate) fn appearance_changed(&mut self, cx: &mut App) {
2114 self.appearance = self.platform_window.appearance();
2115
2116 self.appearance_observers
2117 .clone()
2118 .retain(&(), |callback| callback(self, cx));
2119 }
2120
2121 pub(crate) fn button_layout_changed(&mut self, cx: &mut App) {
2122 self.button_layout_observers
2123 .clone()
2124 .retain(&(), |callback| callback(self, cx));
2125 }
2126
2127 /// Returns the appearance of the current window.
2128 pub fn appearance(&self) -> WindowAppearance {
2129 self.appearance
2130 }
2131
2132 /// Returns the size of the drawable area within the window.
2133 pub fn viewport_size(&self) -> Size<Pixels> {
2134 self.viewport_size
2135 }
2136
2137 /// Returns whether this window is focused by the operating system (receiving key events).
2138 pub fn is_window_active(&self) -> bool {
2139 self.active.get()
2140 }
2141
2142 /// Returns whether this window is considered to be the window
2143 /// that currently owns the mouse cursor.
2144 /// On mac, this is equivalent to `is_window_active`.
2145 pub fn is_window_hovered(&self) -> bool {
2146 if cfg!(any(
2147 target_os = "windows",
2148 target_os = "linux",
2149 target_os = "freebsd"
2150 )) {
2151 self.hovered.get()
2152 } else {
2153 self.is_window_active()
2154 }
2155 }
2156
2157 /// Toggle zoom on the window.
2158 pub fn zoom_window(&self) {
2159 self.platform_window.zoom();
2160 }
2161
2162 /// Opens the native title bar context menu, useful when implementing client side decorations (Wayland and X11)
2163 pub fn show_window_menu(&self, position: Point<Pixels>) {
2164 self.platform_window.show_window_menu(position)
2165 }
2166
2167 /// Handle window movement for Linux and macOS.
2168 /// Tells the compositor to take control of window movement (Wayland and X11)
2169 ///
2170 /// Events may not be received during a move operation.
2171 pub fn start_window_move(&self) {
2172 self.platform_window.start_window_move()
2173 }
2174
2175 /// When using client side decorations, set this to the width of the invisible decorations (Wayland and X11)
2176 pub fn set_client_inset(&mut self, inset: Pixels) {
2177 self.client_inset = Some(inset);
2178 self.platform_window.set_client_inset(inset);
2179 }
2180
2181 /// Returns the client_inset value by [`Self::set_client_inset`].
2182 pub fn client_inset(&self) -> Option<Pixels> {
2183 self.client_inset
2184 }
2185
2186 /// Returns whether the title bar window controls need to be rendered by the application (Wayland and X11)
2187 pub fn window_decorations(&self) -> Decorations {
2188 self.platform_window.window_decorations()
2189 }
2190
2191 /// Returns which window controls are currently visible (Wayland)
2192 pub fn window_controls(&self) -> WindowControls {
2193 self.platform_window.window_controls()
2194 }
2195
2196 /// Updates the window's title at the platform level.
2197 pub fn set_window_title(&mut self, title: &str) {
2198 self.platform_window.set_title(title);
2199 }
2200
2201 /// Sets the application identifier.
2202 pub fn set_app_id(&mut self, app_id: &str) {
2203 self.platform_window.set_app_id(app_id);
2204 }
2205
2206 /// Sets the window background appearance.
2207 pub fn set_background_appearance(&self, background_appearance: WindowBackgroundAppearance) {
2208 self.platform_window
2209 .set_background_appearance(background_appearance);
2210 }
2211
2212 /// Mark the window as dirty at the platform level.
2213 pub fn set_window_edited(&mut self, edited: bool) {
2214 self.platform_window.set_edited(edited);
2215 }
2216
2217 /// Determine the display on which the window is visible.
2218 pub fn display(&self, cx: &App) -> Option<Rc<dyn PlatformDisplay>> {
2219 cx.platform
2220 .displays()
2221 .into_iter()
2222 .find(|display| Some(display.id()) == self.display_id)
2223 }
2224
2225 /// Show the platform character palette.
2226 pub fn show_character_palette(&self) {
2227 self.platform_window.show_character_palette();
2228 }
2229
2230 /// The scale factor of the display associated with the window. For example, it could
2231 /// return 2.0 for a "retina" display, indicating that each logical pixel should actually
2232 /// be rendered as two pixels on screen.
2233 pub fn scale_factor(&self) -> f32 {
2234 self.scale_factor
2235 }
2236
2237 /// The size of an em for the base font of the application. Adjusting this value allows the
2238 /// UI to scale, just like zooming a web page.
2239 pub fn rem_size(&self) -> Pixels {
2240 self.rem_size_override_stack
2241 .last()
2242 .copied()
2243 .unwrap_or(self.rem_size)
2244 }
2245
2246 /// Sets the size of an em for the base font of the application. Adjusting this value allows the
2247 /// UI to scale, just like zooming a web page.
2248 pub fn set_rem_size(&mut self, rem_size: impl Into<Pixels>) {
2249 self.rem_size = rem_size.into();
2250 }
2251
2252 /// Acquire a globally unique identifier for the given ElementId.
2253 /// Only valid for the duration of the provided closure.
2254 pub fn with_global_id<R>(
2255 &mut self,
2256 element_id: ElementId,
2257 f: impl FnOnce(&GlobalElementId, &mut Self) -> R,
2258 ) -> R {
2259 self.with_id(element_id, |this| {
2260 let global_id = GlobalElementId(Arc::from(&*this.element_id_stack));
2261
2262 f(&global_id, this)
2263 })
2264 }
2265
2266 /// Calls the provided closure with the element ID pushed on the stack.
2267 #[inline]
2268 pub fn with_id<R>(
2269 &mut self,
2270 element_id: impl Into<ElementId>,
2271 f: impl FnOnce(&mut Self) -> R,
2272 ) -> R {
2273 self.element_id_stack.push(element_id.into());
2274 let result = f(self);
2275 self.element_id_stack.pop();
2276 result
2277 }
2278
2279 /// Executes the provided function with the specified rem size.
2280 ///
2281 /// This method must only be called as part of element drawing.
2282 // This function is called in a highly recursive manner in editor
2283 // prepainting, make sure its inlined to reduce the stack burden
2284 #[inline]
2285 pub fn with_rem_size<F, R>(&mut self, rem_size: Option<impl Into<Pixels>>, f: F) -> R
2286 where
2287 F: FnOnce(&mut Self) -> R,
2288 {
2289 self.invalidator.debug_assert_paint_or_prepaint();
2290
2291 if let Some(rem_size) = rem_size {
2292 self.rem_size_override_stack.push(rem_size.into());
2293 let result = f(self);
2294 self.rem_size_override_stack.pop();
2295 result
2296 } else {
2297 f(self)
2298 }
2299 }
2300
2301 /// The line height associated with the current text style.
2302 pub fn line_height(&self) -> Pixels {
2303 self.text_style().line_height_in_pixels(self.rem_size())
2304 }
2305
2306 /// Call to prevent the default action of an event. Currently only used to prevent
2307 /// parent elements from becoming focused on mouse down.
2308 pub fn prevent_default(&mut self) {
2309 self.default_prevented = true;
2310 }
2311
2312 /// Obtain whether default has been prevented for the event currently being dispatched.
2313 pub fn default_prevented(&self) -> bool {
2314 self.default_prevented
2315 }
2316
2317 /// Determine whether the given action is available along the dispatch path to the currently focused element.
2318 pub fn is_action_available(&self, action: &dyn Action, cx: &App) -> bool {
2319 let node_id =
2320 self.focus_node_id_in_rendered_frame(self.focused(cx).map(|handle| handle.id));
2321 self.rendered_frame
2322 .dispatch_tree
2323 .is_action_available(action, node_id)
2324 }
2325
2326 /// Determine whether the given action is available along the dispatch path to the given focus_handle.
2327 pub fn is_action_available_in(&self, action: &dyn Action, focus_handle: &FocusHandle) -> bool {
2328 let node_id = self.focus_node_id_in_rendered_frame(Some(focus_handle.id));
2329 self.rendered_frame
2330 .dispatch_tree
2331 .is_action_available(action, node_id)
2332 }
2333
2334 /// The position of the mouse relative to the window.
2335 pub fn mouse_position(&self) -> Point<Pixels> {
2336 self.mouse_position
2337 }
2338
2339 /// Captures the pointer for the given hitbox. While captured, all mouse move and mouse up
2340 /// events will be routed to listeners that check this hitbox's `is_hovered` status,
2341 /// regardless of actual hit testing. This enables drag operations that continue
2342 /// even when the pointer moves outside the element's bounds.
2343 ///
2344 /// The capture is automatically released on mouse up.
2345 pub fn capture_pointer(&mut self, hitbox_id: HitboxId) {
2346 self.captured_hitbox = Some(hitbox_id);
2347 }
2348
2349 /// Releases any active pointer capture.
2350 pub fn release_pointer(&mut self) {
2351 self.captured_hitbox = None;
2352 }
2353
2354 /// Returns the hitbox that has captured the pointer, if any.
2355 pub fn captured_hitbox(&self) -> Option<HitboxId> {
2356 self.captured_hitbox
2357 }
2358
2359 /// The current state of the keyboard's modifiers
2360 pub fn modifiers(&self) -> Modifiers {
2361 self.modifiers
2362 }
2363
2364 /// Returns true if the last input event was keyboard-based (key press, tab navigation, etc.)
2365 /// This is used for focus-visible styling to show focus indicators only for keyboard navigation.
2366 pub fn last_input_was_keyboard(&self) -> bool {
2367 self.last_input_modality == InputModality::Keyboard
2368 }
2369
2370 /// The current state of the keyboard's capslock
2371 pub fn capslock(&self) -> Capslock {
2372 self.capslock
2373 }
2374
2375 fn complete_frame(&self) {
2376 self.platform_window.completed_frame();
2377 }
2378
2379 /// Produces a new frame and assigns it to `rendered_frame`. To actually show
2380 /// the contents of the new [`Scene`], use [`Self::present`].
2381 #[profiling::function]
2382 pub fn draw(&mut self, cx: &mut App) -> ArenaClearNeeded {
2383 // Set up the per-App arena for element allocation during this draw.
2384 // This ensures that multiple test Apps have isolated arenas.
2385 let _arena_scope = ElementArenaScope::enter(&cx.element_arena);
2386
2387 self.invalidate_entities();
2388 cx.entities.clear_accessed();
2389 debug_assert!(self.rendered_entity_stack.is_empty());
2390 self.invalidator.set_dirty(false);
2391 self.requested_autoscroll = None;
2392
2393 // Restore the previously-used input handler.
2394 if let Some(input_handler) = self.platform_window.take_input_handler() {
2395 self.rendered_frame.input_handlers.push(Some(input_handler));
2396 }
2397 if !cx.mode.skip_drawing() {
2398 self.draw_roots(cx);
2399 }
2400 self.dirty_views.clear();
2401 self.next_frame.window_active = self.active.get();
2402
2403 // Register requested input handler with the platform window.
2404 if let Some(input_handler) = self.next_frame.input_handlers.pop() {
2405 self.platform_window
2406 .set_input_handler(input_handler.unwrap());
2407 }
2408
2409 self.layout_engine.as_mut().unwrap().clear();
2410 self.text_system().finish_frame();
2411 self.next_frame.finish(&mut self.rendered_frame);
2412
2413 self.invalidator.set_phase(DrawPhase::Focus);
2414 let previous_focus_path = self.rendered_frame.focus_path();
2415 let previous_window_active = self.rendered_frame.window_active;
2416 mem::swap(&mut self.rendered_frame, &mut self.next_frame);
2417 self.next_frame.clear();
2418 let current_focus_path = self.rendered_frame.focus_path();
2419 let current_window_active = self.rendered_frame.window_active;
2420
2421 if previous_focus_path != current_focus_path
2422 || previous_window_active != current_window_active
2423 {
2424 if !previous_focus_path.is_empty() && current_focus_path.is_empty() {
2425 self.focus_lost_listeners
2426 .clone()
2427 .retain(&(), |listener| listener(self, cx));
2428 }
2429
2430 let event = WindowFocusEvent {
2431 previous_focus_path: if previous_window_active {
2432 previous_focus_path
2433 } else {
2434 Default::default()
2435 },
2436 current_focus_path: if current_window_active {
2437 current_focus_path
2438 } else {
2439 Default::default()
2440 },
2441 };
2442 self.focus_listeners
2443 .clone()
2444 .retain(&(), |listener| listener(&event, self, cx));
2445 }
2446
2447 debug_assert!(self.rendered_entity_stack.is_empty());
2448 self.record_entities_accessed(cx);
2449 self.reset_cursor_style(cx);
2450 self.refreshing = false;
2451 self.invalidator.set_phase(DrawPhase::None);
2452 self.needs_present.set(true);
2453
2454 ArenaClearNeeded::new(&cx.element_arena)
2455 }
2456
2457 fn record_entities_accessed(&mut self, cx: &mut App) {
2458 let mut entities_ref = cx.entities.accessed_entities.get_mut();
2459 let mut entities = mem::take(entities_ref.deref_mut());
2460 let handle = self.handle;
2461 cx.record_entities_accessed(
2462 handle,
2463 // Try moving window invalidator into the Window
2464 self.invalidator.clone(),
2465 &entities,
2466 );
2467 let mut entities_ref = cx.entities.accessed_entities.get_mut();
2468 mem::swap(&mut entities, entities_ref.deref_mut());
2469 }
2470
2471 fn invalidate_entities(&mut self) {
2472 let mut views = self.invalidator.take_views();
2473 for entity in views.drain() {
2474 self.mark_view_dirty(entity);
2475 }
2476 self.invalidator.replace_views(views);
2477 }
2478
2479 #[profiling::function]
2480 fn present(&mut self) {
2481 self.platform_window.draw(&self.rendered_frame.scene);
2482 #[cfg(feature = "input-latency-histogram")]
2483 self.input_latency_tracker.record_frame_presented();
2484 self.needs_present.set(false);
2485 profiling::finish_frame!();
2486 }
2487
2488 /// Returns a snapshot of the current input-latency histograms.
2489 #[cfg(feature = "input-latency-histogram")]
2490 pub fn input_latency_snapshot(&self) -> InputLatencySnapshot {
2491 self.input_latency_tracker.snapshot()
2492 }
2493
2494 fn draw_roots(&mut self, cx: &mut App) {
2495 self.invalidator.set_phase(DrawPhase::Prepaint);
2496 self.tooltip_bounds.take();
2497
2498 let _inspector_width: Pixels = rems(30.0).to_pixels(self.rem_size());
2499 let root_size = {
2500 #[cfg(any(feature = "inspector", debug_assertions))]
2501 {
2502 if self.inspector.is_some() {
2503 let mut size = self.viewport_size;
2504 size.width = (size.width - _inspector_width).max(px(0.0));
2505 size
2506 } else {
2507 self.viewport_size
2508 }
2509 }
2510 #[cfg(not(any(feature = "inspector", debug_assertions)))]
2511 {
2512 self.viewport_size
2513 }
2514 };
2515
2516 // Layout all root elements.
2517 let mut root_element = self.root.as_ref().unwrap().clone().into_any();
2518 root_element.prepaint_as_root(Point::default(), root_size.into(), self, cx);
2519
2520 #[cfg(any(feature = "inspector", debug_assertions))]
2521 let inspector_element = self.prepaint_inspector(_inspector_width, cx);
2522
2523 self.prepaint_deferred_draws(cx);
2524
2525 let mut prompt_element = None;
2526 let mut active_drag_element = None;
2527 let mut tooltip_element = None;
2528 if let Some(prompt) = self.prompt.take() {
2529 let mut element = prompt.view.any_view().into_any();
2530 element.prepaint_as_root(Point::default(), root_size.into(), self, cx);
2531 prompt_element = Some(element);
2532 self.prompt = Some(prompt);
2533 } else if let Some(active_drag) = cx.active_drag.take() {
2534 let mut element = active_drag.view.clone().into_any();
2535 let offset = self.mouse_position() - active_drag.cursor_offset;
2536 element.prepaint_as_root(offset, AvailableSpace::min_size(), self, cx);
2537 active_drag_element = Some(element);
2538 cx.active_drag = Some(active_drag);
2539 } else {
2540 tooltip_element = self.prepaint_tooltip(cx);
2541 }
2542
2543 self.mouse_hit_test = self.next_frame.hit_test(self.mouse_position);
2544
2545 // Now actually paint the elements.
2546 self.invalidator.set_phase(DrawPhase::Paint);
2547 root_element.paint(self, cx);
2548
2549 #[cfg(any(feature = "inspector", debug_assertions))]
2550 self.paint_inspector(inspector_element, cx);
2551
2552 self.paint_deferred_draws(cx);
2553
2554 if let Some(mut prompt_element) = prompt_element {
2555 prompt_element.paint(self, cx);
2556 } else if let Some(mut drag_element) = active_drag_element {
2557 drag_element.paint(self, cx);
2558 } else if let Some(mut tooltip_element) = tooltip_element {
2559 tooltip_element.paint(self, cx);
2560 }
2561
2562 #[cfg(any(feature = "inspector", debug_assertions))]
2563 self.paint_inspector_hitbox(cx);
2564 }
2565
2566 fn prepaint_tooltip(&mut self, cx: &mut App) -> Option<AnyElement> {
2567 // Use indexing instead of iteration to avoid borrowing self for the duration of the loop.
2568 for tooltip_request_index in (0..self.next_frame.tooltip_requests.len()).rev() {
2569 let Some(Some(tooltip_request)) = self
2570 .next_frame
2571 .tooltip_requests
2572 .get(tooltip_request_index)
2573 .cloned()
2574 else {
2575 log::error!("Unexpectedly absent TooltipRequest");
2576 continue;
2577 };
2578 let mut element = tooltip_request.tooltip.view.clone().into_any();
2579 let mouse_position = tooltip_request.tooltip.mouse_position;
2580 let tooltip_size = element.layout_as_root(AvailableSpace::min_size(), self, cx);
2581
2582 let mut tooltip_bounds =
2583 Bounds::new(mouse_position + point(px(1.), px(1.)), tooltip_size);
2584 let window_bounds = Bounds {
2585 origin: Point::default(),
2586 size: self.viewport_size(),
2587 };
2588
2589 if tooltip_bounds.right() > window_bounds.right() {
2590 let new_x = mouse_position.x - tooltip_bounds.size.width - px(1.);
2591 if new_x >= Pixels::ZERO {
2592 tooltip_bounds.origin.x = new_x;
2593 } else {
2594 tooltip_bounds.origin.x = cmp::max(
2595 Pixels::ZERO,
2596 tooltip_bounds.origin.x - tooltip_bounds.right() - window_bounds.right(),
2597 );
2598 }
2599 }
2600
2601 if tooltip_bounds.bottom() > window_bounds.bottom() {
2602 let new_y = mouse_position.y - tooltip_bounds.size.height - px(1.);
2603 if new_y >= Pixels::ZERO {
2604 tooltip_bounds.origin.y = new_y;
2605 } else {
2606 tooltip_bounds.origin.y = cmp::max(
2607 Pixels::ZERO,
2608 tooltip_bounds.origin.y - tooltip_bounds.bottom() - window_bounds.bottom(),
2609 );
2610 }
2611 }
2612
2613 // It's possible for an element to have an active tooltip while not being painted (e.g.
2614 // via the `visible_on_hover` method). Since mouse listeners are not active in this
2615 // case, instead update the tooltip's visibility here.
2616 let is_visible =
2617 (tooltip_request.tooltip.check_visible_and_update)(tooltip_bounds, self, cx);
2618 if !is_visible {
2619 continue;
2620 }
2621
2622 self.with_absolute_element_offset(tooltip_bounds.origin, |window| {
2623 element.prepaint(window, cx)
2624 });
2625
2626 self.tooltip_bounds = Some(TooltipBounds {
2627 id: tooltip_request.id,
2628 bounds: tooltip_bounds,
2629 });
2630 return Some(element);
2631 }
2632 None
2633 }
2634
2635 fn prepaint_deferred_draws(&mut self, cx: &mut App) {
2636 assert_eq!(self.element_id_stack.len(), 0);
2637
2638 let mut completed_draws = Vec::new();
2639
2640 // Process deferred draws in multiple rounds to support nesting.
2641 // Each round processes all current deferred draws, which may produce new ones.
2642 let mut depth = 0;
2643 loop {
2644 // Limit maximum nesting depth to prevent infinite loops.
2645 assert!(depth < 10, "Exceeded maximum (10) deferred depth");
2646 depth += 1;
2647 let deferred_count = self.next_frame.deferred_draws.len();
2648 if deferred_count == 0 {
2649 break;
2650 }
2651
2652 // Sort by priority for this round
2653 let traversal_order = self.deferred_draw_traversal_order();
2654 let mut deferred_draws = mem::take(&mut self.next_frame.deferred_draws);
2655
2656 for deferred_draw_ix in traversal_order {
2657 let deferred_draw = &mut deferred_draws[deferred_draw_ix];
2658 self.element_id_stack
2659 .clone_from(&deferred_draw.element_id_stack);
2660 self.text_style_stack
2661 .clone_from(&deferred_draw.text_style_stack);
2662 self.next_frame
2663 .dispatch_tree
2664 .set_active_node(deferred_draw.parent_node);
2665
2666 let prepaint_start = self.prepaint_index();
2667 if let Some(element) = deferred_draw.element.as_mut() {
2668 self.with_rendered_view(deferred_draw.current_view, |window| {
2669 window.with_rem_size(Some(deferred_draw.rem_size), |window| {
2670 window.with_absolute_element_offset(
2671 deferred_draw.absolute_offset,
2672 |window| {
2673 element.prepaint(window, cx);
2674 },
2675 );
2676 });
2677 })
2678 } else {
2679 self.reuse_prepaint(deferred_draw.prepaint_range.clone());
2680 }
2681 let prepaint_end = self.prepaint_index();
2682 deferred_draw.prepaint_range = prepaint_start..prepaint_end;
2683 }
2684
2685 // Save completed draws and continue with newly added ones
2686 completed_draws.append(&mut deferred_draws);
2687
2688 self.element_id_stack.clear();
2689 self.text_style_stack.clear();
2690 }
2691
2692 // Restore all completed draws
2693 self.next_frame.deferred_draws = completed_draws;
2694 }
2695
2696 fn paint_deferred_draws(&mut self, cx: &mut App) {
2697 assert_eq!(self.element_id_stack.len(), 0);
2698
2699 // Paint all deferred draws in priority order.
2700 // Since prepaint has already processed nested deferreds, we just paint them all.
2701 if self.next_frame.deferred_draws.len() == 0 {
2702 return;
2703 }
2704
2705 let traversal_order = self.deferred_draw_traversal_order();
2706 let mut deferred_draws = mem::take(&mut self.next_frame.deferred_draws);
2707 for deferred_draw_ix in traversal_order {
2708 let mut deferred_draw = &mut deferred_draws[deferred_draw_ix];
2709 self.element_id_stack
2710 .clone_from(&deferred_draw.element_id_stack);
2711 self.next_frame
2712 .dispatch_tree
2713 .set_active_node(deferred_draw.parent_node);
2714
2715 let paint_start = self.paint_index();
2716 let content_mask = deferred_draw.content_mask;
2717 if let Some(element) = deferred_draw.element.as_mut() {
2718 self.with_rendered_view(deferred_draw.current_view, |window| {
2719 window.with_content_mask(content_mask, |window| {
2720 window.with_rem_size(Some(deferred_draw.rem_size), |window| {
2721 element.paint(window, cx);
2722 });
2723 })
2724 })
2725 } else {
2726 self.reuse_paint(deferred_draw.paint_range.clone());
2727 }
2728 let paint_end = self.paint_index();
2729 deferred_draw.paint_range = paint_start..paint_end;
2730 }
2731 self.next_frame.deferred_draws = deferred_draws;
2732 self.element_id_stack.clear();
2733 }
2734
2735 fn deferred_draw_traversal_order(&mut self) -> SmallVec<[usize; 8]> {
2736 let deferred_count = self.next_frame.deferred_draws.len();
2737 let mut sorted_indices = (0..deferred_count).collect::<SmallVec<[_; 8]>>();
2738 sorted_indices.sort_by_key(|ix| self.next_frame.deferred_draws[*ix].priority);
2739 sorted_indices
2740 }
2741
2742 pub(crate) fn prepaint_index(&self) -> PrepaintStateIndex {
2743 PrepaintStateIndex {
2744 hitboxes_index: self.next_frame.hitboxes.len(),
2745 tooltips_index: self.next_frame.tooltip_requests.len(),
2746 deferred_draws_index: self.next_frame.deferred_draws.len(),
2747 dispatch_tree_index: self.next_frame.dispatch_tree.len(),
2748 accessed_element_states_index: self.next_frame.accessed_element_states.len(),
2749 line_layout_index: self.text_system.layout_index(),
2750 }
2751 }
2752
2753 pub(crate) fn reuse_prepaint(&mut self, range: Range<PrepaintStateIndex>) {
2754 self.next_frame.hitboxes.extend(
2755 self.rendered_frame.hitboxes[range.start.hitboxes_index..range.end.hitboxes_index]
2756 .iter()
2757 .cloned(),
2758 );
2759 self.next_frame.tooltip_requests.extend(
2760 self.rendered_frame.tooltip_requests
2761 [range.start.tooltips_index..range.end.tooltips_index]
2762 .iter_mut()
2763 .map(|request| request.take()),
2764 );
2765 self.next_frame.accessed_element_states.extend(
2766 self.rendered_frame.accessed_element_states[range.start.accessed_element_states_index
2767 ..range.end.accessed_element_states_index]
2768 .iter()
2769 .map(|(id, type_id)| (id.clone(), *type_id)),
2770 );
2771 self.text_system
2772 .reuse_layouts(range.start.line_layout_index..range.end.line_layout_index);
2773
2774 let reused_subtree = self.next_frame.dispatch_tree.reuse_subtree(
2775 range.start.dispatch_tree_index..range.end.dispatch_tree_index,
2776 &mut self.rendered_frame.dispatch_tree,
2777 self.focus,
2778 );
2779
2780 if reused_subtree.contains_focus() {
2781 self.next_frame.focus = self.focus;
2782 }
2783
2784 self.next_frame.deferred_draws.extend(
2785 self.rendered_frame.deferred_draws
2786 [range.start.deferred_draws_index..range.end.deferred_draws_index]
2787 .iter()
2788 .map(|deferred_draw| DeferredDraw {
2789 current_view: deferred_draw.current_view,
2790 parent_node: reused_subtree.refresh_node_id(deferred_draw.parent_node),
2791 element_id_stack: deferred_draw.element_id_stack.clone(),
2792 text_style_stack: deferred_draw.text_style_stack.clone(),
2793 content_mask: deferred_draw.content_mask,
2794 rem_size: deferred_draw.rem_size,
2795 priority: deferred_draw.priority,
2796 element: None,
2797 absolute_offset: deferred_draw.absolute_offset,
2798 prepaint_range: deferred_draw.prepaint_range.clone(),
2799 paint_range: deferred_draw.paint_range.clone(),
2800 }),
2801 );
2802 }
2803
2804 pub(crate) fn paint_index(&self) -> PaintIndex {
2805 PaintIndex {
2806 scene_index: self.next_frame.scene.len(),
2807 mouse_listeners_index: self.next_frame.mouse_listeners.len(),
2808 input_handlers_index: self.next_frame.input_handlers.len(),
2809 cursor_styles_index: self.next_frame.cursor_styles.len(),
2810 accessed_element_states_index: self.next_frame.accessed_element_states.len(),
2811 tab_handle_index: self.next_frame.tab_stops.paint_index(),
2812 line_layout_index: self.text_system.layout_index(),
2813 }
2814 }
2815
2816 pub(crate) fn reuse_paint(&mut self, range: Range<PaintIndex>) {
2817 self.next_frame.cursor_styles.extend(
2818 self.rendered_frame.cursor_styles
2819 [range.start.cursor_styles_index..range.end.cursor_styles_index]
2820 .iter()
2821 .cloned(),
2822 );
2823 self.next_frame.input_handlers.extend(
2824 self.rendered_frame.input_handlers
2825 [range.start.input_handlers_index..range.end.input_handlers_index]
2826 .iter_mut()
2827 .map(|handler| handler.take()),
2828 );
2829 self.next_frame.mouse_listeners.extend(
2830 self.rendered_frame.mouse_listeners
2831 [range.start.mouse_listeners_index..range.end.mouse_listeners_index]
2832 .iter_mut()
2833 .map(|listener| listener.take()),
2834 );
2835 self.next_frame.accessed_element_states.extend(
2836 self.rendered_frame.accessed_element_states[range.start.accessed_element_states_index
2837 ..range.end.accessed_element_states_index]
2838 .iter()
2839 .map(|(id, type_id)| (id.clone(), *type_id)),
2840 );
2841 self.next_frame.tab_stops.replay(
2842 &self.rendered_frame.tab_stops.insertion_history
2843 [range.start.tab_handle_index..range.end.tab_handle_index],
2844 );
2845
2846 self.text_system
2847 .reuse_layouts(range.start.line_layout_index..range.end.line_layout_index);
2848 self.next_frame.scene.replay(
2849 range.start.scene_index..range.end.scene_index,
2850 &self.rendered_frame.scene,
2851 );
2852 }
2853
2854 /// Push a text style onto the stack, and call a function with that style active.
2855 /// Use [`Window::text_style`] to get the current, combined text style. This method
2856 /// should only be called as part of element drawing.
2857 // This function is called in a highly recursive manner in editor
2858 // prepainting, make sure its inlined to reduce the stack burden
2859 #[inline]
2860 pub fn with_text_style<F, R>(&mut self, style: Option<TextStyleRefinement>, f: F) -> R
2861 where
2862 F: FnOnce(&mut Self) -> R,
2863 {
2864 self.invalidator.debug_assert_paint_or_prepaint();
2865 if let Some(style) = style {
2866 self.text_style_stack.push(style);
2867 let result = f(self);
2868 self.text_style_stack.pop();
2869 result
2870 } else {
2871 f(self)
2872 }
2873 }
2874
2875 /// Updates the cursor style at the platform level. This method should only be called
2876 /// during the paint phase of element drawing.
2877 pub fn set_cursor_style(&mut self, style: CursorStyle, hitbox: &Hitbox) {
2878 self.invalidator.debug_assert_paint();
2879 self.next_frame.cursor_styles.push(CursorStyleRequest {
2880 hitbox_id: Some(hitbox.id),
2881 style,
2882 });
2883 }
2884
2885 /// Updates the cursor style for the entire window at the platform level. A cursor
2886 /// style using this method will have precedence over any cursor style set using
2887 /// `set_cursor_style`. This method should only be called during the paint
2888 /// phase of element drawing.
2889 pub fn set_window_cursor_style(&mut self, style: CursorStyle) {
2890 self.invalidator.debug_assert_paint();
2891 self.next_frame.cursor_styles.push(CursorStyleRequest {
2892 hitbox_id: None,
2893 style,
2894 })
2895 }
2896
2897 /// Sets a tooltip to be rendered for the upcoming frame. This method should only be called
2898 /// during the paint phase of element drawing.
2899 pub fn set_tooltip(&mut self, tooltip: AnyTooltip) -> TooltipId {
2900 self.invalidator.debug_assert_prepaint();
2901 let id = TooltipId(post_inc(&mut self.next_tooltip_id.0));
2902 self.next_frame
2903 .tooltip_requests
2904 .push(Some(TooltipRequest { id, tooltip }));
2905 id
2906 }
2907
2908 /// Invoke the given function with the given content mask after intersecting it
2909 /// with the current mask. This method should only be called during element drawing.
2910 // This function is called in a highly recursive manner in editor
2911 // prepainting, make sure its inlined to reduce the stack burden
2912 #[inline]
2913 pub fn with_content_mask<R>(
2914 &mut self,
2915 mask: Option<ContentMask<Pixels>>,
2916 f: impl FnOnce(&mut Self) -> R,
2917 ) -> R {
2918 self.invalidator.debug_assert_paint_or_prepaint();
2919 if let Some(mask) = mask {
2920 let mask = mask.intersect(&self.content_mask());
2921 self.content_mask_stack.push(mask);
2922 let result = f(self);
2923 self.content_mask_stack.pop();
2924 result
2925 } else {
2926 f(self)
2927 }
2928 }
2929
2930 /// Updates the global element offset relative to the current offset. This is used to implement
2931 /// scrolling. This method should only be called during the prepaint phase of element drawing.
2932 pub fn with_element_offset<R>(
2933 &mut self,
2934 offset: Point<Pixels>,
2935 f: impl FnOnce(&mut Self) -> R,
2936 ) -> R {
2937 self.invalidator.debug_assert_prepaint();
2938
2939 if offset.is_zero() {
2940 return f(self);
2941 };
2942
2943 let abs_offset = self.element_offset() + offset;
2944 self.with_absolute_element_offset(abs_offset, f)
2945 }
2946
2947 /// Updates the global element offset based on the given offset. This is used to implement
2948 /// drag handles and other manual painting of elements. This method should only be called during
2949 /// the prepaint phase of element drawing.
2950 pub fn with_absolute_element_offset<R>(
2951 &mut self,
2952 offset: Point<Pixels>,
2953 f: impl FnOnce(&mut Self) -> R,
2954 ) -> R {
2955 self.invalidator.debug_assert_prepaint();
2956 self.element_offset_stack.push(offset);
2957 let result = f(self);
2958 self.element_offset_stack.pop();
2959 result
2960 }
2961
2962 pub(crate) fn with_element_opacity<R>(
2963 &mut self,
2964 opacity: Option<f32>,
2965 f: impl FnOnce(&mut Self) -> R,
2966 ) -> R {
2967 self.invalidator.debug_assert_paint_or_prepaint();
2968
2969 let Some(opacity) = opacity else {
2970 return f(self);
2971 };
2972
2973 let previous_opacity = self.element_opacity;
2974 self.element_opacity = previous_opacity * opacity;
2975 let result = f(self);
2976 self.element_opacity = previous_opacity;
2977 result
2978 }
2979
2980 /// Perform prepaint on child elements in a "retryable" manner, so that any side effects
2981 /// of prepaints can be discarded before prepainting again. This is used to support autoscroll
2982 /// where we need to prepaint children to detect the autoscroll bounds, then adjust the
2983 /// element offset and prepaint again. See [`crate::List`] for an example. This method should only be
2984 /// called during the prepaint phase of element drawing.
2985 pub fn transact<T, U>(&mut self, f: impl FnOnce(&mut Self) -> Result<T, U>) -> Result<T, U> {
2986 self.invalidator.debug_assert_prepaint();
2987 let index = self.prepaint_index();
2988 let result = f(self);
2989 if result.is_err() {
2990 self.next_frame.hitboxes.truncate(index.hitboxes_index);
2991 self.next_frame
2992 .tooltip_requests
2993 .truncate(index.tooltips_index);
2994 self.next_frame
2995 .deferred_draws
2996 .truncate(index.deferred_draws_index);
2997 self.next_frame
2998 .dispatch_tree
2999 .truncate(index.dispatch_tree_index);
3000 self.next_frame
3001 .accessed_element_states
3002 .truncate(index.accessed_element_states_index);
3003 self.text_system.truncate_layouts(index.line_layout_index);
3004 }
3005 result
3006 }
3007
3008 /// When you call this method during [`Element::prepaint`], containing elements will attempt to
3009 /// scroll to cause the specified bounds to become visible. When they decide to autoscroll, they will call
3010 /// [`Element::prepaint`] again with a new set of bounds. See [`crate::List`] for an example of an element
3011 /// that supports this method being called on the elements it contains. This method should only be
3012 /// called during the prepaint phase of element drawing.
3013 pub fn request_autoscroll(&mut self, bounds: Bounds<Pixels>) {
3014 self.invalidator.debug_assert_prepaint();
3015 self.requested_autoscroll = Some(bounds);
3016 }
3017
3018 /// This method can be called from a containing element such as [`crate::List`] to support the autoscroll behavior
3019 /// described in [`Self::request_autoscroll`].
3020 pub fn take_autoscroll(&mut self) -> Option<Bounds<Pixels>> {
3021 self.invalidator.debug_assert_prepaint();
3022 self.requested_autoscroll.take()
3023 }
3024
3025 /// Asynchronously load an asset, if the asset hasn't finished loading this will return None.
3026 /// Your view will be re-drawn once the asset has finished loading.
3027 ///
3028 /// Note that the multiple calls to this method will only result in one `Asset::load` call at a
3029 /// time.
3030 pub fn use_asset<A: Asset>(&mut self, source: &A::Source, cx: &mut App) -> Option<A::Output> {
3031 let (task, is_first) = cx.fetch_asset::<A>(source);
3032 task.clone().now_or_never().or_else(|| {
3033 if is_first {
3034 let entity_id = self.current_view();
3035 self.spawn(cx, {
3036 let task = task.clone();
3037 async move |cx| {
3038 task.await;
3039
3040 cx.on_next_frame(move |_, cx| {
3041 cx.notify(entity_id);
3042 });
3043 }
3044 })
3045 .detach();
3046 }
3047
3048 None
3049 })
3050 }
3051
3052 /// Asynchronously load an asset, if the asset hasn't finished loading or doesn't exist this will return None.
3053 /// Your view will not be re-drawn once the asset has finished loading.
3054 ///
3055 /// Note that the multiple calls to this method will only result in one `Asset::load` call at a
3056 /// time.
3057 pub fn get_asset<A: Asset>(&mut self, source: &A::Source, cx: &mut App) -> Option<A::Output> {
3058 let (task, _) = cx.fetch_asset::<A>(source);
3059 task.now_or_never()
3060 }
3061 /// Obtain the current element offset. This method should only be called during the
3062 /// prepaint phase of element drawing.
3063 pub fn element_offset(&self) -> Point<Pixels> {
3064 self.invalidator.debug_assert_prepaint();
3065 self.element_offset_stack
3066 .last()
3067 .copied()
3068 .unwrap_or_default()
3069 }
3070
3071 /// Obtain the current element opacity. This method should only be called during the
3072 /// prepaint phase of element drawing.
3073 #[inline]
3074 pub(crate) fn element_opacity(&self) -> f32 {
3075 self.invalidator.debug_assert_paint_or_prepaint();
3076 self.element_opacity
3077 }
3078
3079 /// Obtain the current content mask. This method should only be called during element drawing.
3080 pub fn content_mask(&self) -> ContentMask<Pixels> {
3081 self.invalidator.debug_assert_paint_or_prepaint();
3082 self.content_mask_stack
3083 .last()
3084 .cloned()
3085 .unwrap_or_else(|| ContentMask {
3086 bounds: Bounds {
3087 origin: Point::default(),
3088 size: self.viewport_size,
3089 },
3090 })
3091 }
3092
3093 /// Provide elements in the called function with a new namespace in which their identifiers must be unique.
3094 /// This can be used within a custom element to distinguish multiple sets of child elements.
3095 pub fn with_element_namespace<R>(
3096 &mut self,
3097 element_id: impl Into<ElementId>,
3098 f: impl FnOnce(&mut Self) -> R,
3099 ) -> R {
3100 self.element_id_stack.push(element_id.into());
3101 let result = f(self);
3102 self.element_id_stack.pop();
3103 result
3104 }
3105
3106 /// Use a piece of state that exists as long this element is being rendered in consecutive frames.
3107 pub fn use_keyed_state<S: 'static>(
3108 &mut self,
3109 key: impl Into<ElementId>,
3110 cx: &mut App,
3111 init: impl FnOnce(&mut Self, &mut Context<S>) -> S,
3112 ) -> Entity<S> {
3113 let current_view = self.current_view();
3114 self.with_global_id(key.into(), |global_id, window| {
3115 window.with_element_state(global_id, |state: Option<Entity<S>>, window| {
3116 if let Some(state) = state {
3117 (state.clone(), state)
3118 } else {
3119 let new_state = cx.new(|cx| init(window, cx));
3120 cx.observe(&new_state, move |_, cx| {
3121 cx.notify(current_view);
3122 })
3123 .detach();
3124 (new_state.clone(), new_state)
3125 }
3126 })
3127 })
3128 }
3129
3130 /// Use a piece of state that exists as long this element is being rendered in consecutive frames, without needing to specify a key
3131 ///
3132 /// NOTE: This method uses the location of the caller to generate an ID for this state.
3133 /// If this is not sufficient to identify your state (e.g. you're rendering a list item),
3134 /// you can provide a custom ElementID using the `use_keyed_state` method.
3135 #[track_caller]
3136 pub fn use_state<S: 'static>(
3137 &mut self,
3138 cx: &mut App,
3139 init: impl FnOnce(&mut Self, &mut Context<S>) -> S,
3140 ) -> Entity<S> {
3141 self.use_keyed_state(
3142 ElementId::CodeLocation(*core::panic::Location::caller()),
3143 cx,
3144 init,
3145 )
3146 }
3147
3148 /// Updates or initializes state for an element with the given id that lives across multiple
3149 /// frames. If an element with this ID existed in the rendered frame, its state will be passed
3150 /// to the given closure. The state returned by the closure will be stored so it can be referenced
3151 /// when drawing the next frame. This method should only be called as part of element drawing.
3152 pub fn with_element_state<S, R>(
3153 &mut self,
3154 global_id: &GlobalElementId,
3155 f: impl FnOnce(Option<S>, &mut Self) -> (R, S),
3156 ) -> R
3157 where
3158 S: 'static,
3159 {
3160 self.invalidator.debug_assert_paint_or_prepaint();
3161
3162 let key = (global_id.clone(), TypeId::of::<S>());
3163 self.next_frame.accessed_element_states.push(key.clone());
3164
3165 if let Some(any) = self
3166 .next_frame
3167 .element_states
3168 .remove(&key)
3169 .or_else(|| self.rendered_frame.element_states.remove(&key))
3170 {
3171 let ElementStateBox {
3172 inner,
3173 #[cfg(debug_assertions)]
3174 type_name,
3175 } = any;
3176 // Using the extra inner option to avoid needing to reallocate a new box.
3177 let mut state_box = inner
3178 .downcast::<Option<S>>()
3179 .map_err(|_| {
3180 #[cfg(debug_assertions)]
3181 {
3182 anyhow::anyhow!(
3183 "invalid element state type for id, requested {:?}, actual: {:?}",
3184 std::any::type_name::<S>(),
3185 type_name
3186 )
3187 }
3188
3189 #[cfg(not(debug_assertions))]
3190 {
3191 anyhow::anyhow!(
3192 "invalid element state type for id, requested {:?}",
3193 std::any::type_name::<S>(),
3194 )
3195 }
3196 })
3197 .unwrap();
3198
3199 let state = state_box.take().expect(
3200 "reentrant call to with_element_state for the same state type and element id",
3201 );
3202 let (result, state) = f(Some(state), self);
3203 state_box.replace(state);
3204 self.next_frame.element_states.insert(
3205 key,
3206 ElementStateBox {
3207 inner: state_box,
3208 #[cfg(debug_assertions)]
3209 type_name,
3210 },
3211 );
3212 result
3213 } else {
3214 let (result, state) = f(None, self);
3215 self.next_frame.element_states.insert(
3216 key,
3217 ElementStateBox {
3218 inner: Box::new(Some(state)),
3219 #[cfg(debug_assertions)]
3220 type_name: std::any::type_name::<S>(),
3221 },
3222 );
3223 result
3224 }
3225 }
3226
3227 /// A variant of `with_element_state` that allows the element's id to be optional. This is a convenience
3228 /// method for elements where the element id may or may not be assigned. Prefer using `with_element_state`
3229 /// when the element is guaranteed to have an id.
3230 ///
3231 /// The first option means 'no ID provided'
3232 /// The second option means 'not yet initialized'
3233 pub fn with_optional_element_state<S, R>(
3234 &mut self,
3235 global_id: Option<&GlobalElementId>,
3236 f: impl FnOnce(Option<Option<S>>, &mut Self) -> (R, Option<S>),
3237 ) -> R
3238 where
3239 S: 'static,
3240 {
3241 self.invalidator.debug_assert_paint_or_prepaint();
3242
3243 if let Some(global_id) = global_id {
3244 self.with_element_state(global_id, |state, cx| {
3245 let (result, state) = f(Some(state), cx);
3246 let state =
3247 state.expect("you must return some state when you pass some element id");
3248 (result, state)
3249 })
3250 } else {
3251 let (result, state) = f(None, self);
3252 debug_assert!(
3253 state.is_none(),
3254 "you must not return an element state when passing None for the global id"
3255 );
3256 result
3257 }
3258 }
3259
3260 /// Executes the given closure within the context of a tab group.
3261 #[inline]
3262 pub fn with_tab_group<R>(&mut self, index: Option<isize>, f: impl FnOnce(&mut Self) -> R) -> R {
3263 if let Some(index) = index {
3264 self.next_frame.tab_stops.begin_group(index);
3265 let result = f(self);
3266 self.next_frame.tab_stops.end_group();
3267 result
3268 } else {
3269 f(self)
3270 }
3271 }
3272
3273 /// Defers the drawing of the given element, scheduling it to be painted on top of the currently-drawn tree
3274 /// at a later time. The `priority` parameter determines the drawing order relative to other deferred elements,
3275 /// with higher values being drawn on top.
3276 ///
3277 /// When `content_mask` is provided, the deferred element will be clipped to that region during
3278 /// both prepaint and paint. When `None`, no additional clipping is applied.
3279 ///
3280 /// This method should only be called as part of the prepaint phase of element drawing.
3281 pub fn defer_draw(
3282 &mut self,
3283 element: AnyElement,
3284 absolute_offset: Point<Pixels>,
3285 priority: usize,
3286 content_mask: Option<ContentMask<Pixels>>,
3287 ) {
3288 self.invalidator.debug_assert_prepaint();
3289 let parent_node = self.next_frame.dispatch_tree.active_node_id().unwrap();
3290 self.next_frame.deferred_draws.push(DeferredDraw {
3291 current_view: self.current_view(),
3292 parent_node,
3293 element_id_stack: self.element_id_stack.clone(),
3294 text_style_stack: self.text_style_stack.clone(),
3295 content_mask,
3296 rem_size: self.rem_size(),
3297 priority,
3298 element: Some(element),
3299 absolute_offset,
3300 prepaint_range: PrepaintStateIndex::default()..PrepaintStateIndex::default(),
3301 paint_range: PaintIndex::default()..PaintIndex::default(),
3302 });
3303 }
3304
3305 /// Creates a new painting layer for the specified bounds. A "layer" is a batch
3306 /// of geometry that are non-overlapping and have the same draw order. This is typically used
3307 /// for performance reasons.
3308 ///
3309 /// This method should only be called as part of the paint phase of element drawing.
3310 pub fn paint_layer<R>(&mut self, bounds: Bounds<Pixels>, f: impl FnOnce(&mut Self) -> R) -> R {
3311 self.invalidator.debug_assert_paint();
3312
3313 let scale_factor = self.scale_factor();
3314 let content_mask = self.content_mask();
3315 let clipped_bounds = bounds.intersect(&content_mask.bounds);
3316 if !clipped_bounds.is_empty() {
3317 self.next_frame
3318 .scene
3319 .push_layer(clipped_bounds.scale(scale_factor));
3320 }
3321
3322 let result = f(self);
3323
3324 if !clipped_bounds.is_empty() {
3325 self.next_frame.scene.pop_layer();
3326 }
3327
3328 result
3329 }
3330
3331 /// Paint one or more drop shadows into the scene for the next frame at the current z-index.
3332 ///
3333 /// This method should only be called as part of the paint phase of element drawing.
3334 pub fn paint_shadows(
3335 &mut self,
3336 bounds: Bounds<Pixels>,
3337 corner_radii: Corners<Pixels>,
3338 shadows: &[BoxShadow],
3339 ) {
3340 self.invalidator.debug_assert_paint();
3341
3342 let scale_factor = self.scale_factor();
3343 let content_mask = self.content_mask();
3344 let opacity = self.element_opacity();
3345 for shadow in shadows {
3346 let shadow_bounds = (bounds + shadow.offset).dilate(shadow.spread_radius);
3347 self.next_frame.scene.insert_primitive(Shadow {
3348 order: 0,
3349 blur_radius: shadow.blur_radius.scale(scale_factor),
3350 bounds: shadow_bounds.scale(scale_factor),
3351 content_mask: content_mask.scale(scale_factor),
3352 corner_radii: corner_radii.scale(scale_factor),
3353 color: shadow.color.opacity(opacity),
3354 });
3355 }
3356 }
3357
3358 /// Paint one or more quads into the scene for the next frame at the current stacking context.
3359 /// Quads are colored rectangular regions with an optional background, border, and corner radius.
3360 /// see [`fill`], [`outline`], and [`quad`] to construct this type.
3361 ///
3362 /// This method should only be called as part of the paint phase of element drawing.
3363 ///
3364 /// Note that the `quad.corner_radii` are allowed to exceed the bounds, creating sharp corners
3365 /// where the circular arcs meet. This will not display well when combined with dashed borders.
3366 /// Use `Corners::clamp_radii_for_quad_size` if the radii should fit within the bounds.
3367 pub fn paint_quad(&mut self, quad: PaintQuad) {
3368 self.invalidator.debug_assert_paint();
3369
3370 let scale_factor = self.scale_factor();
3371 let content_mask = self.content_mask();
3372 let opacity = self.element_opacity();
3373 self.next_frame.scene.insert_primitive(Quad {
3374 order: 0,
3375 bounds: quad.bounds.scale(scale_factor),
3376 content_mask: content_mask.scale(scale_factor),
3377 background: quad.background.opacity(opacity),
3378 border_color: quad.border_color.opacity(opacity),
3379 corner_radii: quad.corner_radii.scale(scale_factor),
3380 border_widths: quad.border_widths.scale(scale_factor),
3381 border_style: quad.border_style,
3382 });
3383 }
3384
3385 /// Paint the given `Path` into the scene for the next frame at the current z-index.
3386 ///
3387 /// This method should only be called as part of the paint phase of element drawing.
3388 pub fn paint_path(&mut self, mut path: Path<Pixels>, color: impl Into<Background>) {
3389 self.invalidator.debug_assert_paint();
3390
3391 let scale_factor = self.scale_factor();
3392 let content_mask = self.content_mask();
3393 let opacity = self.element_opacity();
3394 path.content_mask = content_mask;
3395 let color: Background = color.into();
3396 path.color = color.opacity(opacity);
3397 self.next_frame
3398 .scene
3399 .insert_primitive(path.scale(scale_factor));
3400 }
3401
3402 /// Paint an underline into the scene for the next frame at the current z-index.
3403 ///
3404 /// This method should only be called as part of the paint phase of element drawing.
3405 pub fn paint_underline(
3406 &mut self,
3407 origin: Point<Pixels>,
3408 width: Pixels,
3409 style: &UnderlineStyle,
3410 ) {
3411 self.invalidator.debug_assert_paint();
3412
3413 let scale_factor = self.scale_factor();
3414 let height = if style.wavy {
3415 style.thickness * 3.
3416 } else {
3417 style.thickness
3418 };
3419 let bounds = Bounds {
3420 origin,
3421 size: size(width, height),
3422 };
3423 let content_mask = self.content_mask();
3424 let element_opacity = self.element_opacity();
3425
3426 self.next_frame.scene.insert_primitive(Underline {
3427 order: 0,
3428 pad: 0,
3429 bounds: bounds.scale(scale_factor),
3430 content_mask: content_mask.scale(scale_factor),
3431 color: style.color.unwrap_or_default().opacity(element_opacity),
3432 thickness: style.thickness.scale(scale_factor),
3433 wavy: if style.wavy { 1 } else { 0 },
3434 });
3435 }
3436
3437 /// Paint a strikethrough into the scene for the next frame at the current z-index.
3438 ///
3439 /// This method should only be called as part of the paint phase of element drawing.
3440 pub fn paint_strikethrough(
3441 &mut self,
3442 origin: Point<Pixels>,
3443 width: Pixels,
3444 style: &StrikethroughStyle,
3445 ) {
3446 self.invalidator.debug_assert_paint();
3447
3448 let scale_factor = self.scale_factor();
3449 let height = style.thickness;
3450 let bounds = Bounds {
3451 origin,
3452 size: size(width, height),
3453 };
3454 let content_mask = self.content_mask();
3455 let opacity = self.element_opacity();
3456
3457 self.next_frame.scene.insert_primitive(Underline {
3458 order: 0,
3459 pad: 0,
3460 bounds: bounds.scale(scale_factor),
3461 content_mask: content_mask.scale(scale_factor),
3462 thickness: style.thickness.scale(scale_factor),
3463 color: style.color.unwrap_or_default().opacity(opacity),
3464 wavy: 0,
3465 });
3466 }
3467
3468 /// Paints a monochrome (non-emoji) glyph into the scene for the next frame at the current z-index.
3469 ///
3470 /// The y component of the origin is the baseline of the glyph.
3471 /// You should generally prefer to use the [`ShapedLine::paint`](crate::ShapedLine::paint) or
3472 /// [`WrappedLine::paint`](crate::WrappedLine::paint) methods in the [`TextSystem`](crate::TextSystem).
3473 /// This method is only useful if you need to paint a single glyph that has already been shaped.
3474 ///
3475 /// This method should only be called as part of the paint phase of element drawing.
3476 pub fn paint_glyph(
3477 &mut self,
3478 origin: Point<Pixels>,
3479 font_id: FontId,
3480 glyph_id: GlyphId,
3481 font_size: Pixels,
3482 color: Hsla,
3483 ) -> Result<()> {
3484 self.invalidator.debug_assert_paint();
3485
3486 let element_opacity = self.element_opacity();
3487 let scale_factor = self.scale_factor();
3488 let glyph_origin = origin.scale(scale_factor);
3489
3490 let subpixel_variant = Point {
3491 x: (glyph_origin.x.0.fract() * SUBPIXEL_VARIANTS_X as f32).floor() as u8,
3492 y: (glyph_origin.y.0.fract() * SUBPIXEL_VARIANTS_Y as f32).floor() as u8,
3493 };
3494 let subpixel_rendering = self.should_use_subpixel_rendering(font_id, font_size);
3495 let params = RenderGlyphParams {
3496 font_id,
3497 glyph_id,
3498 font_size,
3499 subpixel_variant,
3500 scale_factor,
3501 is_emoji: false,
3502 subpixel_rendering,
3503 };
3504
3505 let raster_bounds = self.text_system().raster_bounds(¶ms)?;
3506 if !raster_bounds.is_zero() {
3507 let tile = self
3508 .sprite_atlas
3509 .get_or_insert_with(¶ms.clone().into(), &mut || {
3510 let (size, bytes) = self.text_system().rasterize_glyph(¶ms)?;
3511 Ok(Some((size, Cow::Owned(bytes))))
3512 })?
3513 .expect("Callback above only errors or returns Some");
3514 let bounds = Bounds {
3515 origin: glyph_origin.map(|px| px.floor()) + raster_bounds.origin.map(Into::into),
3516 size: tile.bounds.size.map(Into::into),
3517 };
3518 let content_mask = self.content_mask().scale(scale_factor);
3519
3520 if subpixel_rendering {
3521 self.next_frame.scene.insert_primitive(SubpixelSprite {
3522 order: 0,
3523 pad: 0,
3524 bounds,
3525 content_mask,
3526 color: color.opacity(element_opacity),
3527 tile,
3528 transformation: TransformationMatrix::unit(),
3529 });
3530 } else {
3531 self.next_frame.scene.insert_primitive(MonochromeSprite {
3532 order: 0,
3533 pad: 0,
3534 bounds,
3535 content_mask,
3536 color: color.opacity(element_opacity),
3537 tile,
3538 transformation: TransformationMatrix::unit(),
3539 });
3540 }
3541 }
3542 Ok(())
3543 }
3544
3545 /// Paints a monochrome glyph with pre-computed raster bounds.
3546 ///
3547 /// This is faster than `paint_glyph` because it skips the per-glyph cache lookup.
3548 /// Use `ShapedLine::compute_glyph_raster_data` to batch-compute raster bounds during prepaint.
3549 pub fn paint_glyph_with_raster_bounds(
3550 &mut self,
3551 origin: Point<Pixels>,
3552 _font_id: FontId,
3553 _glyph_id: GlyphId,
3554 _font_size: Pixels,
3555 color: Hsla,
3556 raster_bounds: Bounds<DevicePixels>,
3557 params: &RenderGlyphParams,
3558 ) -> Result<()> {
3559 self.invalidator.debug_assert_paint();
3560
3561 let element_opacity = self.element_opacity();
3562 let scale_factor = self.scale_factor();
3563 let glyph_origin = origin.scale(scale_factor);
3564
3565 if !raster_bounds.is_zero() {
3566 let tile = self
3567 .sprite_atlas
3568 .get_or_insert_with(¶ms.clone().into(), &mut || {
3569 let (size, bytes) = self.text_system().rasterize_glyph(params)?;
3570 Ok(Some((size, Cow::Owned(bytes))))
3571 })?
3572 .expect("Callback above only errors or returns Some");
3573 let bounds = Bounds {
3574 origin: glyph_origin.map(|px| px.floor()) + raster_bounds.origin.map(Into::into),
3575 size: tile.bounds.size.map(Into::into),
3576 };
3577 let content_mask = self.content_mask().scale(scale_factor);
3578 self.next_frame.scene.insert_primitive(MonochromeSprite {
3579 order: 0,
3580 pad: 0,
3581 bounds,
3582 content_mask,
3583 color: color.opacity(element_opacity),
3584 tile,
3585 transformation: TransformationMatrix::unit(),
3586 });
3587 }
3588 Ok(())
3589 }
3590
3591 /// Paints an emoji glyph with pre-computed raster bounds.
3592 ///
3593 /// This is faster than `paint_emoji` because it skips the per-glyph cache lookup.
3594 /// Use `ShapedLine::compute_glyph_raster_data` to batch-compute raster bounds during prepaint.
3595 pub fn paint_emoji_with_raster_bounds(
3596 &mut self,
3597 origin: Point<Pixels>,
3598 _font_id: FontId,
3599 _glyph_id: GlyphId,
3600 _font_size: Pixels,
3601 raster_bounds: Bounds<DevicePixels>,
3602 params: &RenderGlyphParams,
3603 ) -> Result<()> {
3604 self.invalidator.debug_assert_paint();
3605
3606 let scale_factor = self.scale_factor();
3607 let glyph_origin = origin.scale(scale_factor);
3608
3609 if !raster_bounds.is_zero() {
3610 let tile = self
3611 .sprite_atlas
3612 .get_or_insert_with(¶ms.clone().into(), &mut || {
3613 let (size, bytes) = self.text_system().rasterize_glyph(params)?;
3614 Ok(Some((size, Cow::Owned(bytes))))
3615 })?
3616 .expect("Callback above only errors or returns Some");
3617
3618 let bounds = Bounds {
3619 origin: glyph_origin.map(|px| px.floor()) + raster_bounds.origin.map(Into::into),
3620 size: tile.bounds.size.map(Into::into),
3621 };
3622 let content_mask = self.content_mask().scale(scale_factor);
3623 let opacity = self.element_opacity();
3624
3625 self.next_frame.scene.insert_primitive(PolychromeSprite {
3626 order: 0,
3627 pad: 0,
3628 grayscale: false,
3629 bounds,
3630 corner_radii: Default::default(),
3631 content_mask,
3632 tile,
3633 opacity,
3634 });
3635 }
3636 Ok(())
3637 }
3638
3639 fn should_use_subpixel_rendering(&self, font_id: FontId, font_size: Pixels) -> bool {
3640 if self.platform_window.background_appearance() != WindowBackgroundAppearance::Opaque {
3641 return false;
3642 }
3643
3644 if !self.platform_window.is_subpixel_rendering_supported() {
3645 return false;
3646 }
3647
3648 let mode = match self.text_rendering_mode.get() {
3649 TextRenderingMode::PlatformDefault => self
3650 .text_system()
3651 .recommended_rendering_mode(font_id, font_size),
3652 mode => mode,
3653 };
3654
3655 mode == TextRenderingMode::Subpixel
3656 }
3657
3658 /// Paints an emoji glyph into the scene for the next frame at the current z-index.
3659 ///
3660 /// The y component of the origin is the baseline of the glyph.
3661 /// You should generally prefer to use the [`ShapedLine::paint`](crate::ShapedLine::paint) or
3662 /// [`WrappedLine::paint`](crate::WrappedLine::paint) methods in the [`TextSystem`](crate::TextSystem).
3663 /// This method is only useful if you need to paint a single emoji that has already been shaped.
3664 ///
3665 /// This method should only be called as part of the paint phase of element drawing.
3666 pub fn paint_emoji(
3667 &mut self,
3668 origin: Point<Pixels>,
3669 font_id: FontId,
3670 glyph_id: GlyphId,
3671 font_size: Pixels,
3672 ) -> Result<()> {
3673 self.invalidator.debug_assert_paint();
3674
3675 let scale_factor = self.scale_factor();
3676 let glyph_origin = origin.scale(scale_factor);
3677 let params = RenderGlyphParams {
3678 font_id,
3679 glyph_id,
3680 font_size,
3681 // We don't render emojis with subpixel variants.
3682 subpixel_variant: Default::default(),
3683 scale_factor,
3684 is_emoji: true,
3685 subpixel_rendering: false,
3686 };
3687
3688 let raster_bounds = self.text_system().raster_bounds(¶ms)?;
3689 if !raster_bounds.is_zero() {
3690 let tile = self
3691 .sprite_atlas
3692 .get_or_insert_with(¶ms.clone().into(), &mut || {
3693 let (size, bytes) = self.text_system().rasterize_glyph(¶ms)?;
3694 Ok(Some((size, Cow::Owned(bytes))))
3695 })?
3696 .expect("Callback above only errors or returns Some");
3697
3698 let bounds = Bounds {
3699 origin: glyph_origin.map(|px| px.floor()) + raster_bounds.origin.map(Into::into),
3700 size: tile.bounds.size.map(Into::into),
3701 };
3702 let content_mask = self.content_mask().scale(scale_factor);
3703 let opacity = self.element_opacity();
3704
3705 self.next_frame.scene.insert_primitive(PolychromeSprite {
3706 order: 0,
3707 pad: 0,
3708 grayscale: false,
3709 bounds,
3710 corner_radii: Default::default(),
3711 content_mask,
3712 tile,
3713 opacity,
3714 });
3715 }
3716 Ok(())
3717 }
3718
3719 /// Paint a monochrome SVG into the scene for the next frame at the current stacking context.
3720 ///
3721 /// This method should only be called as part of the paint phase of element drawing.
3722 pub fn paint_svg(
3723 &mut self,
3724 bounds: Bounds<Pixels>,
3725 path: SharedString,
3726 mut data: Option<&[u8]>,
3727 transformation: TransformationMatrix,
3728 color: Hsla,
3729 cx: &App,
3730 ) -> Result<()> {
3731 self.invalidator.debug_assert_paint();
3732
3733 let element_opacity = self.element_opacity();
3734 let scale_factor = self.scale_factor();
3735
3736 let bounds = bounds.scale(scale_factor);
3737 let params = RenderSvgParams {
3738 path,
3739 size: bounds.size.map(|pixels| {
3740 DevicePixels::from((pixels.0 * SMOOTH_SVG_SCALE_FACTOR).ceil() as i32)
3741 }),
3742 };
3743
3744 let Some(tile) =
3745 self.sprite_atlas
3746 .get_or_insert_with(¶ms.clone().into(), &mut || {
3747 let Some((size, bytes)) = cx.svg_renderer.render_alpha_mask(¶ms, data)?
3748 else {
3749 return Ok(None);
3750 };
3751 Ok(Some((size, Cow::Owned(bytes))))
3752 })?
3753 else {
3754 return Ok(());
3755 };
3756 let content_mask = self.content_mask().scale(scale_factor);
3757 let svg_bounds = Bounds {
3758 origin: bounds.center()
3759 - Point::new(
3760 ScaledPixels(tile.bounds.size.width.0 as f32 / SMOOTH_SVG_SCALE_FACTOR / 2.),
3761 ScaledPixels(tile.bounds.size.height.0 as f32 / SMOOTH_SVG_SCALE_FACTOR / 2.),
3762 ),
3763 size: tile
3764 .bounds
3765 .size
3766 .map(|value| ScaledPixels(value.0 as f32 / SMOOTH_SVG_SCALE_FACTOR)),
3767 };
3768
3769 self.next_frame.scene.insert_primitive(MonochromeSprite {
3770 order: 0,
3771 pad: 0,
3772 bounds: svg_bounds
3773 .map_origin(|origin| origin.round())
3774 .map_size(|size| size.ceil()),
3775 content_mask,
3776 color: color.opacity(element_opacity),
3777 tile,
3778 transformation,
3779 });
3780
3781 Ok(())
3782 }
3783
3784 /// Paint an image into the scene for the next frame at the current z-index.
3785 /// This method will panic if the frame_index is not valid
3786 ///
3787 /// This method should only be called as part of the paint phase of element drawing.
3788 pub fn paint_image(
3789 &mut self,
3790 bounds: Bounds<Pixels>,
3791 corner_radii: Corners<Pixels>,
3792 data: Arc<RenderImage>,
3793 frame_index: usize,
3794 grayscale: bool,
3795 ) -> Result<()> {
3796 self.invalidator.debug_assert_paint();
3797
3798 let scale_factor = self.scale_factor();
3799 let bounds = bounds.scale(scale_factor);
3800 let params = RenderImageParams {
3801 image_id: data.id,
3802 frame_index,
3803 };
3804
3805 let tile = self
3806 .sprite_atlas
3807 .get_or_insert_with(¶ms.into(), &mut || {
3808 Ok(Some((
3809 data.size(frame_index),
3810 Cow::Borrowed(
3811 data.as_bytes(frame_index)
3812 .expect("It's the caller's job to pass a valid frame index"),
3813 ),
3814 )))
3815 })?
3816 .expect("Callback above only returns Some");
3817 let content_mask = self.content_mask().scale(scale_factor);
3818 let corner_radii = corner_radii.scale(scale_factor);
3819 let opacity = self.element_opacity();
3820
3821 self.next_frame.scene.insert_primitive(PolychromeSprite {
3822 order: 0,
3823 pad: 0,
3824 grayscale,
3825 bounds: bounds
3826 .map_origin(|origin| origin.floor())
3827 .map_size(|size| size.ceil()),
3828 content_mask,
3829 corner_radii,
3830 tile,
3831 opacity,
3832 });
3833 Ok(())
3834 }
3835
3836 /// Paint a surface into the scene for the next frame at the current z-index.
3837 ///
3838 /// This method should only be called as part of the paint phase of element drawing.
3839 #[cfg(target_os = "macos")]
3840 pub fn paint_surface(&mut self, bounds: Bounds<Pixels>, image_buffer: CVPixelBuffer) {
3841 use crate::PaintSurface;
3842
3843 self.invalidator.debug_assert_paint();
3844
3845 let scale_factor = self.scale_factor();
3846 let bounds = bounds.scale(scale_factor);
3847 let content_mask = self.content_mask().scale(scale_factor);
3848 self.next_frame.scene.insert_primitive(PaintSurface {
3849 order: 0,
3850 bounds,
3851 content_mask,
3852 image_buffer,
3853 });
3854 }
3855
3856 /// Removes an image from the sprite atlas.
3857 pub fn drop_image(&mut self, data: Arc<RenderImage>) -> Result<()> {
3858 for frame_index in 0..data.frame_count() {
3859 let params = RenderImageParams {
3860 image_id: data.id,
3861 frame_index,
3862 };
3863
3864 self.sprite_atlas.remove(¶ms.clone().into());
3865 }
3866
3867 Ok(())
3868 }
3869
3870 /// Add a node to the layout tree for the current frame. Takes the `Style` of the element for which
3871 /// layout is being requested, along with the layout ids of any children. This method is called during
3872 /// calls to the [`Element::request_layout`] trait method and enables any element to participate in layout.
3873 ///
3874 /// This method should only be called as part of the request_layout or prepaint phase of element drawing.
3875 #[must_use]
3876 pub fn request_layout(
3877 &mut self,
3878 style: Style,
3879 children: impl IntoIterator<Item = LayoutId>,
3880 cx: &mut App,
3881 ) -> LayoutId {
3882 self.invalidator.debug_assert_prepaint();
3883
3884 cx.layout_id_buffer.clear();
3885 cx.layout_id_buffer.extend(children);
3886 let rem_size = self.rem_size();
3887 let scale_factor = self.scale_factor();
3888
3889 self.layout_engine.as_mut().unwrap().request_layout(
3890 style,
3891 rem_size,
3892 scale_factor,
3893 &cx.layout_id_buffer,
3894 )
3895 }
3896
3897 /// Add a node to the layout tree for the current frame. Instead of taking a `Style` and children,
3898 /// this variant takes a function that is invoked during layout so you can use arbitrary logic to
3899 /// determine the element's size. One place this is used internally is when measuring text.
3900 ///
3901 /// The given closure is invoked at layout time with the known dimensions and available space and
3902 /// returns a `Size`.
3903 ///
3904 /// This method should only be called as part of the request_layout or prepaint phase of element drawing.
3905 pub fn request_measured_layout<F>(&mut self, style: Style, measure: F) -> LayoutId
3906 where
3907 F: Fn(Size<Option<Pixels>>, Size<AvailableSpace>, &mut Window, &mut App) -> Size<Pixels>
3908 + 'static,
3909 {
3910 self.invalidator.debug_assert_prepaint();
3911
3912 let rem_size = self.rem_size();
3913 let scale_factor = self.scale_factor();
3914 self.layout_engine
3915 .as_mut()
3916 .unwrap()
3917 .request_measured_layout(style, rem_size, scale_factor, measure)
3918 }
3919
3920 /// Compute the layout for the given id within the given available space.
3921 /// This method is called for its side effect, typically by the framework prior to painting.
3922 /// After calling it, you can request the bounds of the given layout node id or any descendant.
3923 ///
3924 /// This method should only be called as part of the prepaint phase of element drawing.
3925 pub fn compute_layout(
3926 &mut self,
3927 layout_id: LayoutId,
3928 available_space: Size<AvailableSpace>,
3929 cx: &mut App,
3930 ) {
3931 self.invalidator.debug_assert_prepaint();
3932
3933 let mut layout_engine = self.layout_engine.take().unwrap();
3934 layout_engine.compute_layout(layout_id, available_space, self, cx);
3935 self.layout_engine = Some(layout_engine);
3936 }
3937
3938 /// Obtain the bounds computed for the given LayoutId relative to the window. This method will usually be invoked by
3939 /// GPUI itself automatically in order to pass your element its `Bounds` automatically.
3940 ///
3941 /// This method should only be called as part of element drawing.
3942 pub fn layout_bounds(&mut self, layout_id: LayoutId) -> Bounds<Pixels> {
3943 self.invalidator.debug_assert_prepaint();
3944
3945 let scale_factor = self.scale_factor();
3946 let mut bounds = self
3947 .layout_engine
3948 .as_mut()
3949 .unwrap()
3950 .layout_bounds(layout_id, scale_factor)
3951 .map(Into::into);
3952 bounds.origin += self.element_offset();
3953 bounds
3954 }
3955
3956 /// This method should be called during `prepaint`. You can use
3957 /// the returned [Hitbox] during `paint` or in an event handler
3958 /// to determine whether the inserted hitbox was the topmost.
3959 ///
3960 /// This method should only be called as part of the prepaint phase of element drawing.
3961 pub fn insert_hitbox(&mut self, bounds: Bounds<Pixels>, behavior: HitboxBehavior) -> Hitbox {
3962 self.invalidator.debug_assert_prepaint();
3963
3964 let content_mask = self.content_mask();
3965 let mut id = self.next_hitbox_id;
3966 self.next_hitbox_id = self.next_hitbox_id.next();
3967 let hitbox = Hitbox {
3968 id,
3969 bounds,
3970 content_mask,
3971 behavior,
3972 };
3973 self.next_frame.hitboxes.push(hitbox.clone());
3974 hitbox
3975 }
3976
3977 /// Set a hitbox which will act as a control area of the platform window.
3978 ///
3979 /// This method should only be called as part of the paint phase of element drawing.
3980 pub fn insert_window_control_hitbox(&mut self, area: WindowControlArea, hitbox: Hitbox) {
3981 self.invalidator.debug_assert_paint();
3982 self.next_frame.window_control_hitboxes.push((area, hitbox));
3983 }
3984
3985 /// Sets the key context for the current element. This context will be used to translate
3986 /// keybindings into actions.
3987 ///
3988 /// This method should only be called as part of the paint phase of element drawing.
3989 pub fn set_key_context(&mut self, context: KeyContext) {
3990 self.invalidator.debug_assert_paint();
3991 self.next_frame.dispatch_tree.set_key_context(context);
3992 }
3993
3994 /// Sets the focus handle for the current element. This handle will be used to manage focus state
3995 /// and keyboard event dispatch for the element.
3996 ///
3997 /// This method should only be called as part of the prepaint phase of element drawing.
3998 pub fn set_focus_handle(&mut self, focus_handle: &FocusHandle, _: &App) {
3999 self.invalidator.debug_assert_prepaint();
4000 if focus_handle.is_focused(self) {
4001 self.next_frame.focus = Some(focus_handle.id);
4002 }
4003 self.next_frame.dispatch_tree.set_focus_id(focus_handle.id);
4004 }
4005
4006 /// Sets the view id for the current element, which will be used to manage view caching.
4007 ///
4008 /// This method should only be called as part of element prepaint. We plan on removing this
4009 /// method eventually when we solve some issues that require us to construct editor elements
4010 /// directly instead of always using editors via views.
4011 pub fn set_view_id(&mut self, view_id: EntityId) {
4012 self.invalidator.debug_assert_prepaint();
4013 self.next_frame.dispatch_tree.set_view_id(view_id);
4014 }
4015
4016 /// Get the entity ID for the currently rendering view
4017 pub fn current_view(&self) -> EntityId {
4018 self.invalidator.debug_assert_paint_or_prepaint();
4019 self.rendered_entity_stack.last().copied().unwrap()
4020 }
4021
4022 #[inline]
4023 pub(crate) fn with_rendered_view<R>(
4024 &mut self,
4025 id: EntityId,
4026 f: impl FnOnce(&mut Self) -> R,
4027 ) -> R {
4028 self.rendered_entity_stack.push(id);
4029 let result = f(self);
4030 self.rendered_entity_stack.pop();
4031 result
4032 }
4033
4034 /// Executes the provided function with the specified image cache.
4035 pub fn with_image_cache<F, R>(&mut self, image_cache: Option<AnyImageCache>, f: F) -> R
4036 where
4037 F: FnOnce(&mut Self) -> R,
4038 {
4039 if let Some(image_cache) = image_cache {
4040 self.image_cache_stack.push(image_cache);
4041 let result = f(self);
4042 self.image_cache_stack.pop();
4043 result
4044 } else {
4045 f(self)
4046 }
4047 }
4048
4049 /// Sets an input handler, such as [`ElementInputHandler`][element_input_handler], which interfaces with the
4050 /// platform to receive textual input with proper integration with concerns such
4051 /// as IME interactions. This handler will be active for the upcoming frame until the following frame is
4052 /// rendered.
4053 ///
4054 /// This method should only be called as part of the paint phase of element drawing.
4055 ///
4056 /// [element_input_handler]: crate::ElementInputHandler
4057 pub fn handle_input(
4058 &mut self,
4059 focus_handle: &FocusHandle,
4060 input_handler: impl InputHandler,
4061 cx: &App,
4062 ) {
4063 self.invalidator.debug_assert_paint();
4064
4065 if focus_handle.is_focused(self) {
4066 let cx = self.to_async(cx);
4067 self.next_frame
4068 .input_handlers
4069 .push(Some(PlatformInputHandler::new(cx, Box::new(input_handler))));
4070 }
4071 }
4072
4073 /// Register a mouse event listener on the window for the next frame. The type of event
4074 /// is determined by the first parameter of the given listener. When the next frame is rendered
4075 /// the listener will be cleared.
4076 ///
4077 /// This method should only be called as part of the paint phase of element drawing.
4078 pub fn on_mouse_event<Event: MouseEvent>(
4079 &mut self,
4080 mut listener: impl FnMut(&Event, DispatchPhase, &mut Window, &mut App) + 'static,
4081 ) {
4082 self.invalidator.debug_assert_paint();
4083
4084 self.next_frame.mouse_listeners.push(Some(Box::new(
4085 move |event: &dyn Any, phase: DispatchPhase, window: &mut Window, cx: &mut App| {
4086 if let Some(event) = event.downcast_ref() {
4087 listener(event, phase, window, cx)
4088 }
4089 },
4090 )));
4091 }
4092
4093 /// Register a key event listener on this node for the next frame. The type of event
4094 /// is determined by the first parameter of the given listener. When the next frame is rendered
4095 /// the listener will be cleared.
4096 ///
4097 /// This is a fairly low-level method, so prefer using event handlers on elements unless you have
4098 /// a specific need to register a listener yourself.
4099 ///
4100 /// This method should only be called as part of the paint phase of element drawing.
4101 pub fn on_key_event<Event: KeyEvent>(
4102 &mut self,
4103 listener: impl Fn(&Event, DispatchPhase, &mut Window, &mut App) + 'static,
4104 ) {
4105 self.invalidator.debug_assert_paint();
4106
4107 self.next_frame.dispatch_tree.on_key_event(Rc::new(
4108 move |event: &dyn Any, phase, window: &mut Window, cx: &mut App| {
4109 if let Some(event) = event.downcast_ref::<Event>() {
4110 listener(event, phase, window, cx)
4111 }
4112 },
4113 ));
4114 }
4115
4116 /// Register a modifiers changed event listener on the window for the next frame.
4117 ///
4118 /// This is a fairly low-level method, so prefer using event handlers on elements unless you have
4119 /// a specific need to register a global listener.
4120 ///
4121 /// This method should only be called as part of the paint phase of element drawing.
4122 pub fn on_modifiers_changed(
4123 &mut self,
4124 listener: impl Fn(&ModifiersChangedEvent, &mut Window, &mut App) + 'static,
4125 ) {
4126 self.invalidator.debug_assert_paint();
4127
4128 self.next_frame.dispatch_tree.on_modifiers_changed(Rc::new(
4129 move |event: &ModifiersChangedEvent, window: &mut Window, cx: &mut App| {
4130 listener(event, window, cx)
4131 },
4132 ));
4133 }
4134
4135 /// Register a listener to be called when the given focus handle or one of its descendants receives focus.
4136 /// This does not fire if the given focus handle - or one of its descendants - was previously focused.
4137 /// Returns a subscription and persists until the subscription is dropped.
4138 pub fn on_focus_in(
4139 &mut self,
4140 handle: &FocusHandle,
4141 cx: &mut App,
4142 mut listener: impl FnMut(&mut Window, &mut App) + 'static,
4143 ) -> Subscription {
4144 let focus_id = handle.id;
4145 let (subscription, activate) =
4146 self.new_focus_listener(Box::new(move |event, window, cx| {
4147 if event.is_focus_in(focus_id) {
4148 listener(window, cx);
4149 }
4150 true
4151 }));
4152 cx.defer(move |_| activate());
4153 subscription
4154 }
4155
4156 /// Register a listener to be called when the given focus handle or one of its descendants loses focus.
4157 /// Returns a subscription and persists until the subscription is dropped.
4158 pub fn on_focus_out(
4159 &mut self,
4160 handle: &FocusHandle,
4161 cx: &mut App,
4162 mut listener: impl FnMut(FocusOutEvent, &mut Window, &mut App) + 'static,
4163 ) -> Subscription {
4164 let focus_id = handle.id;
4165 let (subscription, activate) =
4166 self.new_focus_listener(Box::new(move |event, window, cx| {
4167 if let Some(blurred_id) = event.previous_focus_path.last().copied()
4168 && event.is_focus_out(focus_id)
4169 {
4170 let event = FocusOutEvent {
4171 blurred: WeakFocusHandle {
4172 id: blurred_id,
4173 handles: Arc::downgrade(&cx.focus_handles),
4174 },
4175 };
4176 listener(event, window, cx)
4177 }
4178 true
4179 }));
4180 cx.defer(move |_| activate());
4181 subscription
4182 }
4183
4184 fn reset_cursor_style(&self, cx: &mut App) {
4185 // Set the cursor only if we're the active window.
4186 if self.is_window_hovered() {
4187 let style = self
4188 .rendered_frame
4189 .cursor_style(self)
4190 .unwrap_or(CursorStyle::Arrow);
4191 cx.platform.set_cursor_style(style);
4192 }
4193 }
4194
4195 /// Dispatch a given keystroke as though the user had typed it.
4196 /// You can create a keystroke with Keystroke::parse("").
4197 pub fn dispatch_keystroke(&mut self, keystroke: Keystroke, cx: &mut App) -> bool {
4198 let keystroke = keystroke.with_simulated_ime();
4199 let result = self.dispatch_event(
4200 PlatformInput::KeyDown(KeyDownEvent {
4201 keystroke: keystroke.clone(),
4202 is_held: false,
4203 prefer_character_input: false,
4204 }),
4205 cx,
4206 );
4207 if !result.propagate {
4208 return true;
4209 }
4210
4211 if let Some(input) = keystroke.key_char
4212 && let Some(mut input_handler) = self.platform_window.take_input_handler()
4213 {
4214 input_handler.dispatch_input(&input, self, cx);
4215 self.platform_window.set_input_handler(input_handler);
4216 return true;
4217 }
4218
4219 false
4220 }
4221
4222 /// Return a key binding string for an action, to display in the UI. Uses the highest precedence
4223 /// binding for the action (last binding added to the keymap).
4224 pub fn keystroke_text_for(&self, action: &dyn Action) -> String {
4225 self.highest_precedence_binding_for_action(action)
4226 .map(|binding| {
4227 binding
4228 .keystrokes()
4229 .iter()
4230 .map(ToString::to_string)
4231 .collect::<Vec<_>>()
4232 .join(" ")
4233 })
4234 .unwrap_or_else(|| action.name().to_string())
4235 }
4236
4237 /// Dispatch a mouse or keyboard event on the window.
4238 #[profiling::function]
4239 pub fn dispatch_event(&mut self, event: PlatformInput, cx: &mut App) -> DispatchEventResult {
4240 #[cfg(feature = "input-latency-histogram")]
4241 let dispatch_time = Instant::now();
4242 let update_count_before = self.invalidator.update_count();
4243 // Track input modality for focus-visible styling and hover suppression.
4244 // Hover is suppressed during keyboard modality so that keyboard navigation
4245 // doesn't show hover highlights on the item under the mouse cursor.
4246 let old_modality = self.last_input_modality;
4247 self.last_input_modality = match &event {
4248 PlatformInput::KeyDown(_) => InputModality::Keyboard,
4249 PlatformInput::MouseMove(_) | PlatformInput::MouseDown(_) => InputModality::Mouse,
4250 _ => self.last_input_modality,
4251 };
4252 if self.last_input_modality != old_modality {
4253 self.refresh();
4254 }
4255
4256 // Handlers may set this to false by calling `stop_propagation`.
4257 cx.propagate_event = true;
4258 // Handlers may set this to true by calling `prevent_default`.
4259 self.default_prevented = false;
4260
4261 let event = match event {
4262 // Track the mouse position with our own state, since accessing the platform
4263 // API for the mouse position can only occur on the main thread.
4264 PlatformInput::MouseMove(mouse_move) => {
4265 self.mouse_position = mouse_move.position;
4266 self.modifiers = mouse_move.modifiers;
4267 PlatformInput::MouseMove(mouse_move)
4268 }
4269 PlatformInput::MouseDown(mouse_down) => {
4270 self.mouse_position = mouse_down.position;
4271 self.modifiers = mouse_down.modifiers;
4272 PlatformInput::MouseDown(mouse_down)
4273 }
4274 PlatformInput::MouseUp(mouse_up) => {
4275 self.mouse_position = mouse_up.position;
4276 self.modifiers = mouse_up.modifiers;
4277 PlatformInput::MouseUp(mouse_up)
4278 }
4279 PlatformInput::MousePressure(mouse_pressure) => {
4280 PlatformInput::MousePressure(mouse_pressure)
4281 }
4282 PlatformInput::MouseExited(mouse_exited) => {
4283 self.modifiers = mouse_exited.modifiers;
4284 PlatformInput::MouseExited(mouse_exited)
4285 }
4286 PlatformInput::ModifiersChanged(modifiers_changed) => {
4287 self.modifiers = modifiers_changed.modifiers;
4288 self.capslock = modifiers_changed.capslock;
4289 PlatformInput::ModifiersChanged(modifiers_changed)
4290 }
4291 PlatformInput::ScrollWheel(scroll_wheel) => {
4292 self.mouse_position = scroll_wheel.position;
4293 self.modifiers = scroll_wheel.modifiers;
4294 PlatformInput::ScrollWheel(scroll_wheel)
4295 }
4296 PlatformInput::Pinch(pinch) => {
4297 self.mouse_position = pinch.position;
4298 self.modifiers = pinch.modifiers;
4299 PlatformInput::Pinch(pinch)
4300 }
4301 // Translate dragging and dropping of external files from the operating system
4302 // to internal drag and drop events.
4303 PlatformInput::FileDrop(file_drop) => match file_drop {
4304 FileDropEvent::Entered { position, paths } => {
4305 self.mouse_position = position;
4306 if cx.active_drag.is_none() {
4307 cx.active_drag = Some(AnyDrag {
4308 value: Arc::new(paths.clone()),
4309 view: cx.new(|_| paths).into(),
4310 cursor_offset: position,
4311 cursor_style: None,
4312 });
4313 }
4314 PlatformInput::MouseMove(MouseMoveEvent {
4315 position,
4316 pressed_button: Some(MouseButton::Left),
4317 modifiers: Modifiers::default(),
4318 })
4319 }
4320 FileDropEvent::Pending { position } => {
4321 self.mouse_position = position;
4322 PlatformInput::MouseMove(MouseMoveEvent {
4323 position,
4324 pressed_button: Some(MouseButton::Left),
4325 modifiers: Modifiers::default(),
4326 })
4327 }
4328 FileDropEvent::Submit { position } => {
4329 cx.activate(true);
4330 self.mouse_position = position;
4331 PlatformInput::MouseUp(MouseUpEvent {
4332 button: MouseButton::Left,
4333 position,
4334 modifiers: Modifiers::default(),
4335 click_count: 1,
4336 })
4337 }
4338 FileDropEvent::Exited => {
4339 cx.active_drag.take();
4340 PlatformInput::FileDrop(FileDropEvent::Exited)
4341 }
4342 },
4343 PlatformInput::KeyDown(_) | PlatformInput::KeyUp(_) => event,
4344 };
4345
4346 if let Some(any_mouse_event) = event.mouse_event() {
4347 self.dispatch_mouse_event(any_mouse_event, cx);
4348 } else if let Some(any_key_event) = event.keyboard_event() {
4349 self.dispatch_key_event(any_key_event, cx);
4350 }
4351
4352 if self.invalidator.update_count() > update_count_before {
4353 self.input_rate_tracker.borrow_mut().record_input();
4354 #[cfg(feature = "input-latency-histogram")]
4355 if self.invalidator.not_drawing() {
4356 self.input_latency_tracker.record_input(dispatch_time);
4357 } else {
4358 self.input_latency_tracker.record_mid_draw_input();
4359 }
4360 }
4361
4362 DispatchEventResult {
4363 propagate: cx.propagate_event,
4364 default_prevented: self.default_prevented,
4365 }
4366 }
4367
4368 fn dispatch_mouse_event(&mut self, event: &dyn Any, cx: &mut App) {
4369 let hit_test = self.rendered_frame.hit_test(self.mouse_position());
4370 if hit_test != self.mouse_hit_test {
4371 self.mouse_hit_test = hit_test;
4372 self.reset_cursor_style(cx);
4373 }
4374
4375 #[cfg(any(feature = "inspector", debug_assertions))]
4376 if self.is_inspector_picking(cx) {
4377 self.handle_inspector_mouse_event(event, cx);
4378 // When inspector is picking, all other mouse handling is skipped.
4379 return;
4380 }
4381
4382 let mut mouse_listeners = mem::take(&mut self.rendered_frame.mouse_listeners);
4383
4384 // Capture phase, events bubble from back to front. Handlers for this phase are used for
4385 // special purposes, such as detecting events outside of a given Bounds.
4386 for listener in &mut mouse_listeners {
4387 let listener = listener.as_mut().unwrap();
4388 listener(event, DispatchPhase::Capture, self, cx);
4389 if !cx.propagate_event {
4390 break;
4391 }
4392 }
4393
4394 // Bubble phase, where most normal handlers do their work.
4395 if cx.propagate_event {
4396 for listener in mouse_listeners.iter_mut().rev() {
4397 let listener = listener.as_mut().unwrap();
4398 listener(event, DispatchPhase::Bubble, self, cx);
4399 if !cx.propagate_event {
4400 break;
4401 }
4402 }
4403 }
4404
4405 self.rendered_frame.mouse_listeners = mouse_listeners;
4406
4407 if cx.has_active_drag() {
4408 if event.is::<MouseMoveEvent>() {
4409 // If this was a mouse move event, redraw the window so that the
4410 // active drag can follow the mouse cursor.
4411 self.refresh();
4412 } else if event.is::<MouseUpEvent>() {
4413 // If this was a mouse up event, cancel the active drag and redraw
4414 // the window.
4415 cx.active_drag = None;
4416 self.refresh();
4417 }
4418 }
4419
4420 // Auto-release pointer capture on mouse up
4421 if event.is::<MouseUpEvent>() && self.captured_hitbox.is_some() {
4422 self.captured_hitbox = None;
4423 }
4424 }
4425
4426 fn dispatch_key_event(&mut self, event: &dyn Any, cx: &mut App) {
4427 if self.invalidator.is_dirty() {
4428 self.draw(cx).clear();
4429 }
4430
4431 let node_id = self.focus_node_id_in_rendered_frame(self.focus);
4432 let dispatch_path = self.rendered_frame.dispatch_tree.dispatch_path(node_id);
4433
4434 let mut keystroke: Option<Keystroke> = None;
4435
4436 if let Some(event) = event.downcast_ref::<ModifiersChangedEvent>() {
4437 if event.modifiers.number_of_modifiers() == 0
4438 && self.pending_modifier.modifiers.number_of_modifiers() == 1
4439 && !self.pending_modifier.saw_keystroke
4440 {
4441 let key = match self.pending_modifier.modifiers {
4442 modifiers if modifiers.shift => Some("shift"),
4443 modifiers if modifiers.control => Some("control"),
4444 modifiers if modifiers.alt => Some("alt"),
4445 modifiers if modifiers.platform => Some("platform"),
4446 modifiers if modifiers.function => Some("function"),
4447 _ => None,
4448 };
4449 if let Some(key) = key {
4450 keystroke = Some(Keystroke {
4451 key: key.to_string(),
4452 key_char: None,
4453 modifiers: Modifiers::default(),
4454 });
4455 }
4456 }
4457
4458 if self.pending_modifier.modifiers.number_of_modifiers() == 0
4459 && event.modifiers.number_of_modifiers() == 1
4460 {
4461 self.pending_modifier.saw_keystroke = false
4462 }
4463 self.pending_modifier.modifiers = event.modifiers
4464 } else if let Some(key_down_event) = event.downcast_ref::<KeyDownEvent>() {
4465 self.pending_modifier.saw_keystroke = true;
4466 keystroke = Some(key_down_event.keystroke.clone());
4467 }
4468
4469 let Some(keystroke) = keystroke else {
4470 self.finish_dispatch_key_event(event, dispatch_path, self.context_stack(), cx);
4471 return;
4472 };
4473
4474 cx.propagate_event = true;
4475 self.dispatch_keystroke_interceptors(event, self.context_stack(), cx);
4476 if !cx.propagate_event {
4477 self.finish_dispatch_key_event(event, dispatch_path, self.context_stack(), cx);
4478 return;
4479 }
4480
4481 let mut currently_pending = self.pending_input.take().unwrap_or_default();
4482 if currently_pending.focus.is_some() && currently_pending.focus != self.focus {
4483 currently_pending = PendingInput::default();
4484 }
4485
4486 let match_result = self.rendered_frame.dispatch_tree.dispatch_key(
4487 currently_pending.keystrokes,
4488 keystroke,
4489 &dispatch_path,
4490 );
4491
4492 if !match_result.to_replay.is_empty() {
4493 self.replay_pending_input(match_result.to_replay, cx);
4494 cx.propagate_event = true;
4495 }
4496
4497 if !match_result.pending.is_empty() {
4498 currently_pending.timer.take();
4499 currently_pending.keystrokes = match_result.pending;
4500 currently_pending.focus = self.focus;
4501
4502 let text_input_requires_timeout = event
4503 .downcast_ref::<KeyDownEvent>()
4504 .filter(|key_down| key_down.keystroke.key_char.is_some())
4505 .and_then(|_| self.platform_window.take_input_handler())
4506 .map_or(false, |mut input_handler| {
4507 let accepts = input_handler.accepts_text_input(self, cx);
4508 self.platform_window.set_input_handler(input_handler);
4509 accepts
4510 });
4511
4512 currently_pending.needs_timeout |=
4513 match_result.pending_has_binding || text_input_requires_timeout;
4514
4515 if currently_pending.needs_timeout {
4516 currently_pending.timer = Some(self.spawn(cx, async move |cx| {
4517 cx.background_executor.timer(Duration::from_secs(1)).await;
4518 cx.update(move |window, cx| {
4519 let Some(currently_pending) = window
4520 .pending_input
4521 .take()
4522 .filter(|pending| pending.focus == window.focus)
4523 else {
4524 return;
4525 };
4526
4527 let node_id = window.focus_node_id_in_rendered_frame(window.focus);
4528 let dispatch_path =
4529 window.rendered_frame.dispatch_tree.dispatch_path(node_id);
4530
4531 let to_replay = window
4532 .rendered_frame
4533 .dispatch_tree
4534 .flush_dispatch(currently_pending.keystrokes, &dispatch_path);
4535
4536 window.pending_input_changed(cx);
4537 window.replay_pending_input(to_replay, cx)
4538 })
4539 .log_err();
4540 }));
4541 } else {
4542 currently_pending.timer = None;
4543 }
4544 self.pending_input = Some(currently_pending);
4545 self.pending_input_changed(cx);
4546 cx.propagate_event = false;
4547 return;
4548 }
4549
4550 let skip_bindings = event
4551 .downcast_ref::<KeyDownEvent>()
4552 .filter(|key_down_event| key_down_event.prefer_character_input)
4553 .map(|_| {
4554 self.platform_window
4555 .take_input_handler()
4556 .map_or(false, |mut input_handler| {
4557 let accepts = input_handler.accepts_text_input(self, cx);
4558 self.platform_window.set_input_handler(input_handler);
4559 // If modifiers are not excessive (e.g. AltGr), and the input handler is accepting text input,
4560 // we prefer the text input over bindings.
4561 accepts
4562 })
4563 })
4564 .unwrap_or(false);
4565
4566 if !skip_bindings {
4567 for binding in match_result.bindings {
4568 self.dispatch_action_on_node(node_id, binding.action.as_ref(), cx);
4569 if !cx.propagate_event {
4570 self.dispatch_keystroke_observers(
4571 event,
4572 Some(binding.action),
4573 match_result.context_stack,
4574 cx,
4575 );
4576 self.pending_input_changed(cx);
4577 return;
4578 }
4579 }
4580 }
4581
4582 self.finish_dispatch_key_event(event, dispatch_path, match_result.context_stack, cx);
4583 self.pending_input_changed(cx);
4584 }
4585
4586 fn finish_dispatch_key_event(
4587 &mut self,
4588 event: &dyn Any,
4589 dispatch_path: SmallVec<[DispatchNodeId; 32]>,
4590 context_stack: Vec<KeyContext>,
4591 cx: &mut App,
4592 ) {
4593 self.dispatch_key_down_up_event(event, &dispatch_path, cx);
4594 if !cx.propagate_event {
4595 return;
4596 }
4597
4598 self.dispatch_modifiers_changed_event(event, &dispatch_path, cx);
4599 if !cx.propagate_event {
4600 return;
4601 }
4602
4603 self.dispatch_keystroke_observers(event, None, context_stack, cx);
4604 }
4605
4606 pub(crate) fn pending_input_changed(&mut self, cx: &mut App) {
4607 self.pending_input_observers
4608 .clone()
4609 .retain(&(), |callback| callback(self, cx));
4610 }
4611
4612 fn dispatch_key_down_up_event(
4613 &mut self,
4614 event: &dyn Any,
4615 dispatch_path: &SmallVec<[DispatchNodeId; 32]>,
4616 cx: &mut App,
4617 ) {
4618 // Capture phase
4619 for node_id in dispatch_path {
4620 let node = self.rendered_frame.dispatch_tree.node(*node_id);
4621
4622 for key_listener in node.key_listeners.clone() {
4623 key_listener(event, DispatchPhase::Capture, self, cx);
4624 if !cx.propagate_event {
4625 return;
4626 }
4627 }
4628 }
4629
4630 // Bubble phase
4631 for node_id in dispatch_path.iter().rev() {
4632 // Handle low level key events
4633 let node = self.rendered_frame.dispatch_tree.node(*node_id);
4634 for key_listener in node.key_listeners.clone() {
4635 key_listener(event, DispatchPhase::Bubble, self, cx);
4636 if !cx.propagate_event {
4637 return;
4638 }
4639 }
4640 }
4641 }
4642
4643 fn dispatch_modifiers_changed_event(
4644 &mut self,
4645 event: &dyn Any,
4646 dispatch_path: &SmallVec<[DispatchNodeId; 32]>,
4647 cx: &mut App,
4648 ) {
4649 let Some(event) = event.downcast_ref::<ModifiersChangedEvent>() else {
4650 return;
4651 };
4652 for node_id in dispatch_path.iter().rev() {
4653 let node = self.rendered_frame.dispatch_tree.node(*node_id);
4654 for listener in node.modifiers_changed_listeners.clone() {
4655 listener(event, self, cx);
4656 if !cx.propagate_event {
4657 return;
4658 }
4659 }
4660 }
4661 }
4662
4663 /// Determine whether a potential multi-stroke key binding is in progress on this window.
4664 pub fn has_pending_keystrokes(&self) -> bool {
4665 self.pending_input.is_some()
4666 }
4667
4668 pub(crate) fn clear_pending_keystrokes(&mut self) {
4669 self.pending_input.take();
4670 }
4671
4672 /// Returns the currently pending input keystrokes that might result in a multi-stroke key binding.
4673 pub fn pending_input_keystrokes(&self) -> Option<&[Keystroke]> {
4674 self.pending_input
4675 .as_ref()
4676 .map(|pending_input| pending_input.keystrokes.as_slice())
4677 }
4678
4679 fn replay_pending_input(&mut self, replays: SmallVec<[Replay; 1]>, cx: &mut App) {
4680 let node_id = self.focus_node_id_in_rendered_frame(self.focus);
4681 let dispatch_path = self.rendered_frame.dispatch_tree.dispatch_path(node_id);
4682
4683 'replay: for replay in replays {
4684 let event = KeyDownEvent {
4685 keystroke: replay.keystroke.clone(),
4686 is_held: false,
4687 prefer_character_input: true,
4688 };
4689
4690 cx.propagate_event = true;
4691 for binding in replay.bindings {
4692 self.dispatch_action_on_node(node_id, binding.action.as_ref(), cx);
4693 if !cx.propagate_event {
4694 self.dispatch_keystroke_observers(
4695 &event,
4696 Some(binding.action),
4697 Vec::default(),
4698 cx,
4699 );
4700 continue 'replay;
4701 }
4702 }
4703
4704 self.dispatch_key_down_up_event(&event, &dispatch_path, cx);
4705 if !cx.propagate_event {
4706 continue 'replay;
4707 }
4708 if let Some(input) = replay.keystroke.key_char.as_ref().cloned()
4709 && let Some(mut input_handler) = self.platform_window.take_input_handler()
4710 {
4711 input_handler.dispatch_input(&input, self, cx);
4712 self.platform_window.set_input_handler(input_handler)
4713 }
4714 }
4715 }
4716
4717 fn focus_node_id_in_rendered_frame(&self, focus_id: Option<FocusId>) -> DispatchNodeId {
4718 focus_id
4719 .and_then(|focus_id| {
4720 self.rendered_frame
4721 .dispatch_tree
4722 .focusable_node_id(focus_id)
4723 })
4724 .unwrap_or_else(|| self.rendered_frame.dispatch_tree.root_node_id())
4725 }
4726
4727 fn dispatch_action_on_node(
4728 &mut self,
4729 node_id: DispatchNodeId,
4730 action: &dyn Action,
4731 cx: &mut App,
4732 ) {
4733 let dispatch_path = self.rendered_frame.dispatch_tree.dispatch_path(node_id);
4734
4735 // Capture phase for global actions.
4736 cx.propagate_event = true;
4737 if let Some(mut global_listeners) = cx
4738 .global_action_listeners
4739 .remove(&action.as_any().type_id())
4740 {
4741 for listener in &global_listeners {
4742 listener(action.as_any(), DispatchPhase::Capture, cx);
4743 if !cx.propagate_event {
4744 break;
4745 }
4746 }
4747
4748 global_listeners.extend(
4749 cx.global_action_listeners
4750 .remove(&action.as_any().type_id())
4751 .unwrap_or_default(),
4752 );
4753
4754 cx.global_action_listeners
4755 .insert(action.as_any().type_id(), global_listeners);
4756 }
4757
4758 if !cx.propagate_event {
4759 return;
4760 }
4761
4762 // Capture phase for window actions.
4763 for node_id in &dispatch_path {
4764 let node = self.rendered_frame.dispatch_tree.node(*node_id);
4765 for DispatchActionListener {
4766 action_type,
4767 listener,
4768 } in node.action_listeners.clone()
4769 {
4770 let any_action = action.as_any();
4771 if action_type == any_action.type_id() {
4772 listener(any_action, DispatchPhase::Capture, self, cx);
4773
4774 if !cx.propagate_event {
4775 return;
4776 }
4777 }
4778 }
4779 }
4780
4781 // Bubble phase for window actions.
4782 for node_id in dispatch_path.iter().rev() {
4783 let node = self.rendered_frame.dispatch_tree.node(*node_id);
4784 for DispatchActionListener {
4785 action_type,
4786 listener,
4787 } in node.action_listeners.clone()
4788 {
4789 let any_action = action.as_any();
4790 if action_type == any_action.type_id() {
4791 cx.propagate_event = false; // Actions stop propagation by default during the bubble phase
4792 listener(any_action, DispatchPhase::Bubble, self, cx);
4793
4794 if !cx.propagate_event {
4795 return;
4796 }
4797 }
4798 }
4799 }
4800
4801 // Bubble phase for global actions.
4802 if let Some(mut global_listeners) = cx
4803 .global_action_listeners
4804 .remove(&action.as_any().type_id())
4805 {
4806 for listener in global_listeners.iter().rev() {
4807 cx.propagate_event = false; // Actions stop propagation by default during the bubble phase
4808
4809 listener(action.as_any(), DispatchPhase::Bubble, cx);
4810 if !cx.propagate_event {
4811 break;
4812 }
4813 }
4814
4815 global_listeners.extend(
4816 cx.global_action_listeners
4817 .remove(&action.as_any().type_id())
4818 .unwrap_or_default(),
4819 );
4820
4821 cx.global_action_listeners
4822 .insert(action.as_any().type_id(), global_listeners);
4823 }
4824 }
4825
4826 /// Register the given handler to be invoked whenever the global of the given type
4827 /// is updated.
4828 pub fn observe_global<G: Global>(
4829 &mut self,
4830 cx: &mut App,
4831 f: impl Fn(&mut Window, &mut App) + 'static,
4832 ) -> Subscription {
4833 let window_handle = self.handle;
4834 let (subscription, activate) = cx.global_observers.insert(
4835 TypeId::of::<G>(),
4836 Box::new(move |cx| {
4837 window_handle
4838 .update(cx, |_, window, cx| f(window, cx))
4839 .is_ok()
4840 }),
4841 );
4842 cx.defer(move |_| activate());
4843 subscription
4844 }
4845
4846 /// Focus the current window and bring it to the foreground at the platform level.
4847 pub fn activate_window(&self) {
4848 self.platform_window.activate();
4849 }
4850
4851 /// Minimize the current window at the platform level.
4852 pub fn minimize_window(&self) {
4853 self.platform_window.minimize();
4854 }
4855
4856 /// Toggle full screen status on the current window at the platform level.
4857 pub fn toggle_fullscreen(&self) {
4858 self.platform_window.toggle_fullscreen();
4859 }
4860
4861 /// Updates the IME panel position suggestions for languages like japanese, chinese.
4862 pub fn invalidate_character_coordinates(&self) {
4863 self.on_next_frame(|window, cx| {
4864 if let Some(mut input_handler) = window.platform_window.take_input_handler() {
4865 if let Some(bounds) = input_handler.selected_bounds(window, cx) {
4866 window.platform_window.update_ime_position(bounds);
4867 }
4868 window.platform_window.set_input_handler(input_handler);
4869 }
4870 });
4871 }
4872
4873 /// Present a platform dialog.
4874 /// The provided message will be presented, along with buttons for each answer.
4875 /// When a button is clicked, the returned Receiver will receive the index of the clicked button.
4876 pub fn prompt<T>(
4877 &mut self,
4878 level: PromptLevel,
4879 message: &str,
4880 detail: Option<&str>,
4881 answers: &[T],
4882 cx: &mut App,
4883 ) -> oneshot::Receiver<usize>
4884 where
4885 T: Clone + Into<PromptButton>,
4886 {
4887 let prompt_builder = cx.prompt_builder.take();
4888 let Some(prompt_builder) = prompt_builder else {
4889 unreachable!("Re-entrant window prompting is not supported by GPUI");
4890 };
4891
4892 let answers = answers
4893 .iter()
4894 .map(|answer| answer.clone().into())
4895 .collect::<Vec<_>>();
4896
4897 let receiver = match &prompt_builder {
4898 PromptBuilder::Default => self
4899 .platform_window
4900 .prompt(level, message, detail, &answers)
4901 .unwrap_or_else(|| {
4902 self.build_custom_prompt(&prompt_builder, level, message, detail, &answers, cx)
4903 }),
4904 PromptBuilder::Custom(_) => {
4905 self.build_custom_prompt(&prompt_builder, level, message, detail, &answers, cx)
4906 }
4907 };
4908
4909 cx.prompt_builder = Some(prompt_builder);
4910
4911 receiver
4912 }
4913
4914 fn build_custom_prompt(
4915 &mut self,
4916 prompt_builder: &PromptBuilder,
4917 level: PromptLevel,
4918 message: &str,
4919 detail: Option<&str>,
4920 answers: &[PromptButton],
4921 cx: &mut App,
4922 ) -> oneshot::Receiver<usize> {
4923 let (sender, receiver) = oneshot::channel();
4924 let handle = PromptHandle::new(sender);
4925 let handle = (prompt_builder)(level, message, detail, answers, handle, self, cx);
4926 self.prompt = Some(handle);
4927 receiver
4928 }
4929
4930 /// Returns the current context stack.
4931 pub fn context_stack(&self) -> Vec<KeyContext> {
4932 let node_id = self.focus_node_id_in_rendered_frame(self.focus);
4933 let dispatch_tree = &self.rendered_frame.dispatch_tree;
4934 dispatch_tree
4935 .dispatch_path(node_id)
4936 .iter()
4937 .filter_map(move |&node_id| dispatch_tree.node(node_id).context.clone())
4938 .collect()
4939 }
4940
4941 /// Returns all available actions for the focused element.
4942 pub fn available_actions(&self, cx: &App) -> Vec<Box<dyn Action>> {
4943 let node_id = self.focus_node_id_in_rendered_frame(self.focus);
4944 let mut actions = self.rendered_frame.dispatch_tree.available_actions(node_id);
4945 for action_type in cx.global_action_listeners.keys() {
4946 if let Err(ix) = actions.binary_search_by_key(action_type, |a| a.as_any().type_id()) {
4947 let action = cx.actions.build_action_type(action_type).ok();
4948 if let Some(action) = action {
4949 actions.insert(ix, action);
4950 }
4951 }
4952 }
4953 actions
4954 }
4955
4956 /// Returns key bindings that invoke an action on the currently focused element. Bindings are
4957 /// returned in the order they were added. For display, the last binding should take precedence.
4958 pub fn bindings_for_action(&self, action: &dyn Action) -> Vec<KeyBinding> {
4959 self.rendered_frame
4960 .dispatch_tree
4961 .bindings_for_action(action, &self.rendered_frame.dispatch_tree.context_stack)
4962 }
4963
4964 /// Returns the highest precedence key binding that invokes an action on the currently focused
4965 /// element. This is more efficient than getting the last result of `bindings_for_action`.
4966 pub fn highest_precedence_binding_for_action(&self, action: &dyn Action) -> Option<KeyBinding> {
4967 self.rendered_frame
4968 .dispatch_tree
4969 .highest_precedence_binding_for_action(
4970 action,
4971 &self.rendered_frame.dispatch_tree.context_stack,
4972 )
4973 }
4974
4975 /// Returns the key bindings for an action in a context.
4976 pub fn bindings_for_action_in_context(
4977 &self,
4978 action: &dyn Action,
4979 context: KeyContext,
4980 ) -> Vec<KeyBinding> {
4981 let dispatch_tree = &self.rendered_frame.dispatch_tree;
4982 dispatch_tree.bindings_for_action(action, &[context])
4983 }
4984
4985 /// Returns the highest precedence key binding for an action in a context. This is more
4986 /// efficient than getting the last result of `bindings_for_action_in_context`.
4987 pub fn highest_precedence_binding_for_action_in_context(
4988 &self,
4989 action: &dyn Action,
4990 context: KeyContext,
4991 ) -> Option<KeyBinding> {
4992 let dispatch_tree = &self.rendered_frame.dispatch_tree;
4993 dispatch_tree.highest_precedence_binding_for_action(action, &[context])
4994 }
4995
4996 /// Returns any bindings that would invoke an action on the given focus handle if it were
4997 /// focused. Bindings are returned in the order they were added. For display, the last binding
4998 /// should take precedence.
4999 pub fn bindings_for_action_in(
5000 &self,
5001 action: &dyn Action,
5002 focus_handle: &FocusHandle,
5003 ) -> Vec<KeyBinding> {
5004 let dispatch_tree = &self.rendered_frame.dispatch_tree;
5005 let Some(context_stack) = self.context_stack_for_focus_handle(focus_handle) else {
5006 return vec![];
5007 };
5008 dispatch_tree.bindings_for_action(action, &context_stack)
5009 }
5010
5011 /// Returns the highest precedence key binding that would invoke an action on the given focus
5012 /// handle if it were focused. This is more efficient than getting the last result of
5013 /// `bindings_for_action_in`.
5014 pub fn highest_precedence_binding_for_action_in(
5015 &self,
5016 action: &dyn Action,
5017 focus_handle: &FocusHandle,
5018 ) -> Option<KeyBinding> {
5019 let dispatch_tree = &self.rendered_frame.dispatch_tree;
5020 let context_stack = self.context_stack_for_focus_handle(focus_handle)?;
5021 dispatch_tree.highest_precedence_binding_for_action(action, &context_stack)
5022 }
5023
5024 /// Find the bindings that can follow the current input sequence for the current context stack.
5025 pub fn possible_bindings_for_input(&self, input: &[Keystroke]) -> Vec<KeyBinding> {
5026 self.rendered_frame
5027 .dispatch_tree
5028 .possible_next_bindings_for_input(input, &self.context_stack())
5029 }
5030
5031 fn context_stack_for_focus_handle(
5032 &self,
5033 focus_handle: &FocusHandle,
5034 ) -> Option<Vec<KeyContext>> {
5035 let dispatch_tree = &self.rendered_frame.dispatch_tree;
5036 let node_id = dispatch_tree.focusable_node_id(focus_handle.id)?;
5037 let context_stack: Vec<_> = dispatch_tree
5038 .dispatch_path(node_id)
5039 .into_iter()
5040 .filter_map(|node_id| dispatch_tree.node(node_id).context.clone())
5041 .collect();
5042 Some(context_stack)
5043 }
5044
5045 /// Returns a generic event listener that invokes the given listener with the view and context associated with the given view handle.
5046 pub fn listener_for<T: 'static, E>(
5047 &self,
5048 view: &Entity<T>,
5049 f: impl Fn(&mut T, &E, &mut Window, &mut Context<T>) + 'static,
5050 ) -> impl Fn(&E, &mut Window, &mut App) + 'static {
5051 let view = view.downgrade();
5052 move |e: &E, window: &mut Window, cx: &mut App| {
5053 view.update(cx, |view, cx| f(view, e, window, cx)).ok();
5054 }
5055 }
5056
5057 /// Returns a generic handler that invokes the given handler with the view and context associated with the given view handle.
5058 pub fn handler_for<E: 'static, Callback: Fn(&mut E, &mut Window, &mut Context<E>) + 'static>(
5059 &self,
5060 entity: &Entity<E>,
5061 f: Callback,
5062 ) -> impl Fn(&mut Window, &mut App) + 'static {
5063 let entity = entity.downgrade();
5064 move |window: &mut Window, cx: &mut App| {
5065 entity.update(cx, |entity, cx| f(entity, window, cx)).ok();
5066 }
5067 }
5068
5069 /// Register a callback that can interrupt the closing of the current window based the returned boolean.
5070 /// If the callback returns false, the window won't be closed.
5071 pub fn on_window_should_close(
5072 &self,
5073 cx: &App,
5074 f: impl Fn(&mut Window, &mut App) -> bool + 'static,
5075 ) {
5076 let mut cx = self.to_async(cx);
5077 self.platform_window.on_should_close(Box::new(move || {
5078 cx.update(|window, cx| f(window, cx)).unwrap_or(true)
5079 }))
5080 }
5081
5082 /// Register an action listener on this node for the next frame. The type of action
5083 /// is determined by the first parameter of the given listener. When the next frame is rendered
5084 /// the listener will be cleared.
5085 ///
5086 /// This is a fairly low-level method, so prefer using action handlers on elements unless you have
5087 /// a specific need to register a listener yourself.
5088 ///
5089 /// This method should only be called as part of the paint phase of element drawing.
5090 pub fn on_action(
5091 &mut self,
5092 action_type: TypeId,
5093 listener: impl Fn(&dyn Any, DispatchPhase, &mut Window, &mut App) + 'static,
5094 ) {
5095 self.invalidator.debug_assert_paint();
5096
5097 self.next_frame
5098 .dispatch_tree
5099 .on_action(action_type, Rc::new(listener));
5100 }
5101
5102 /// Register a capturing action listener on this node for the next frame if the condition is true.
5103 /// The type of action is determined by the first parameter of the given listener. When the next
5104 /// frame is rendered the listener will be cleared.
5105 ///
5106 /// This is a fairly low-level method, so prefer using action handlers on elements unless you have
5107 /// a specific need to register a listener yourself.
5108 ///
5109 /// This method should only be called as part of the paint phase of element drawing.
5110 pub fn on_action_when(
5111 &mut self,
5112 condition: bool,
5113 action_type: TypeId,
5114 listener: impl Fn(&dyn Any, DispatchPhase, &mut Window, &mut App) + 'static,
5115 ) {
5116 self.invalidator.debug_assert_paint();
5117
5118 if condition {
5119 self.next_frame
5120 .dispatch_tree
5121 .on_action(action_type, Rc::new(listener));
5122 }
5123 }
5124
5125 /// Read information about the GPU backing this window.
5126 /// Currently returns None on Mac and Windows.
5127 pub fn gpu_specs(&self) -> Option<GpuSpecs> {
5128 self.platform_window.gpu_specs()
5129 }
5130
5131 /// Perform titlebar double-click action.
5132 /// This is macOS specific.
5133 pub fn titlebar_double_click(&self) {
5134 self.platform_window.titlebar_double_click();
5135 }
5136
5137 /// Gets the window's title at the platform level.
5138 /// This is macOS specific.
5139 pub fn window_title(&self) -> String {
5140 self.platform_window.get_title()
5141 }
5142
5143 /// Returns a list of all tabbed windows and their titles.
5144 /// This is macOS specific.
5145 pub fn tabbed_windows(&self) -> Option<Vec<SystemWindowTab>> {
5146 self.platform_window.tabbed_windows()
5147 }
5148
5149 /// Returns the tab bar visibility.
5150 /// This is macOS specific.
5151 pub fn tab_bar_visible(&self) -> bool {
5152 self.platform_window.tab_bar_visible()
5153 }
5154
5155 /// Merges all open windows into a single tabbed window.
5156 /// This is macOS specific.
5157 pub fn merge_all_windows(&self) {
5158 self.platform_window.merge_all_windows()
5159 }
5160
5161 /// Moves the tab to a new containing window.
5162 /// This is macOS specific.
5163 pub fn move_tab_to_new_window(&self) {
5164 self.platform_window.move_tab_to_new_window()
5165 }
5166
5167 /// Shows or hides the window tab overview.
5168 /// This is macOS specific.
5169 pub fn toggle_window_tab_overview(&self) {
5170 self.platform_window.toggle_window_tab_overview()
5171 }
5172
5173 /// Sets the tabbing identifier for the window.
5174 /// This is macOS specific.
5175 pub fn set_tabbing_identifier(&self, tabbing_identifier: Option<String>) {
5176 self.platform_window
5177 .set_tabbing_identifier(tabbing_identifier)
5178 }
5179
5180 /// Request the OS to play an alert sound. On some platforms this is associated
5181 /// with the window, for others it's just a simple global function call.
5182 pub fn play_system_bell(&self) {
5183 self.platform_window.play_system_bell()
5184 }
5185
5186 /// Toggles the inspector mode on this window.
5187 #[cfg(any(feature = "inspector", debug_assertions))]
5188 pub fn toggle_inspector(&mut self, cx: &mut App) {
5189 self.inspector = match self.inspector {
5190 None => Some(cx.new(|_| Inspector::new())),
5191 Some(_) => None,
5192 };
5193 self.refresh();
5194 }
5195
5196 /// Returns true if the window is in inspector mode.
5197 pub fn is_inspector_picking(&self, _cx: &App) -> bool {
5198 #[cfg(any(feature = "inspector", debug_assertions))]
5199 {
5200 if let Some(inspector) = &self.inspector {
5201 return inspector.read(_cx).is_picking();
5202 }
5203 }
5204 false
5205 }
5206
5207 /// Executes the provided function with mutable access to an inspector state.
5208 #[cfg(any(feature = "inspector", debug_assertions))]
5209 pub fn with_inspector_state<T: 'static, R>(
5210 &mut self,
5211 _inspector_id: Option<&crate::InspectorElementId>,
5212 cx: &mut App,
5213 f: impl FnOnce(&mut Option<T>, &mut Self) -> R,
5214 ) -> R {
5215 if let Some(inspector_id) = _inspector_id
5216 && let Some(inspector) = &self.inspector
5217 {
5218 let inspector = inspector.clone();
5219 let active_element_id = inspector.read(cx).active_element_id();
5220 if Some(inspector_id) == active_element_id {
5221 return inspector.update(cx, |inspector, _cx| {
5222 inspector.with_active_element_state(self, f)
5223 });
5224 }
5225 }
5226 f(&mut None, self)
5227 }
5228
5229 #[cfg(any(feature = "inspector", debug_assertions))]
5230 pub(crate) fn build_inspector_element_id(
5231 &mut self,
5232 path: crate::InspectorElementPath,
5233 ) -> crate::InspectorElementId {
5234 self.invalidator.debug_assert_paint_or_prepaint();
5235 let path = Rc::new(path);
5236 let next_instance_id = self
5237 .next_frame
5238 .next_inspector_instance_ids
5239 .entry(path.clone())
5240 .or_insert(0);
5241 let instance_id = *next_instance_id;
5242 *next_instance_id += 1;
5243 crate::InspectorElementId { path, instance_id }
5244 }
5245
5246 #[cfg(any(feature = "inspector", debug_assertions))]
5247 fn prepaint_inspector(&mut self, inspector_width: Pixels, cx: &mut App) -> Option<AnyElement> {
5248 if let Some(inspector) = self.inspector.take() {
5249 let mut inspector_element = AnyView::from(inspector.clone()).into_any_element();
5250 inspector_element.prepaint_as_root(
5251 point(self.viewport_size.width - inspector_width, px(0.0)),
5252 size(inspector_width, self.viewport_size.height).into(),
5253 self,
5254 cx,
5255 );
5256 self.inspector = Some(inspector);
5257 Some(inspector_element)
5258 } else {
5259 None
5260 }
5261 }
5262
5263 #[cfg(any(feature = "inspector", debug_assertions))]
5264 fn paint_inspector(&mut self, mut inspector_element: Option<AnyElement>, cx: &mut App) {
5265 if let Some(mut inspector_element) = inspector_element {
5266 inspector_element.paint(self, cx);
5267 };
5268 }
5269
5270 /// Registers a hitbox that can be used for inspector picking mode, allowing users to select and
5271 /// inspect UI elements by clicking on them.
5272 #[cfg(any(feature = "inspector", debug_assertions))]
5273 pub fn insert_inspector_hitbox(
5274 &mut self,
5275 hitbox_id: HitboxId,
5276 inspector_id: Option<&crate::InspectorElementId>,
5277 cx: &App,
5278 ) {
5279 self.invalidator.debug_assert_paint_or_prepaint();
5280 if !self.is_inspector_picking(cx) {
5281 return;
5282 }
5283 if let Some(inspector_id) = inspector_id {
5284 self.next_frame
5285 .inspector_hitboxes
5286 .insert(hitbox_id, inspector_id.clone());
5287 }
5288 }
5289
5290 #[cfg(any(feature = "inspector", debug_assertions))]
5291 fn paint_inspector_hitbox(&mut self, cx: &App) {
5292 if let Some(inspector) = self.inspector.as_ref() {
5293 let inspector = inspector.read(cx);
5294 if let Some((hitbox_id, _)) = self.hovered_inspector_hitbox(inspector, &self.next_frame)
5295 && let Some(hitbox) = self
5296 .next_frame
5297 .hitboxes
5298 .iter()
5299 .find(|hitbox| hitbox.id == hitbox_id)
5300 {
5301 self.paint_quad(crate::fill(hitbox.bounds, crate::rgba(0x61afef4d)));
5302 }
5303 }
5304 }
5305
5306 #[cfg(any(feature = "inspector", debug_assertions))]
5307 fn handle_inspector_mouse_event(&mut self, event: &dyn Any, cx: &mut App) {
5308 let Some(inspector) = self.inspector.clone() else {
5309 return;
5310 };
5311 if event.downcast_ref::<MouseMoveEvent>().is_some() {
5312 inspector.update(cx, |inspector, _cx| {
5313 if let Some((_, inspector_id)) =
5314 self.hovered_inspector_hitbox(inspector, &self.rendered_frame)
5315 {
5316 inspector.hover(inspector_id, self);
5317 }
5318 });
5319 } else if event.downcast_ref::<crate::MouseDownEvent>().is_some() {
5320 inspector.update(cx, |inspector, _cx| {
5321 if let Some((_, inspector_id)) =
5322 self.hovered_inspector_hitbox(inspector, &self.rendered_frame)
5323 {
5324 inspector.select(inspector_id, self);
5325 }
5326 });
5327 } else if let Some(event) = event.downcast_ref::<crate::ScrollWheelEvent>() {
5328 // This should be kept in sync with SCROLL_LINES in x11 platform.
5329 const SCROLL_LINES: f32 = 3.0;
5330 const SCROLL_PIXELS_PER_LAYER: f32 = 36.0;
5331 let delta_y = event
5332 .delta
5333 .pixel_delta(px(SCROLL_PIXELS_PER_LAYER / SCROLL_LINES))
5334 .y;
5335 if let Some(inspector) = self.inspector.clone() {
5336 inspector.update(cx, |inspector, _cx| {
5337 if let Some(depth) = inspector.pick_depth.as_mut() {
5338 *depth += f32::from(delta_y) / SCROLL_PIXELS_PER_LAYER;
5339 let max_depth = self.mouse_hit_test.ids.len() as f32 - 0.5;
5340 if *depth < 0.0 {
5341 *depth = 0.0;
5342 } else if *depth > max_depth {
5343 *depth = max_depth;
5344 }
5345 if let Some((_, inspector_id)) =
5346 self.hovered_inspector_hitbox(inspector, &self.rendered_frame)
5347 {
5348 inspector.set_active_element_id(inspector_id, self);
5349 }
5350 }
5351 });
5352 }
5353 }
5354 }
5355
5356 #[cfg(any(feature = "inspector", debug_assertions))]
5357 fn hovered_inspector_hitbox(
5358 &self,
5359 inspector: &Inspector,
5360 frame: &Frame,
5361 ) -> Option<(HitboxId, crate::InspectorElementId)> {
5362 if let Some(pick_depth) = inspector.pick_depth {
5363 let depth = (pick_depth as i64).try_into().unwrap_or(0);
5364 let max_skipped = self.mouse_hit_test.ids.len().saturating_sub(1);
5365 let skip_count = (depth as usize).min(max_skipped);
5366 for hitbox_id in self.mouse_hit_test.ids.iter().skip(skip_count) {
5367 if let Some(inspector_id) = frame.inspector_hitboxes.get(hitbox_id) {
5368 return Some((*hitbox_id, inspector_id.clone()));
5369 }
5370 }
5371 }
5372 None
5373 }
5374
5375 /// For testing: set the current modifier keys state.
5376 /// This does not generate any events.
5377 #[cfg(any(test, feature = "test-support"))]
5378 pub fn set_modifiers(&mut self, modifiers: Modifiers) {
5379 self.modifiers = modifiers;
5380 }
5381
5382 /// For testing: simulate a mouse move event to the given position.
5383 /// This dispatches the event through the normal event handling path,
5384 /// which will trigger hover states and tooltips.
5385 #[cfg(any(test, feature = "test-support"))]
5386 pub fn simulate_mouse_move(&mut self, position: Point<Pixels>, cx: &mut App) {
5387 let event = PlatformInput::MouseMove(MouseMoveEvent {
5388 position,
5389 modifiers: self.modifiers,
5390 pressed_button: None,
5391 });
5392 let _ = self.dispatch_event(event, cx);
5393 }
5394}
5395
5396// #[derive(Clone, Copy, Eq, PartialEq, Hash)]
5397slotmap::new_key_type! {
5398 /// A unique identifier for a window.
5399 pub struct WindowId;
5400}
5401
5402impl WindowId {
5403 /// Converts this window ID to a `u64`.
5404 pub fn as_u64(&self) -> u64 {
5405 self.0.as_ffi()
5406 }
5407}
5408
5409impl From<u64> for WindowId {
5410 fn from(value: u64) -> Self {
5411 WindowId(slotmap::KeyData::from_ffi(value))
5412 }
5413}
5414
5415/// A handle to a window with a specific root view type.
5416/// Note that this does not keep the window alive on its own.
5417#[derive(Deref, DerefMut)]
5418pub struct WindowHandle<V> {
5419 #[deref]
5420 #[deref_mut]
5421 pub(crate) any_handle: AnyWindowHandle,
5422 state_type: PhantomData<fn(V) -> V>,
5423}
5424
5425impl<V> Debug for WindowHandle<V> {
5426 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5427 f.debug_struct("WindowHandle")
5428 .field("any_handle", &self.any_handle.id.as_u64())
5429 .finish()
5430 }
5431}
5432
5433impl<V: 'static + Render> WindowHandle<V> {
5434 /// Creates a new handle from a window ID.
5435 /// This does not check if the root type of the window is `V`.
5436 pub fn new(id: WindowId) -> Self {
5437 WindowHandle {
5438 any_handle: AnyWindowHandle {
5439 id,
5440 state_type: TypeId::of::<V>(),
5441 },
5442 state_type: PhantomData,
5443 }
5444 }
5445
5446 /// Get the root view out of this window.
5447 ///
5448 /// This will fail if the window is closed or if the root view's type does not match `V`.
5449 #[cfg(any(test, feature = "test-support"))]
5450 pub fn root<C>(&self, cx: &mut C) -> Result<Entity<V>>
5451 where
5452 C: AppContext,
5453 {
5454 cx.update_window(self.any_handle, |root_view, _, _| {
5455 root_view
5456 .downcast::<V>()
5457 .map_err(|_| anyhow!("the type of the window's root view has changed"))
5458 })?
5459 }
5460
5461 /// Updates the root view of this window.
5462 ///
5463 /// This will fail if the window has been closed or if the root view's type does not match
5464 pub fn update<C, R>(
5465 &self,
5466 cx: &mut C,
5467 update: impl FnOnce(&mut V, &mut Window, &mut Context<V>) -> R,
5468 ) -> Result<R>
5469 where
5470 C: AppContext,
5471 {
5472 cx.update_window(self.any_handle, |root_view, window, cx| {
5473 let view = root_view
5474 .downcast::<V>()
5475 .map_err(|_| anyhow!("the type of the window's root view has changed"))?;
5476
5477 Ok(view.update(cx, |view, cx| update(view, window, cx)))
5478 })?
5479 }
5480
5481 /// Read the root view out of this window.
5482 ///
5483 /// This will fail if the window is closed or if the root view's type does not match `V`.
5484 pub fn read<'a>(&self, cx: &'a App) -> Result<&'a V> {
5485 let x = cx
5486 .windows
5487 .get(self.id)
5488 .and_then(|window| {
5489 window
5490 .as_deref()
5491 .and_then(|window| window.root.clone())
5492 .map(|root_view| root_view.downcast::<V>())
5493 })
5494 .context("window not found")?
5495 .map_err(|_| anyhow!("the type of the window's root view has changed"))?;
5496
5497 Ok(x.read(cx))
5498 }
5499
5500 /// Read the root view out of this window, with a callback
5501 ///
5502 /// This will fail if the window is closed or if the root view's type does not match `V`.
5503 pub fn read_with<C, R>(&self, cx: &C, read_with: impl FnOnce(&V, &App) -> R) -> Result<R>
5504 where
5505 C: AppContext,
5506 {
5507 cx.read_window(self, |root_view, cx| read_with(root_view.read(cx), cx))
5508 }
5509
5510 /// Read the root view pointer off of this window.
5511 ///
5512 /// This will fail if the window is closed or if the root view's type does not match `V`.
5513 pub fn entity<C>(&self, cx: &C) -> Result<Entity<V>>
5514 where
5515 C: AppContext,
5516 {
5517 cx.read_window(self, |root_view, _cx| root_view)
5518 }
5519
5520 /// Check if this window is 'active'.
5521 ///
5522 /// Will return `None` if the window is closed or currently
5523 /// borrowed.
5524 pub fn is_active(&self, cx: &mut App) -> Option<bool> {
5525 cx.update_window(self.any_handle, |_, window, _| window.is_window_active())
5526 .ok()
5527 }
5528}
5529
5530impl<V> Copy for WindowHandle<V> {}
5531
5532impl<V> Clone for WindowHandle<V> {
5533 fn clone(&self) -> Self {
5534 *self
5535 }
5536}
5537
5538impl<V> PartialEq for WindowHandle<V> {
5539 fn eq(&self, other: &Self) -> bool {
5540 self.any_handle == other.any_handle
5541 }
5542}
5543
5544impl<V> Eq for WindowHandle<V> {}
5545
5546impl<V> Hash for WindowHandle<V> {
5547 fn hash<H: Hasher>(&self, state: &mut H) {
5548 self.any_handle.hash(state);
5549 }
5550}
5551
5552impl<V: 'static> From<WindowHandle<V>> for AnyWindowHandle {
5553 fn from(val: WindowHandle<V>) -> Self {
5554 val.any_handle
5555 }
5556}
5557
5558/// A handle to a window with any root view type, which can be downcast to a window with a specific root view type.
5559#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
5560pub struct AnyWindowHandle {
5561 pub(crate) id: WindowId,
5562 state_type: TypeId,
5563}
5564
5565impl AnyWindowHandle {
5566 /// Get the ID of this window.
5567 pub fn window_id(&self) -> WindowId {
5568 self.id
5569 }
5570
5571 /// Attempt to convert this handle to a window handle with a specific root view type.
5572 /// If the types do not match, this will return `None`.
5573 pub fn downcast<T: 'static>(&self) -> Option<WindowHandle<T>> {
5574 if TypeId::of::<T>() == self.state_type {
5575 Some(WindowHandle {
5576 any_handle: *self,
5577 state_type: PhantomData,
5578 })
5579 } else {
5580 None
5581 }
5582 }
5583
5584 /// Updates the state of the root view of this window.
5585 ///
5586 /// This will fail if the window has been closed.
5587 pub fn update<C, R>(
5588 self,
5589 cx: &mut C,
5590 update: impl FnOnce(AnyView, &mut Window, &mut App) -> R,
5591 ) -> Result<R>
5592 where
5593 C: AppContext,
5594 {
5595 cx.update_window(self, update)
5596 }
5597
5598 /// Read the state of the root view of this window.
5599 ///
5600 /// This will fail if the window has been closed.
5601 pub fn read<T, C, R>(self, cx: &C, read: impl FnOnce(Entity<T>, &App) -> R) -> Result<R>
5602 where
5603 C: AppContext,
5604 T: 'static,
5605 {
5606 let view = self
5607 .downcast::<T>()
5608 .context("the type of the window's root view has changed")?;
5609
5610 cx.read_window(&view, read)
5611 }
5612}
5613
5614impl HasWindowHandle for Window {
5615 fn window_handle(&self) -> Result<raw_window_handle::WindowHandle<'_>, HandleError> {
5616 self.platform_window.window_handle()
5617 }
5618}
5619
5620impl HasDisplayHandle for Window {
5621 fn display_handle(
5622 &self,
5623 ) -> std::result::Result<raw_window_handle::DisplayHandle<'_>, HandleError> {
5624 self.platform_window.display_handle()
5625 }
5626}
5627
5628/// An identifier for an [`Element`].
5629///
5630/// Can be constructed with a string, a number, or both, as well
5631/// as other internal representations.
5632#[derive(Clone, Debug, Eq, PartialEq, Hash)]
5633pub enum ElementId {
5634 /// The ID of a View element
5635 View(EntityId),
5636 /// An integer ID.
5637 Integer(u64),
5638 /// A string based ID.
5639 Name(SharedString),
5640 /// A UUID.
5641 Uuid(Uuid),
5642 /// An ID that's equated with a focus handle.
5643 FocusHandle(FocusId),
5644 /// A combination of a name and an integer.
5645 NamedInteger(SharedString, u64),
5646 /// A path.
5647 Path(Arc<std::path::Path>),
5648 /// A code location.
5649 CodeLocation(core::panic::Location<'static>),
5650 /// A labeled child of an element.
5651 NamedChild(Arc<ElementId>, SharedString),
5652 /// A byte array ID (used for text-anchors)
5653 OpaqueId([u8; 20]),
5654}
5655
5656impl ElementId {
5657 /// Constructs an `ElementId::NamedInteger` from a name and `usize`.
5658 pub fn named_usize(name: impl Into<SharedString>, integer: usize) -> ElementId {
5659 Self::NamedInteger(name.into(), integer as u64)
5660 }
5661}
5662
5663impl Display for ElementId {
5664 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5665 match self {
5666 ElementId::View(entity_id) => write!(f, "view-{}", entity_id)?,
5667 ElementId::Integer(ix) => write!(f, "{}", ix)?,
5668 ElementId::Name(name) => write!(f, "{}", name)?,
5669 ElementId::FocusHandle(_) => write!(f, "FocusHandle")?,
5670 ElementId::NamedInteger(s, i) => write!(f, "{}-{}", s, i)?,
5671 ElementId::Uuid(uuid) => write!(f, "{}", uuid)?,
5672 ElementId::Path(path) => write!(f, "{}", path.display())?,
5673 ElementId::CodeLocation(location) => write!(f, "{}", location)?,
5674 ElementId::NamedChild(id, name) => write!(f, "{}-{}", id, name)?,
5675 ElementId::OpaqueId(opaque_id) => write!(f, "{:x?}", opaque_id)?,
5676 }
5677
5678 Ok(())
5679 }
5680}
5681
5682impl TryInto<SharedString> for ElementId {
5683 type Error = anyhow::Error;
5684
5685 fn try_into(self) -> anyhow::Result<SharedString> {
5686 if let ElementId::Name(name) = self {
5687 Ok(name)
5688 } else {
5689 anyhow::bail!("element id is not string")
5690 }
5691 }
5692}
5693
5694impl From<usize> for ElementId {
5695 fn from(id: usize) -> Self {
5696 ElementId::Integer(id as u64)
5697 }
5698}
5699
5700impl From<i32> for ElementId {
5701 fn from(id: i32) -> Self {
5702 Self::Integer(id as u64)
5703 }
5704}
5705
5706impl From<SharedString> for ElementId {
5707 fn from(name: SharedString) -> Self {
5708 ElementId::Name(name)
5709 }
5710}
5711
5712impl From<String> for ElementId {
5713 fn from(name: String) -> Self {
5714 ElementId::Name(name.into())
5715 }
5716}
5717
5718impl From<Arc<str>> for ElementId {
5719 fn from(name: Arc<str>) -> Self {
5720 ElementId::Name(name.into())
5721 }
5722}
5723
5724impl From<Arc<std::path::Path>> for ElementId {
5725 fn from(path: Arc<std::path::Path>) -> Self {
5726 ElementId::Path(path)
5727 }
5728}
5729
5730impl From<&'static str> for ElementId {
5731 fn from(name: &'static str) -> Self {
5732 ElementId::Name(name.into())
5733 }
5734}
5735
5736impl<'a> From<&'a FocusHandle> for ElementId {
5737 fn from(handle: &'a FocusHandle) -> Self {
5738 ElementId::FocusHandle(handle.id)
5739 }
5740}
5741
5742impl From<(&'static str, EntityId)> for ElementId {
5743 fn from((name, id): (&'static str, EntityId)) -> Self {
5744 ElementId::NamedInteger(name.into(), id.as_u64())
5745 }
5746}
5747
5748impl From<(&'static str, usize)> for ElementId {
5749 fn from((name, id): (&'static str, usize)) -> Self {
5750 ElementId::NamedInteger(name.into(), id as u64)
5751 }
5752}
5753
5754impl From<(SharedString, usize)> for ElementId {
5755 fn from((name, id): (SharedString, usize)) -> Self {
5756 ElementId::NamedInteger(name, id as u64)
5757 }
5758}
5759
5760impl From<(&'static str, u64)> for ElementId {
5761 fn from((name, id): (&'static str, u64)) -> Self {
5762 ElementId::NamedInteger(name.into(), id)
5763 }
5764}
5765
5766impl From<Uuid> for ElementId {
5767 fn from(value: Uuid) -> Self {
5768 Self::Uuid(value)
5769 }
5770}
5771
5772impl From<(&'static str, u32)> for ElementId {
5773 fn from((name, id): (&'static str, u32)) -> Self {
5774 ElementId::NamedInteger(name.into(), id.into())
5775 }
5776}
5777
5778impl<T: Into<SharedString>> From<(ElementId, T)> for ElementId {
5779 fn from((id, name): (ElementId, T)) -> Self {
5780 ElementId::NamedChild(Arc::new(id), name.into())
5781 }
5782}
5783
5784impl From<&'static core::panic::Location<'static>> for ElementId {
5785 fn from(location: &'static core::panic::Location<'static>) -> Self {
5786 ElementId::CodeLocation(*location)
5787 }
5788}
5789
5790impl From<[u8; 20]> for ElementId {
5791 fn from(opaque_id: [u8; 20]) -> Self {
5792 ElementId::OpaqueId(opaque_id)
5793 }
5794}
5795
5796/// A rectangle to be rendered in the window at the given position and size.
5797/// Passed as an argument [`Window::paint_quad`].
5798#[derive(Clone)]
5799pub struct PaintQuad {
5800 /// The bounds of the quad within the window.
5801 pub bounds: Bounds<Pixels>,
5802 /// The radii of the quad's corners.
5803 pub corner_radii: Corners<Pixels>,
5804 /// The background color of the quad.
5805 pub background: Background,
5806 /// The widths of the quad's borders.
5807 pub border_widths: Edges<Pixels>,
5808 /// The color of the quad's borders.
5809 pub border_color: Hsla,
5810 /// The style of the quad's borders.
5811 pub border_style: BorderStyle,
5812}
5813
5814impl PaintQuad {
5815 /// Sets the corner radii of the quad.
5816 pub fn corner_radii(self, corner_radii: impl Into<Corners<Pixels>>) -> Self {
5817 PaintQuad {
5818 corner_radii: corner_radii.into(),
5819 ..self
5820 }
5821 }
5822
5823 /// Sets the border widths of the quad.
5824 pub fn border_widths(self, border_widths: impl Into<Edges<Pixels>>) -> Self {
5825 PaintQuad {
5826 border_widths: border_widths.into(),
5827 ..self
5828 }
5829 }
5830
5831 /// Sets the border color of the quad.
5832 pub fn border_color(self, border_color: impl Into<Hsla>) -> Self {
5833 PaintQuad {
5834 border_color: border_color.into(),
5835 ..self
5836 }
5837 }
5838
5839 /// Sets the background color of the quad.
5840 pub fn background(self, background: impl Into<Background>) -> Self {
5841 PaintQuad {
5842 background: background.into(),
5843 ..self
5844 }
5845 }
5846}
5847
5848/// Creates a quad with the given parameters.
5849pub fn quad(
5850 bounds: Bounds<Pixels>,
5851 corner_radii: impl Into<Corners<Pixels>>,
5852 background: impl Into<Background>,
5853 border_widths: impl Into<Edges<Pixels>>,
5854 border_color: impl Into<Hsla>,
5855 border_style: BorderStyle,
5856) -> PaintQuad {
5857 PaintQuad {
5858 bounds,
5859 corner_radii: corner_radii.into(),
5860 background: background.into(),
5861 border_widths: border_widths.into(),
5862 border_color: border_color.into(),
5863 border_style,
5864 }
5865}
5866
5867/// Creates a filled quad with the given bounds and background color.
5868pub fn fill(bounds: impl Into<Bounds<Pixels>>, background: impl Into<Background>) -> PaintQuad {
5869 PaintQuad {
5870 bounds: bounds.into(),
5871 corner_radii: (0.).into(),
5872 background: background.into(),
5873 border_widths: (0.).into(),
5874 border_color: transparent_black(),
5875 border_style: BorderStyle::default(),
5876 }
5877}
5878
5879/// Creates a rectangle outline with the given bounds, border color, and a 1px border width
5880pub fn outline(
5881 bounds: impl Into<Bounds<Pixels>>,
5882 border_color: impl Into<Hsla>,
5883 border_style: BorderStyle,
5884) -> PaintQuad {
5885 PaintQuad {
5886 bounds: bounds.into(),
5887 corner_radii: (0.).into(),
5888 background: transparent_black().into(),
5889 border_widths: (1.).into(),
5890 border_color: border_color.into(),
5891 border_style,
5892 }
5893}