Skip to main content

i_slint_core/
window.rs

1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
3
4// cSpell: ignore backtab componentrc datastructure subelements unmaximized unminimized
5
6#![warn(missing_docs)]
7//! Exposed Window API
8use crate::api::{
9    CloseRequestResponse, LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize,
10    PlatformError, Window, WindowPosition, WindowSize,
11};
12use crate::input::{
13    ClickState, DragData, FocusEvent, FocusReason, InternalKeyEvent, KeyEventResult, KeyEventType,
14    Keys, MouseEvent, MouseInputState, PointerEventButton, TextCursorBlinker, TouchPhase,
15    TouchState, key_codes,
16};
17use crate::item_tree::{
18    ItemRc, ItemTreeRc, ItemTreeRef, ItemTreeRefPin, ItemTreeVTable, ItemTreeWeak, ItemWeak,
19    ParentItemTraversalMode,
20};
21use crate::items::{InputType, ItemRef, MenuEntry, MouseCursor, PopupClosePolicy};
22use crate::lengths::{LogicalLength, LogicalPoint, LogicalRect, LogicalVector, SizeLengths};
23use crate::menus::MenuVTable;
24use crate::properties::{Property, PropertyTracker};
25use crate::renderer::Renderer;
26use crate::{Callback, Coord, SharedString, SharedVector};
27use alloc::boxed::Box;
28use alloc::rc::{Rc, Weak};
29use alloc::vec::Vec;
30use core::cell::{Cell, RefCell};
31use core::num::NonZeroU32;
32use core::pin::Pin;
33use euclid::num::Zero;
34use vtable::{VRc, VRcMapped};
35
36pub mod popup;
37
38fn next_focus_item(item: ItemRc) -> ItemRc {
39    item.next_focus_item()
40}
41
42fn previous_focus_item(item: ItemRc) -> ItemRc {
43    item.previous_focus_item()
44}
45
46/// The window kind when creating a new child window
47#[repr(C)]
48pub enum WindowKind {
49    /// Tooltip
50    ToolTip,
51    /// Popup Window
52    Popup,
53    /// Popup Menu
54    Menu,
55}
56
57/// This trait represents the adaptation layer between the [`Window`] API and then
58/// windowing specific window representation, such as a Win32 `HWND` handle or a `wayland_surface_t`.
59///
60/// Implement this trait to establish the link between the two, and pass messages in both
61/// directions:
62///
63/// - When receiving messages from the windowing system about state changes, such as the window being resized,
64///   the user requested the window to be closed, input being received, etc. you need to create a
65///   [`WindowEvent`](crate::platform::WindowEvent) and send it to Slint via [`Window::try_dispatch_event()`].
66///
67/// - Slint sends requests to change visibility, position, size, etc. via functions such as [`Self::set_visible`],
68///   [`Self::set_size`], [`Self::set_position`], or [`Self::update_window_properties()`]. Re-implement these functions
69///   and delegate the requests to the windowing system.
70///
71/// If the implementation of this bi-directional message passing protocol is incomplete, the user may
72/// experience unexpected behavior, or the intention of the developer calling functions on the [`Window`]
73/// API may not be fulfilled.
74///
75/// Your implementation must hold a renderer, such as `SoftwareRenderer` or `FemtoVGRenderer`.
76/// In the [`Self::renderer()`] function, you must return a reference to it.
77///
78/// It is also required to hold a [`Window`] and return a reference to it in your
79/// implementation of [`Self::window()`].
80///
81/// See also `slint::platform::software_renderer::MinimalSoftwareWindow`
82/// for a minimal implementation of this trait using the software renderer
83pub trait WindowAdapter {
84    /// Returns the window API.
85    fn window(&self) -> &Window;
86
87    /// Show the window if the argument is true, hide otherwise.
88    fn set_visible(&self, _visible: bool) -> Result<(), PlatformError> {
89        Ok(())
90    }
91
92    /// Returns the position of the window on the screen, in physical screen coordinates and including
93    /// a window frame (if present).
94    ///
95    /// The default implementation returns `None`
96    ///
97    /// Called from [`Window::position()`]
98    fn position(&self) -> Option<PhysicalPosition> {
99        None
100    }
101    /// Sets the position of the window on the screen, in physical screen coordinates and including
102    /// a window frame (if present).
103    ///
104    /// The default implementation does nothing
105    ///
106    /// Called from [`Window::set_position()`]
107    fn set_position(&self, _position: WindowPosition) {}
108
109    /// Request a new size for the window to the specified size on the screen, in physical or logical pixels
110    /// and excluding a window frame (if present).
111    ///
112    /// This is called from [`Window::set_size()`]
113    ///
114    /// The default implementation does nothing
115    ///
116    /// This function should sent the size to the Windowing system. If the window size actually changes, you
117    /// should dispatch a [`WindowEvent::Resized`](crate::platform::WindowEvent::Resized) using
118    /// [`Window::dispatch_event()`] to propagate the new size to the slint view
119    fn set_size(&self, _size: WindowSize) {}
120
121    /// Return the size of the Window on the screen
122    fn size(&self) -> PhysicalSize;
123
124    /// Issues a request to the windowing system to re-render the contents of the window.
125    ///
126    /// This request is typically asynchronous.
127    /// It is called when a property that was used during window rendering is marked as dirty.
128    ///
129    /// An implementation should repaint the window in a subsequent iteration of the event loop,
130    /// throttled to the screen refresh rate if possible.
131    /// It is important not to query any Slint properties to avoid introducing a dependency loop in the properties,
132    /// including the use of the render function, which itself queries properties.
133    ///
134    /// See also [`Window::request_redraw()`]
135    fn request_redraw(&self) {}
136
137    /// Return the renderer.
138    ///
139    /// The `Renderer` trait is an internal trait that you are not expected to implement.
140    /// In your implementation you should return a reference to an instance of one of the renderers provided by Slint.
141    fn renderer(&self) -> &dyn Renderer;
142
143    /// Re-implement this function to update the properties such as window title or layout constraints.
144    ///
145    /// This function is called before `set_visible(true)`, and will be called again when the properties
146    /// that were queried on the last call are changed. If you do not query any properties, it may not
147    /// be called again.
148    fn update_window_properties(&self, _properties: WindowProperties<'_>) {}
149
150    #[doc(hidden)]
151    fn internal(&self, _: crate::InternalToken) -> Option<&dyn WindowAdapterInternal> {
152        None
153    }
154
155    /// Re-implement this to support exposing raw window handles (version 0.6).
156    #[cfg(feature = "raw-window-handle-06")]
157    fn window_handle_06(
158        &self,
159    ) -> Result<raw_window_handle_06::WindowHandle<'_>, raw_window_handle_06::HandleError> {
160        Err(raw_window_handle_06::HandleError::NotSupported)
161    }
162
163    /// Re-implement this to support exposing raw display handles (version 0.6).
164    #[cfg(feature = "raw-window-handle-06")]
165    fn display_handle_06(
166        &self,
167    ) -> Result<raw_window_handle_06::DisplayHandle<'_>, raw_window_handle_06::HandleError> {
168        Err(raw_window_handle_06::HandleError::NotSupported)
169    }
170}
171
172/// Implementation details behind [`WindowAdapter`], but since this
173/// trait is not exported in the public API, it is not possible for the
174/// users to call or re-implement these functions.
175// TODO: add events for window receiving and loosing focus
176#[doc(hidden)]
177pub trait WindowAdapterInternal: core::any::Any {
178    /// This function is called by the generated code when a component and therefore its tree of items are created.
179    fn register_item_tree(&self, _: ItemTreeRefPin) {}
180
181    /// This function is called by the generated code when a component and therefore its tree of items are destroyed. The
182    /// implementation typically uses this to free the underlying graphics resources.
183    fn unregister_item_tree(
184        &self,
185        _component: ItemTreeRef,
186        _items: &mut dyn Iterator<Item = Pin<ItemRef<'_>>>,
187    ) {
188    }
189
190    /// Get the parent window adapter of this window adapter
191    fn get_parent(&self) -> Option<Rc<dyn WindowAdapter>> {
192        None
193    }
194
195    /// Create a window for a popup.
196    /// This function will create only the window adapter but does not show the popup it self
197    /// Use this window adapter to create a new popup window and show it with `show_popup()`
198    ///
199    /// If this function return None (the default implementation), then the
200    /// popup will be rendered within the window itself.
201    fn create_child_window_adapter(
202        &self,
203        _window_kind: WindowKind,
204    ) -> Option<Rc<dyn WindowAdapter>> {
205        None
206    }
207
208    /// Set the mouse cursor
209    // TODO: Make the enum public and make public
210    fn set_mouse_cursor(&self, _cursor: MouseCursor) {}
211
212    /// This method allow editable input field to communicate with the platform about input methods
213    fn input_method_request(&self, _: InputMethodRequest) {}
214
215    /// Handle focus change
216    // used for accessibility
217    fn handle_focus_change(&self, _old: Option<ItemRc>, _new: Option<ItemRc>) {}
218
219    /// Returns whether we can have a native menu bar
220    fn supports_native_menu_bar(&self) -> bool {
221        false
222    }
223
224    fn setup_menubar(&self, _menubar: vtable::VRc<MenuVTable>) {}
225
226    fn show_native_popup_menu(
227        &self,
228        _context_menu_item: vtable::VRc<MenuVTable>,
229        _position: LogicalPosition,
230    ) -> bool {
231        false
232    }
233
234    /// Re-implement this to support exposing raw window handles (version 0.6).
235    #[cfg(all(feature = "std", feature = "raw-window-handle-06"))]
236    fn window_handle_06_rc(
237        &self,
238    ) -> Result<
239        std::sync::Arc<dyn raw_window_handle_06::HasWindowHandle>,
240        raw_window_handle_06::HandleError,
241    > {
242        Err(raw_window_handle_06::HandleError::NotSupported)
243    }
244
245    /// Re-implement this to support exposing raw display handles (version 0.6).
246    #[cfg(all(feature = "std", feature = "raw-window-handle-06"))]
247    fn display_handle_06_rc(
248        &self,
249    ) -> Result<
250        std::sync::Arc<dyn raw_window_handle_06::HasDisplayHandle>,
251        raw_window_handle_06::HandleError,
252    > {
253        Err(raw_window_handle_06::HandleError::NotSupported)
254    }
255
256    /// Brings the window to the front and focuses it.
257    fn bring_to_front(&self) -> Result<(), PlatformError> {
258        Ok(())
259    }
260
261    /// Return the inset of the safe area of the Window in physical pixels.
262    /// This is necessary to avoid overlapping system UI such as notches or system bars.
263    fn safe_area_inset(&self) -> crate::lengths::PhysicalEdges {
264        Default::default()
265    }
266}
267
268/// This is the parameter from [`WindowAdapterInternal::input_method_request()`] which lets the editable text input field
269/// communicate with the platform about input methods.
270#[non_exhaustive]
271#[derive(Debug, Clone)]
272pub enum InputMethodRequest {
273    /// Enables the input method with the specified properties.
274    Enable(InputMethodProperties),
275    /// Updates the input method with new properties.
276    Update(InputMethodProperties),
277    /// Disables the input method.
278    Disable,
279}
280
281/// This struct holds properties related to an input method.
282#[non_exhaustive]
283#[derive(Clone, Default, Debug)]
284pub struct InputMethodProperties {
285    /// The text surrounding the cursor.
286    ///
287    /// This field does not include pre-edit text or composition.
288    pub text: SharedString,
289    /// The position of the cursor in bytes within the `text`.
290    pub cursor_position: usize,
291    /// When there is a selection, this is the position of the second anchor
292    /// for the beginning (or the end) of the selection.
293    pub anchor_position: Option<usize>,
294    /// The current value of the pre-edit text as known by the input method.
295    /// This is the text currently being edited but not yet committed.
296    /// When empty, there is no pre-edit text.
297    pub preedit_text: SharedString,
298    /// When the `preedit_text` is not empty, this is the offset of the pre-edit within the `text`.
299    pub preedit_offset: usize,
300    /// The top-left corner of the cursor rectangle in window coordinates.
301    pub cursor_rect_origin: LogicalPosition,
302    /// The size of the cursor rectangle.
303    pub cursor_rect_size: crate::api::LogicalSize,
304    /// The position of the anchor (bottom). Only meaningful if anchor_position is Some
305    pub anchor_point: LogicalPosition,
306    /// The type of input for the text edit.
307    pub input_type: InputType,
308    /// The clip rect in window coordinates
309    pub clip_rect: Option<LogicalRect>,
310}
311
312/// This struct describes layout constraints of a resizable element, such as a window.
313#[non_exhaustive]
314#[derive(Copy, Clone, Debug, PartialEq, Default)]
315pub struct LayoutConstraints {
316    /// The minimum size.
317    pub min: Option<crate::api::LogicalSize>,
318    /// The maximum size.
319    pub max: Option<crate::api::LogicalSize>,
320    /// The preferred size.
321    pub preferred: crate::api::LogicalSize,
322}
323
324/// This struct contains getters that provide access to properties of the `Window`
325/// element, and is used with [`WindowAdapter::update_window_properties`].
326pub struct WindowProperties<'a>(&'a WindowInner);
327
328impl WindowProperties<'_> {
329    /// Returns the Window's title
330    pub fn title(&self) -> SharedString {
331        self.0.window_item().map(|w| w.as_pin_ref().title()).unwrap_or_default()
332    }
333
334    /// The background color or brush of the Window
335    pub fn background(&self) -> crate::Brush {
336        self.0
337            .window_item()
338            .map(|w: VRcMapped<ItemTreeVTable, crate::items::WindowItem>| {
339                w.as_pin_ref().background()
340            })
341            .unwrap_or_default()
342    }
343
344    /// Returns the layout constraints of the window
345    pub fn layout_constraints(&self) -> LayoutConstraints {
346        let component = self.0.component();
347        let component = ItemTreeRc::borrow_pin(&component);
348        let h = component.as_ref().layout_info(crate::layout::Orientation::Horizontal);
349        let v = component.as_ref().layout_info(crate::layout::Orientation::Vertical);
350        let (min, max) = crate::layout::min_max_size_for_layout_constraints(h, v);
351        LayoutConstraints {
352            min,
353            max,
354            preferred: crate::api::LogicalSize::new(
355                h.preferred_bounded() as f32,
356                v.preferred_bounded() as f32,
357            ),
358        }
359    }
360
361    /// Returns true if the window should be shown fullscreen; false otherwise.
362    #[deprecated(note = "Please use `is_fullscreen` instead")]
363    pub fn fullscreen(&self) -> bool {
364        self.is_fullscreen()
365    }
366
367    /// Returns true if the window should be shown fullscreen; false otherwise.
368    pub fn is_fullscreen(&self) -> bool {
369        self.0.is_fullscreen()
370    }
371
372    /// true if the window is in a maximized state, otherwise false
373    pub fn is_maximized(&self) -> bool {
374        self.0.is_maximized()
375    }
376
377    /// true if the window is in a minimized state, otherwise false
378    pub fn is_minimized(&self) -> bool {
379        self.0.is_minimized()
380    }
381}
382
383struct WindowPropertiesTracker {
384    window_adapter_weak: Weak<dyn WindowAdapter>,
385}
386
387impl crate::properties::PropertyDirtyHandler for WindowPropertiesTracker {
388    fn notify(self: Pin<&Self>) {
389        let win = self.window_adapter_weak.clone();
390        crate::timers::Timer::single_shot(Default::default(), move || {
391            if let Some(window_adapter) = win.upgrade() {
392                WindowInner::from_pub(window_adapter.window()).update_window_properties();
393            };
394        })
395    }
396}
397
398pub(crate) struct PopupWindowPropertiesTracker {
399    /// Weak reference to the parent window that owns the active_popups list
400    parent_window_adapter_weak: Weak<dyn WindowAdapter>,
401    /// ID of the popup this tracker belongs to, used to re-evaluate after notification
402    popup_id: NonZeroU32,
403}
404
405impl crate::properties::PropertyDirtyHandler for PopupWindowPropertiesTracker {
406    fn notify(self: Pin<&Self>) {
407        let parent = self.parent_window_adapter_weak.clone();
408        let popup_id = self.popup_id;
409        // Use a timer here, so if we change multiple properties at the same time not multiple notifications are send
410        // This timer will delay for the next evaluation
411        crate::timers::Timer::single_shot(Default::default(), move || {
412            if let Some(parent_adapter) = parent.upgrade() {
413                WindowInner::from_pub(parent_adapter.window()).update_popup_properties(popup_id);
414            }
415        });
416    }
417}
418
419struct WindowRedrawTracker {
420    window_adapter_weak: Weak<dyn WindowAdapter>,
421}
422
423impl crate::properties::PropertyDirtyHandler for WindowRedrawTracker {
424    fn notify(self: Pin<&Self>) {
425        if let Some(window_adapter) = self.window_adapter_weak.upgrade() {
426            window_adapter.request_redraw();
427        };
428    }
429}
430
431/// This enum describes the different ways a popup can be rendered by the back-end.
432pub enum PopupWindowLocation {
433    /// The popup is rendered in its own top-level window that is know to the windowing system.
434    TopLevel(Rc<dyn WindowAdapter>),
435    /// The popup is rendered as an embedded child window at the given position.
436    ChildWindow(LogicalPoint),
437}
438
439/// This structure defines a graphical element that is designed to pop up from the surrounding
440/// UI content, for example to show a context menu.
441pub struct PopupWindow {
442    /// The ID of the associated popup.
443    pub popup_id: NonZeroU32,
444    /// The location defines where the pop up is rendered.
445    pub location: PopupWindowLocation,
446    /// The component that is responsible for providing the popup content.
447    pub component: ItemTreeRc,
448    /// Defines the close behavior of the popup.
449    pub close_policy: PopupClosePolicy,
450    /// the item that had the focus in the parent window when the popup was opened
451    focus_item_in_parent: ItemWeak,
452    /// The item from where the Popup was invoked from
453    pub parent_item: ItemWeak,
454    /// Overlay tooltip: no focus steal, unclamped placement, skipped in main mouse routing.
455    /// Context / popup menu: participates in menu-chain hit testing and cascading close.
456    pub window_kind: WindowKind,
457    /// Callback that returns the current desired logical position of the popup.
458    /// Called during re-evaluation of the position tracker to re-subscribe to dependencies.
459    /// IMPORTANT: This position is relative to the parent
460    position_access: Box<dyn Fn() -> LogicalPosition>,
461    /// Keeps the parent component's `PopupWindow::is-open` property in sync. Provided to
462    /// [`WindowInner::show_popup`], invoked with `true` when the popup is shown and with `false` when
463    /// this `PopupWindow` is dropped (see the `Drop` impl below). It is a no-op for popups whose
464    /// parent does not read `is-open` (menus and tooltips).
465    is_open_setter: Box<dyn Fn(bool)>,
466    // tracks all relevant properties and reacts on changes
467    properties_tracker: Pin<Box<PropertyTracker<true, PopupWindowPropertiesTracker>>>,
468}
469
470impl Drop for PopupWindow {
471    fn drop(&mut self) {
472        // Dropping the `PopupWindow` is the single choke point that every close path funnels through
473        // (click-outside, selection, programmatic `close()`, sibling replacement, window change,
474        // Escape, and tearing down the window itself), so flip the parent's `is-open` back to false
475        // here rather than in any individual close function.
476        (self.is_open_setter)(false);
477    }
478}
479
480#[pin_project::pin_project]
481struct WindowPinnedFields {
482    #[pin]
483    redraw_tracker: PropertyTracker<false, WindowRedrawTracker>,
484    /// Gets dirty when the layout restrictions, or some other property of the windows change
485    #[pin]
486    window_properties_tracker: PropertyTracker<true, WindowPropertiesTracker>,
487    #[pin]
488    scale_factor: Property<f32>,
489    #[pin]
490    active: Property<bool>,
491    #[pin]
492    text_input_focused: Property<bool>,
493    #[pin]
494    menubar_shortcuts: Property<SharedVector<MenuEntry>>,
495}
496
497/// The outcome of dispatching a [`MouseEvent`] through [`WindowInner::process_mouse_input`].
498#[derive(Copy, Clone, Debug)]
499pub struct MouseDispatchResult {
500    /// For `MouseEvent::DragMove` / `MouseEvent::Drop` events, the action negotiated with
501    /// the accepting `DropArea` (or `None` if no `DropArea` accepted). Always `None` for
502    /// other event kinds.
503    pub drag_action: Option<crate::items::DragAction>,
504    /// `true` if an item consumed the event (`EventAccepted`, `GrabMouse`, `StartDrag`, or
505    /// a `DropArea` accepting a drag/drop). `false` if the event fell through without a taker.
506    pub accepted: bool,
507}
508
509/// Inner datastructure for the [`crate::api::Window`]
510pub struct WindowInner {
511    window_adapter_weak: Weak<dyn WindowAdapter>,
512    component: RefCell<ItemTreeWeak>,
513    /// When the window is visible, keep a strong reference
514    strong_component_ref: RefCell<Option<ItemTreeRc>>,
515    mouse_input_state: Cell<MouseInputState>,
516    touch_state: RefCell<TouchState>,
517
518    /// ItemRC that currently have the focus (possibly an instance of TextInput)
519    pub focus_item: RefCell<crate::item_tree::ItemWeak>,
520    /// The last text that was sent to the input method
521    pub(crate) last_ime_text: RefCell<SharedString>,
522    /// Don't let ComponentContainers's instantiation change the focus.
523    /// This is a workaround for a recursion when instantiating ComponentContainer because the
524    /// init code for the component might have code that sets the focus, but we don't want that
525    /// for the ComponentContainer
526    pub(crate) prevent_focus_change: Cell<bool>,
527    cursor_blinker: RefCell<pin_weak::rc::PinWeak<crate::input::TextCursorBlinker>>,
528
529    pinned_fields: Pin<Box<WindowPinnedFields>>,
530
531    menubar: RefCell<Option<vtable::VWeak<MenuVTable>>>,
532
533    /// Stack of currently active popups
534    pub active_popups: RefCell<Vec<PopupWindow>>,
535    next_popup_id: Cell<NonZeroU32>,
536    had_popup_on_press: Cell<bool>,
537    close_requested: Callback<(), CloseRequestResponse>,
538    click_state: ClickState,
539    ctx: core::cell::OnceCell<crate::SlintContext>,
540}
541
542impl Drop for WindowInner {
543    fn drop(&mut self) {
544        if let Some(existing_blinker) = self.cursor_blinker.borrow().upgrade() {
545            existing_blinker.stop();
546        }
547    }
548}
549
550impl WindowInner {
551    /// Create a new instance of the window, given the window_adapter factory fn
552    pub fn new(window_adapter_weak: Weak<dyn WindowAdapter>) -> Self {
553        #![allow(unused_mut)]
554
555        let mut window_properties_tracker =
556            PropertyTracker::new_with_dirty_handler(WindowPropertiesTracker {
557                window_adapter_weak: window_adapter_weak.clone(),
558            });
559
560        let mut redraw_tracker = PropertyTracker::new_with_dirty_handler(WindowRedrawTracker {
561            window_adapter_weak: window_adapter_weak.clone(),
562        });
563
564        #[cfg(slint_debug_property)]
565        {
566            window_properties_tracker
567                .set_debug_name("i_slint_core::Window::window_properties_tracker".into());
568            redraw_tracker.set_debug_name("i_slint_core::Window::redraw_tracker".into());
569        }
570
571        Self {
572            window_adapter_weak,
573            component: Default::default(),
574            strong_component_ref: Default::default(),
575            mouse_input_state: Default::default(),
576            touch_state: Default::default(),
577            pinned_fields: Box::pin(WindowPinnedFields {
578                redraw_tracker,
579                window_properties_tracker,
580                scale_factor: Property::new_named(1., "i_slint_core::Window::scale_factor"),
581                active: Property::new_named(false, "i_slint_core::Window::active"),
582                text_input_focused: Property::new_named(
583                    false,
584                    "i_slint_core::Window::text_input_focused",
585                ),
586                menubar_shortcuts: Property::new_named(
587                    SharedVector::default(),
588                    "i_slint_core::Window::menubar_shortcuts",
589                ),
590            }),
591            focus_item: Default::default(),
592            last_ime_text: Default::default(),
593            cursor_blinker: Default::default(),
594            active_popups: Default::default(),
595            next_popup_id: Cell::new(NonZeroU32::MIN),
596            had_popup_on_press: Default::default(),
597            close_requested: Default::default(),
598            click_state: ClickState::default(),
599            prevent_focus_change: Default::default(),
600            ctx: Default::default(),
601            menubar: Default::default(),
602        }
603    }
604
605    /// Associates this window with the specified component. Further event handling and rendering, etc. will be
606    /// done with that component.
607    pub fn set_component(&self, component: &ItemTreeRc) {
608        self.close_all_popups();
609        self.focus_item.replace(Default::default());
610        self.mouse_input_state.replace(Default::default());
611        self.touch_state.replace(Default::default());
612        self.component.replace(ItemTreeRc::downgrade(component));
613        self.pinned_fields.window_properties_tracker.set_dirty(); // component changed, layout constraints for sure must be re-calculated
614        let window_adapter = self.window_adapter();
615        window_adapter.renderer().set_window_adapter(&window_adapter);
616        let scale_factor = self.scale_factor();
617        self.set_window_item_geometry(window_adapter.size().to_logical(scale_factor).to_euclid());
618        let inset = window_adapter
619            .internal(crate::InternalToken)
620            .map(|internal| internal.safe_area_inset())
621            .unwrap_or_default();
622        self.set_window_item_safe_area(inset.to_logical(scale_factor));
623        window_adapter.request_redraw();
624        let weak = Rc::downgrade(&window_adapter);
625        crate::timers::Timer::single_shot(Default::default(), move || {
626            if let Some(window_adapter) = weak.upgrade() {
627                WindowInner::from_pub(window_adapter.window()).update_window_properties();
628            }
629        })
630    }
631
632    /// return the component.
633    /// Panics if it wasn't set.
634    pub fn component(&self) -> ItemTreeRc {
635        self.component.borrow().upgrade().unwrap()
636    }
637
638    /// returns the component or None if it isn't set.
639    pub fn try_component(&self) -> Option<ItemTreeRc> {
640        self.component.borrow().upgrade()
641    }
642
643    /// Walk the component tree and every active popup to materialize every
644    /// Repeater, Conditional and ComponentContainer.  Runs change handlers
645    /// and the instantiation pass in a loop because init callbacks may set
646    /// properties that trigger change handlers, and change handlers may
647    /// make new conditionals/repeaters dirty.
648    pub fn ensure_tree_instantiated(&self) {
649        // Instantiation runs first so that ListView's ensure_updated_listview
650        // sees the model property before any change handler can reset it.
651        for _ in 0..10 {
652            let mut changed = false;
653            if let Some(component) = self.try_component() {
654                changed |= crate::item_tree::ensure_item_tree_instantiated(&component);
655            }
656            for popup in self.active_popups.borrow().iter() {
657                changed |= crate::item_tree::ensure_item_tree_instantiated(&popup.component);
658            }
659            changed |= crate::properties::ChangeTracker::run_change_handlers_once();
660            if !changed {
661                return;
662            }
663        }
664        crate::debug_log!("Slint: long callback/instantiation chain detected");
665    }
666
667    /// Returns a slice of the active popups.
668    pub fn active_popups(&self) -> core::cell::Ref<'_, [PopupWindow]> {
669        core::cell::Ref::map(self.active_popups.borrow(), |v| v.as_slice())
670    }
671
672    /// Receive a mouse event and pass it to the items of the component to
673    /// change their state.
674    ///
675    /// Returns `None` when there is no component to dispatch to; otherwise returns a
676    /// [`MouseDispatchResult`] carrying:
677    /// - `accepted`: whether an item consumed the event, and
678    /// - `drag_action`: for `DragMove`/`Drop` events, the negotiated
679    ///   [`DragAction`](crate::items::DragAction) (or `None` if no `DropArea` accepted).
680    ///
681    /// Note: when a drag is in flight, the runtime rewrites a `Released` into either a
682    /// `Drop` (if a `DropArea` had previously accepted the matching `DragMove`) or an
683    /// `Exit` (if not). The reported `accepted` reflects the rewritten event, so a
684    /// `Released` that completes a drop on a non-accepting target reports `accepted = false`.
685    pub fn process_mouse_input(&self, mut event: MouseEvent) -> Option<MouseDispatchResult> {
686        crate::animations::update_animations();
687
688        let item_tree = self.try_component()?;
689        self.ensure_tree_instantiated();
690
691        // handle multiple press release
692        event = self.click_state.check_repeat(event, self.context().platform().click_interval());
693
694        let window_adapter = self.window_adapter();
695        let mut mouse_input_state = self.mouse_input_state.take();
696
697        let was_dragging = mouse_input_state.drag_data.is_some();
698        let old_cursor = core::mem::replace(&mut mouse_input_state.cursor, MouseCursor::Default);
699
700        // drag-finished firing is deferred until after dispatch so the DropArea has had
701        // a chance to fire its own `dropped` callback first; that callback returns the
702        // final action, which the runtime then forwards to the source.
703        let mut pending_drag_finished: Option<(
704            crate::item_tree::ItemWeak,
705            Option<crate::item_tree::ItemWeak>,
706        )> = None;
707
708        if let Some(DragData { event: mut drop_event, allowed }) =
709            mouse_input_state.drag_data.clone()
710        {
711            match &event {
712                MouseEvent::Released { position, button: PointerEventButton::Left, .. } => {
713                    mouse_input_state.drag_data = None;
714                    let source = mouse_input_state.drag_source.take();
715                    if let Some(target_weak) = mouse_input_state.drop_target.take() {
716                        // Seed `proposed-action` for the dropped callback with the action the
717                        // target last chose during hover; the callback's return value will
718                        // become the final action reported to the source.
719                        let hovered = target_weak
720                            .upgrade()
721                            .and_then(|t| t.downcast::<crate::items::DropArea>())
722                            .map(|d| d.as_pin_ref().current_action())
723                            .unwrap_or(crate::items::DragAction::None);
724                        drop_event.proposed_action = hovered;
725                        drop_event.position = crate::lengths::logical_position_to_api(*position);
726                        event = MouseEvent::Drop { event: drop_event, allowed };
727                        if let Some(s) = source {
728                            pending_drag_finished = Some((s, Some(target_weak)));
729                        }
730                    } else {
731                        // No DropArea accepted the most recent DragMove. Tear the drag
732                        // down via Exit instead of converting to Drop so a non-accepting
733                        // DropArea under the cursor doesn't fire `dropped`, and so the
734                        // underlying Release doesn't reach hit-tested items as a
735                        // spurious click.
736                        event = MouseEvent::Exit;
737                        if let Some(s) = source {
738                            pending_drag_finished = Some((s, None));
739                        }
740                    }
741                }
742                MouseEvent::Moved { position, .. } => {
743                    drop_event.position = crate::lengths::logical_position_to_api(*position);
744                    // Recompute the proposed action from current modifier state so the target's
745                    // `can-drop` callback sees an up-to-date `event.proposed-action`.
746                    drop_event.proposed_action = crate::items::compute_proposed_action(
747                        self.context().0.modifiers.get().into(),
748                        allowed,
749                    );
750                    // Mirror the position and proposed action into the persistent state so the
751                    // renderer can place the drag-image overlay without re-deriving the cursor
752                    // location, and so a subsequent synthetic Moved (e.g. fired from a modifier
753                    // key press) starts from the right position.
754                    if let Some(d) = mouse_input_state.drag_data.as_mut() {
755                        d.event.position = drop_event.position;
756                        d.event.proposed_action = drop_event.proposed_action;
757                    }
758                    mouse_input_state.cursor = MouseCursor::NoDrop;
759                    event = MouseEvent::DragMove { event: drop_event, allowed };
760                }
761                MouseEvent::Exit => {
762                    mouse_input_state.drag_data = None;
763                    mouse_input_state.drop_target = None;
764                    if let Some(s) = mouse_input_state.drag_source.take() {
765                        pending_drag_finished = Some((s, None));
766                    }
767                }
768                _ => {}
769            }
770        }
771
772        let pressed_event = matches!(event, MouseEvent::Pressed { .. });
773        let released_event = matches!(event, MouseEvent::Released { .. });
774        let had_delay = mouse_input_state.has_delayed_event();
775
776        let last_top_item = mouse_input_state.top_item_including_delayed();
777        if released_event {
778            mouse_input_state =
779                crate::input::process_delayed_event(&window_adapter, mouse_input_state);
780        }
781
782        let parent_adapter = window_adapter
783            .internal(crate::InternalToken)
784            .and_then(|internal| internal.get_parent())
785            .unwrap_or_else(|| window_adapter.clone());
786        let active_popups = &WindowInner::from_pub(parent_adapter.window()).active_popups;
787        let native_popup_index = active_popups.borrow().iter().position(|p| {
788            if let PopupWindowLocation::TopLevel(wa) = &p.location {
789                Rc::ptr_eq(wa, &window_adapter)
790            } else {
791                false
792            }
793        });
794
795        if pressed_event {
796            self.had_popup_on_press.set(!active_popups.borrow().is_empty());
797        }
798
799        let mut popup_to_close = active_popups.borrow().last().and_then(|popup| {
800            let mouse_inside_popup = || {
801                if let PopupWindowLocation::ChildWindow(coordinates) = &popup.location {
802                    event.position().is_none_or(|pos| {
803                        ItemTreeRc::borrow_pin(&popup.component)
804                            .as_ref()
805                            .item_geometry(0)
806                            .contains(pos - coordinates.to_vector())
807                    })
808                } else {
809                    native_popup_index.is_some_and(|idx| idx == active_popups.borrow().len() - 1)
810                        && event.position().is_none_or(|pos| {
811                            ItemTreeRc::borrow_pin(&item_tree)
812                                .as_ref()
813                                .item_geometry(0)
814                                .contains(pos)
815                        })
816                }
817            };
818            match popup.close_policy {
819                PopupClosePolicy::CloseOnClick => {
820                    let mouse_inside_popup = mouse_inside_popup();
821                    (mouse_inside_popup && released_event && self.had_popup_on_press.get())
822                        || (!mouse_inside_popup && pressed_event)
823                }
824                PopupClosePolicy::CloseOnClickOutside => !mouse_inside_popup() && pressed_event,
825                PopupClosePolicy::NoAutoClose => false,
826            }
827            .then_some(popup.popup_id)
828        });
829
830        let grab_result =
831            crate::input::handle_mouse_grab(&event, &window_adapter, &mut mouse_input_state);
832        let grab_accepted = grab_result.accepted;
833
834        let mut dispatch_accepted = false;
835        mouse_input_state = if let Some(mut event) = grab_result.event {
836            // The grab handler may have fired callbacks that modified models or
837            // other state, so materialize any pending repeater/conditional
838            // changes before hit-testing with the returned event.
839            self.ensure_tree_instantiated();
840            let mut item_tree = self.component.borrow().upgrade();
841            let mut offset = LogicalPoint::default();
842            let mut menubar_item = None;
843            for (idx, popup) in active_popups.borrow().iter().enumerate().rev() {
844                if matches!(popup.window_kind, WindowKind::ToolTip) {
845                    continue;
846                }
847                item_tree = None;
848                menubar_item = None;
849                if let PopupWindowLocation::ChildWindow(coordinates) = &popup.location {
850                    let geom = ItemTreeRc::borrow_pin(&popup.component).as_ref().item_geometry(0);
851                    let mouse_inside_popup = event
852                        .position()
853                        .is_none_or(|pos| geom.contains(pos - coordinates.to_vector()));
854                    if mouse_inside_popup {
855                        item_tree = Some(popup.component.clone());
856                        offset = *coordinates;
857                        break;
858                    }
859                } else if native_popup_index.is_some_and(|i| i == idx) {
860                    item_tree = self.component.borrow().upgrade();
861                    break;
862                }
863
864                if !matches!(popup.window_kind, WindowKind::Menu) {
865                    break;
866                } else if popup_to_close.is_some() {
867                    // clicking outside of a popup menu should close all the menus
868                    popup_to_close = Some(popup.popup_id);
869                }
870
871                menubar_item = popup.parent_item.upgrade();
872            }
873
874            let root = match menubar_item {
875                None => item_tree.map(|item_tree| ItemRc::new_root(item_tree.clone())),
876                Some(menubar_item) => {
877                    event.translate(
878                        menubar_item
879                            .map_to_item_tree(Default::default(), &self.component())
880                            .to_vector(),
881                    );
882                    menubar_item.parent_item(ParentItemTraversalMode::StopAtPopups)
883                }
884            };
885
886            if let Some(root) = root {
887                event.translate(-offset.to_vector());
888                let crate::input::MouseInputResult { mut state, accepted } =
889                    crate::input::process_mouse_input(
890                        root,
891                        &event,
892                        &window_adapter,
893                        mouse_input_state,
894                    );
895                state.offset = offset;
896                dispatch_accepted = accepted;
897                state
898            } else {
899                // When outside, send exit event
900                let mut new_input_state = MouseInputState::default();
901                crate::input::send_exit_events(
902                    &mouse_input_state,
903                    &mut new_input_state,
904                    event.position(),
905                    &window_adapter,
906                );
907                new_input_state
908            }
909        } else {
910            mouse_input_state
911        };
912
913        let accepted = dispatch_accepted | grab_accepted;
914
915        if last_top_item != mouse_input_state.top_item_including_delayed() {
916            self.click_state.reset();
917            self.click_state.check_repeat(event, self.context().platform().click_interval());
918        }
919
920        if !had_delay && mouse_input_state.has_delayed_event() {
921            // A delay was just set up, preserve the old cursor
922            mouse_input_state.cursor = old_cursor;
923        } else if old_cursor != mouse_input_state.cursor
924            && let Some(window_adapter) = window_adapter.internal(crate::InternalToken)
925        {
926            window_adapter.set_mouse_cursor(mouse_input_state.cursor);
927        }
928
929        let is_dragging = mouse_input_state.drag_data.is_some();
930        let drag_action = mouse_input_state.drop_target_action();
931        self.mouse_input_state.set(mouse_input_state);
932
933        // The drag-image overlay follows the cursor and lives outside any item tree, so
934        // partial renderers won't otherwise know to repaint it on mouse motion or after
935        // the drag ends. `render_drag_image_overlay` marks its painted rect dirty itself,
936        // we just need to schedule the redraw.
937        if was_dragging || is_dragging {
938            window_adapter.request_redraw();
939        }
940
941        if let Some((source_weak, target_weak)) = pending_drag_finished
942            && let Some(source) = source_weak.upgrade()
943            && let Some(drag_area) = source.downcast::<crate::items::DragArea>()
944        {
945            // The action `dropped` returned is now sitting on the target's `current_action`.
946            // For a cancelled drag (no target) we just report None.
947            let target = target_weak
948                .and_then(|w| w.upgrade())
949                .and_then(|i| i.downcast::<crate::items::DropArea>());
950            let action = target
951                .as_ref()
952                .map(|d| d.as_pin_ref().current_action())
953                .unwrap_or(crate::items::DragAction::None);
954            let drag_area = drag_area.as_pin_ref();
955            drag_area.dragging.set(false);
956            crate::items::DragArea::FIELD_OFFSETS
957                .drag_finished()
958                .apply_pin(drag_area)
959                .call(&(action,));
960            // The drag is over: reset the target's `current_action` so it matches
961            // `has_drag` and the docstring ("none when no drag is hovering").
962            if let Some(target) = target {
963                target.as_pin_ref().current_action.set(crate::items::DragAction::None);
964            }
965        }
966
967        if let Some(popup_id) = popup_to_close {
968            WindowInner::from_pub(parent_adapter.window()).close_popup(popup_id);
969        }
970
971        self.ensure_tree_instantiated();
972
973        Some(MouseDispatchResult { drag_action, accepted })
974    }
975
976    /// Receive a raw touch event from a backend and either forward it as a mouse
977    /// event (single finger) or synthesize `PinchGesture`/`RotationGesture` events
978    /// (two fingers), producing the same events as platform gesture recognition.
979    ///
980    /// `position` must be in **logical coordinates** (i.e., already divided by the
981    /// scale factor). Passing physical coordinates will produce incorrect gesture
982    /// geometry and hit-testing.
983    ///
984    /// `drag_action` is taken from the *last* sub-event (including `None`), because
985    /// `drag_action` reflects the current drop-target negotiation, not a per-event
986    /// verdict to aggregate. For touch sequences that never produce a `DragMove`/`Drop`
987    /// (the common case), this stays `None` throughout.
988    pub fn process_touch_input(
989        &self,
990        id: i32,
991        position: LogicalPoint,
992        phase: TouchPhase,
993    ) -> Option<MouseDispatchResult> {
994        let events = self.touch_state.borrow_mut().process(id, position, phase);
995        let mut aggregate: Option<MouseDispatchResult> = None;
996        for event in events.into_iter() {
997            if let Some(r) = self.process_mouse_input(event) {
998                let agg = aggregate
999                    .get_or_insert(MouseDispatchResult { drag_action: None, accepted: false });
1000                agg.accepted |= r.accepted;
1001                agg.drag_action = r.drag_action;
1002            }
1003        }
1004        aggregate
1005    }
1006
1007    /// Called by the input code's internal timer to send an event that was delayed
1008    pub(crate) fn process_delayed_event(&self) {
1009        self.mouse_input_state.set(crate::input::process_delayed_event(
1010            &self.window_adapter(),
1011            self.mouse_input_state.take(),
1012        ));
1013    }
1014
1015    /// Receive a key event and pass it to the items of the component to
1016    /// change their state.
1017    ///
1018    /// Arguments:
1019    /// * `event`: The key event received by the windowing system.
1020    pub fn process_key_input(
1021        &self,
1022        mut internal_key_event: InternalKeyEvent,
1023    ) -> crate::input::KeyEventResult {
1024        self.ensure_tree_instantiated();
1025        // NFC-normalize the event text so that shortcut matching works consistently
1026        // regardless of the composed/decomposed form the backend provides
1027        // (e.g. é as U+00E9 vs e + U+0301).
1028        // Note: icu_normalizer is currently only enabled if parley is enabled
1029        #[cfg(feature = "shared-parley")]
1030        {
1031            let normalizer = icu_normalizer::ComposingNormalizer::new_nfc();
1032            let normalized = normalizer.normalize(&internal_key_event.key_event.text);
1033            // Only replace the event text if normalization actually changed it,
1034            // to avoid unnecessary allocations.
1035            if let alloc::borrow::Cow::Owned(normalized) = normalized {
1036                internal_key_event.key_event.text = normalized.into();
1037            }
1038        }
1039
1040        if let Some(updated_modifier) = self.context().0.modifiers.get().state_update(
1041            internal_key_event.event_type == KeyEventType::KeyPressed,
1042            &internal_key_event.key_event.text,
1043        ) {
1044            // Updates the key modifiers depending on the key code and pressed state.
1045            self.context().0.modifiers.set(updated_modifier);
1046
1047            // If a drag is in flight, synthesize a Moved at the last drag position so
1048            // the new modifier state flows into `event.proposed-action` and the target's
1049            // `can-drop` re-runs — letting the user change copy/move/link with Ctrl/Shift
1050            // without having to move the mouse first.
1051            let drag_pos = {
1052                let state = self.mouse_input_state.take();
1053                let pos = state.drag_data.as_ref().map(|d| d.event.position);
1054                self.mouse_input_state.replace(state);
1055                pos
1056            };
1057            if let Some(pos) = drag_pos {
1058                self.process_mouse_input(MouseEvent::Moved {
1059                    position: crate::lengths::logical_point_from_api(pos),
1060                    touch_finger_id: 0,
1061                });
1062            }
1063        }
1064
1065        internal_key_event.key_event.modifiers =
1066            self.context().0.modifiers.get().modifiers_for(&internal_key_event);
1067
1068        // Emulate macOS menubar behavior: The OS consumes the event before it reaches any
1069        // Slint widgets. Therefore we process the menubar shortcuts here first and abort event
1070        // propagation if a shortcut matches.
1071        if self.process_menubar_shortcuts(&internal_key_event) == KeyEventResult::EventAccepted {
1072            self.ensure_tree_instantiated();
1073            return crate::input::KeyEventResult::EventAccepted;
1074        }
1075
1076        let mut item = self.focus_item.borrow().clone().upgrade();
1077
1078        if item.as_ref().is_some_and(|i| !i.is_visible()) {
1079            // Reset the focus... not great, but better than keeping it.
1080            self.take_focus_item(&FocusEvent::FocusOut(FocusReason::TabNavigation));
1081            item = None;
1082        }
1083
1084        let item_list = {
1085            let mut tmp = Vec::new();
1086            let mut item = item.clone();
1087
1088            while let Some(i) = item {
1089                tmp.push(i.clone());
1090                item = i.parent_item(ParentItemTraversalMode::StopAtPopups);
1091            }
1092
1093            tmp
1094        };
1095
1096        // Check capture_key_event (going from window to focused item):
1097        for i in item_list.iter().rev() {
1098            if i.borrow().as_ref().capture_key_event(&internal_key_event, &self.window_adapter(), i)
1099                == crate::input::KeyEventResult::EventAccepted
1100            {
1101                self.ensure_tree_instantiated();
1102                return crate::input::KeyEventResult::EventAccepted;
1103            }
1104        }
1105
1106        drop(item_list);
1107
1108        // Deliver key_event (to focused item, going up towards the window):
1109        while let Some(focus_item) = item {
1110            if focus_item.borrow().as_ref().key_event(
1111                &internal_key_event,
1112                &self.window_adapter(),
1113                &focus_item,
1114            ) == crate::input::KeyEventResult::EventAccepted
1115            {
1116                self.ensure_tree_instantiated();
1117                return crate::input::KeyEventResult::EventAccepted;
1118            }
1119            item = focus_item.parent_item(ParentItemTraversalMode::StopAtPopups);
1120        }
1121
1122        // Make Tab/Backtab handle keyboard focus
1123        let extra_mod = internal_key_event.key_event.modifiers.control
1124            || internal_key_event.key_event.modifiers.meta
1125            || internal_key_event.key_event.modifiers.alt;
1126        if internal_key_event.key_event.text.starts_with(key_codes::Tab)
1127            && !internal_key_event.key_event.modifiers.shift
1128            && !extra_mod
1129            && internal_key_event.event_type == KeyEventType::KeyPressed
1130        {
1131            self.focus_next_item();
1132            self.ensure_tree_instantiated();
1133            return crate::input::KeyEventResult::EventAccepted;
1134        } else if (internal_key_event.key_event.text.starts_with(key_codes::Backtab)
1135            || (internal_key_event.key_event.text.starts_with(key_codes::Tab)
1136                && internal_key_event.key_event.modifiers.shift))
1137            && internal_key_event.event_type == KeyEventType::KeyPressed
1138            && !extra_mod
1139        {
1140            self.focus_previous_item();
1141            self.ensure_tree_instantiated();
1142            return crate::input::KeyEventResult::EventAccepted;
1143        } else if internal_key_event.event_type == KeyEventType::KeyPressed
1144            && internal_key_event.key_event.text.starts_with(key_codes::Escape)
1145        {
1146            // Closes top most popup on ESC key pressed when policy is not no-auto-close
1147
1148            // Try to get the parent window in case `self` is the popup itself
1149            let mut adapter = self.window_adapter();
1150            let item_tree = self.component();
1151            let mut a = None;
1152            ItemTreeRc::borrow_pin(&item_tree).as_ref().window_adapter(false, &mut a);
1153            if let Some(a) = a {
1154                adapter = a;
1155            }
1156            let window = WindowInner::from_pub(adapter.window());
1157
1158            let close_on_escape = if let Some(popup) = window.active_popups.borrow().last() {
1159                popup.close_policy == PopupClosePolicy::CloseOnClick
1160                    || popup.close_policy == PopupClosePolicy::CloseOnClickOutside
1161            } else {
1162                false
1163            };
1164
1165            if close_on_escape {
1166                window.close_top_popup();
1167            }
1168            self.ensure_tree_instantiated();
1169            return crate::input::KeyEventResult::EventAccepted;
1170        }
1171
1172        self.ensure_tree_instantiated();
1173        crate::input::KeyEventResult::EventIgnored
1174    }
1175
1176    fn process_menubar_shortcuts(
1177        &self,
1178        internal_key_event: &InternalKeyEvent,
1179    ) -> crate::input::KeyEventResult {
1180        let event_type = internal_key_event.event_type;
1181        let menubar = self.menubar.borrow().as_ref().and_then(vtable::VWeak::upgrade);
1182
1183        if (event_type == KeyEventType::KeyReleased || event_type == KeyEventType::KeyPressed)
1184            && let Some(menubar) = menubar
1185        {
1186            let shortcuts = self.pinned_fields.as_ref().project_ref().menubar_shortcuts.get();
1187            let mut matches = shortcuts
1188                .into_iter()
1189                .filter(|entry| entry.shortcut.matches(&internal_key_event.key_event));
1190            if let Some(entry) = matches.next() {
1191                if internal_key_event.event_type == KeyEventType::KeyPressed {
1192                    VRc::borrow(&menubar).activate(&entry);
1193                    if matches.next().is_some() {
1194                        crate::debug_log!(
1195                            "Warning: Ambiguous menubar shortcut: {}",
1196                            entry.shortcut
1197                        );
1198                    }
1199                }
1200                return crate::input::KeyEventResult::EventAccepted;
1201            }
1202        }
1203        crate::input::KeyEventResult::EventIgnored
1204    }
1205
1206    /// Installs a binding on the specified property that's toggled whenever the text cursor is supposed to be visible or not.
1207    pub fn set_cursor_blink_binding(&self, prop: &crate::Property<bool>) {
1208        let existing_blinker = self.cursor_blinker.borrow().clone();
1209
1210        let blinker = existing_blinker.upgrade().unwrap_or_else(|| {
1211            let new_blinker = TextCursorBlinker::new();
1212            *self.cursor_blinker.borrow_mut() =
1213                pin_weak::rc::PinWeak::downgrade(new_blinker.clone());
1214            new_blinker
1215        });
1216
1217        TextCursorBlinker::set_binding(
1218            blinker,
1219            prop,
1220            self.context().platform().cursor_flash_cycle(),
1221        );
1222    }
1223
1224    /// Sets the focus to the item pointed to by item_ptr. This will remove the focus from any
1225    /// currently focused item. If set_focus is false, the focus is cleared.
1226    pub fn set_focus_item(&self, new_focus_item: &ItemRc, set_focus: bool, reason: FocusReason) {
1227        if self.prevent_focus_change.get() {
1228            return;
1229        }
1230
1231        let popup_wa = self.active_popups.borrow().last().and_then(|p| match &p.location {
1232            PopupWindowLocation::TopLevel(wa) => Some(wa.clone()),
1233            PopupWindowLocation::ChildWindow(..) => None,
1234        });
1235        if let Some(popup_wa) = popup_wa {
1236            // Set the focus item on the popup's Window instead
1237            popup_wa.window().0.set_focus_item(new_focus_item, set_focus, reason);
1238            return;
1239        }
1240
1241        let current_focus_item = self.focus_item.borrow().clone();
1242        if let Some(current_focus_item_rc) = current_focus_item.upgrade() {
1243            if set_focus {
1244                if current_focus_item_rc == *new_focus_item {
1245                    // don't send focus out and in even to the same item if focus doesn't change
1246                    return;
1247                }
1248            } else if current_focus_item_rc != *new_focus_item {
1249                // can't clear focus unless called with currently focused item.
1250                return;
1251            }
1252        }
1253
1254        let old = self.take_focus_item(&FocusEvent::FocusOut(reason));
1255        let new = if set_focus {
1256            self.move_focus(new_focus_item.clone(), next_focus_item, reason)
1257        } else {
1258            None
1259        };
1260        let window_adapter = self.window_adapter();
1261        if let Some(window_adapter) = window_adapter.internal(crate::InternalToken) {
1262            window_adapter.handle_focus_change(old, new);
1263        }
1264    }
1265
1266    /// Take the focus_item out of this Window
1267    ///
1268    /// This sends the event which must be either FocusOut or WindowLostFocus for popups
1269    fn take_focus_item(&self, event: &FocusEvent) -> Option<ItemRc> {
1270        let focus_item = self.focus_item.take();
1271        assert!(matches!(event, FocusEvent::FocusOut(_)));
1272
1273        if let Some(focus_item_rc) = focus_item.upgrade() {
1274            focus_item_rc.borrow().as_ref().focus_event(
1275                event,
1276                &self.window_adapter(),
1277                &focus_item_rc,
1278            );
1279            Some(focus_item_rc)
1280        } else {
1281            None
1282        }
1283    }
1284
1285    /// Publish the new focus_item to this Window and return the FocusEventResult
1286    ///
1287    /// This sends a FocusIn event!
1288    fn publish_focus_item(
1289        &self,
1290        item: &Option<ItemRc>,
1291        reason: FocusReason,
1292    ) -> crate::input::FocusEventResult {
1293        match item {
1294            Some(item) => {
1295                *self.focus_item.borrow_mut() = item.downgrade();
1296                let result = item.borrow().as_ref().focus_event(
1297                    &FocusEvent::FocusIn(reason),
1298                    &self.window_adapter(),
1299                    item,
1300                );
1301                // Reveal offscreen item when it gains focus
1302                if result == crate::input::FocusEventResult::FocusAccepted {
1303                    item.try_scroll_into_visible();
1304                }
1305
1306                result
1307            }
1308            None => {
1309                *self.focus_item.borrow_mut() = Default::default();
1310                crate::input::FocusEventResult::FocusAccepted // We were removing the focus, treat that as OK
1311            }
1312        }
1313    }
1314
1315    fn move_focus(
1316        &self,
1317        start_item: ItemRc,
1318        forward: impl Fn(ItemRc) -> ItemRc,
1319        reason: FocusReason,
1320    ) -> Option<ItemRc> {
1321        let mut current_item = start_item;
1322        let mut visited = Vec::new();
1323
1324        loop {
1325            let can_receive_focus = match reason {
1326                FocusReason::Programmatic => true,
1327                FocusReason::TabNavigation => current_item.is_visible_or_clipped_by_flickable(),
1328                _ => current_item.is_visible(),
1329            };
1330            if can_receive_focus
1331                && self.publish_focus_item(&Some(current_item.clone()), reason)
1332                    == crate::input::FocusEventResult::FocusAccepted
1333            {
1334                return Some(current_item); // Item was just published.
1335            }
1336            visited.push(current_item.clone());
1337            current_item = forward(current_item);
1338
1339            if visited.contains(&current_item) {
1340                return None; // Nothing to do: We took the focus_item already
1341            }
1342        }
1343    }
1344
1345    /// Move keyboard focus to the next item
1346    pub fn focus_next_item(&self) {
1347        let start_item = self
1348            .take_focus_item(&FocusEvent::FocusOut(FocusReason::TabNavigation))
1349            .map(next_focus_item)
1350            .unwrap_or_else(|| {
1351                ItemRc::new(
1352                    self.active_popups
1353                        .borrow()
1354                        .last()
1355                        .map_or_else(|| self.component(), |p| p.component.clone()),
1356                    0,
1357                )
1358            });
1359        let end_item =
1360            self.move_focus(start_item.clone(), next_focus_item, FocusReason::TabNavigation);
1361        let window_adapter = self.window_adapter();
1362        if let Some(window_adapter) = window_adapter.internal(crate::InternalToken) {
1363            window_adapter.handle_focus_change(Some(start_item), end_item);
1364        }
1365    }
1366
1367    /// Move keyboard focus to the previous item.
1368    pub fn focus_previous_item(&self) {
1369        let start_item = previous_focus_item(
1370            self.take_focus_item(&FocusEvent::FocusOut(FocusReason::TabNavigation)).unwrap_or_else(
1371                || {
1372                    ItemRc::new(
1373                        self.active_popups
1374                            .borrow()
1375                            .last()
1376                            .map_or_else(|| self.component(), |p| p.component.clone()),
1377                        0,
1378                    )
1379                },
1380            ),
1381        );
1382        let end_item =
1383            self.move_focus(start_item.clone(), previous_focus_item, FocusReason::TabNavigation);
1384        let window_adapter = self.window_adapter();
1385        if let Some(window_adapter) = window_adapter.internal(crate::InternalToken) {
1386            window_adapter.handle_focus_change(Some(start_item), end_item);
1387        }
1388    }
1389
1390    /// Marks the window to be the active window. This typically coincides with the keyboard
1391    /// focus. One exception though is when a popup is shown, in which case the window may
1392    /// remain active but temporarily loose focus to the popup.
1393    ///
1394    /// This results in WindowFocusReceived and WindowFocusLost events.
1395    pub fn set_active(&self, have_focus: bool) {
1396        self.pinned_fields.as_ref().project_ref().active.set(have_focus);
1397
1398        let event = if have_focus {
1399            FocusEvent::FocusIn(FocusReason::WindowActivation)
1400        } else {
1401            FocusEvent::FocusOut(FocusReason::WindowActivation)
1402        };
1403
1404        if let Some(focus_item) = self.focus_item.borrow().upgrade() {
1405            focus_item.borrow().as_ref().focus_event(&event, &self.window_adapter(), &focus_item);
1406        }
1407
1408        // If we lost focus due to for example a global shortcut, then when we regain focus
1409        // should not assume that the modifiers are in the same state.
1410        if !have_focus {
1411            self.context().0.modifiers.take();
1412        }
1413    }
1414
1415    /// Returns true of the window is the active window. That typically implies having the
1416    /// keyboard focus, except when a popup is shown and temporarily takes the focus.
1417    pub fn active(&self) -> bool {
1418        self.pinned_fields.as_ref().project_ref().active.get()
1419    }
1420
1421    /// If the component's root item is a Window element, then this function synchronizes its properties, such as the title
1422    /// for example, with the properties known to the windowing system.
1423    pub fn update_window_properties(&self) {
1424        let window_adapter = self.window_adapter();
1425
1426        // No `if !dirty { return; }` check here because the backend window may be newly mapped and not up-to-date, so force
1427        // an evaluation.
1428        self.pinned_fields
1429            .as_ref()
1430            .project_ref()
1431            .window_properties_tracker
1432            .evaluate_as_dependency_root(|| {
1433                window_adapter.update_window_properties(WindowProperties(self));
1434            });
1435    }
1436
1437    /// Re-evaluates the position tracker for the popup with the given ID, re-subscribing to its
1438    /// property dependencies so subsequent changes continue to trigger notifications.
1439    fn update_popup_properties(&self, popup_id: NonZeroU32) {
1440        let offset = {
1441            let active_popups = self.active_popups.borrow();
1442            let Some(popup) = active_popups.iter().find(|p| p.popup_id == popup_id) else { return };
1443            if let Some(parent) = popup.parent_item.clone().upgrade() {
1444                parent.map_to_native_window(
1445                    parent.geometry().origin + (popup.position_access)().to_euclid().to_vector(),
1446                )
1447            } else {
1448                LogicalPoint::zero()
1449            }
1450        };
1451        let mut active_popups = self.active_popups.borrow_mut();
1452        let Some(popup) = active_popups.iter_mut().find(|p| p.popup_id == popup_id) else { return };
1453        match &mut popup.location {
1454            PopupWindowLocation::ChildWindow(old_location) => {
1455                let (old_popup_region, new_popup_region) =
1456                    popup.properties_tracker.as_ref().evaluate_as_dependency_root(|| {
1457                        let component = ItemTreeRc::borrow_pin(&popup.component);
1458                        let root_item = component.as_ref().get_item_ref(0);
1459                        let window_item =
1460                            ItemRef::downcast_pin::<crate::items::WindowItem>(root_item)
1461                                .expect("Popup component is a Window item");
1462                        // Access the properties to set them as dependencies
1463                        let old_popup_region = LogicalRect::new(
1464                            *old_location,
1465                            crate::lengths::LogicalSize::new(
1466                                window_item.width().0,
1467                                window_item.height().0,
1468                            ),
1469                        );
1470
1471                        let width = {
1472                            let layout_info_h = component
1473                                .as_ref()
1474                                .layout_info(crate::layout::Orientation::Horizontal);
1475                            let w = layout_info_h.min.min(layout_info_h.max);
1476                            window_item.width.set(LogicalLength::new(w));
1477                            w
1478                        };
1479
1480                        let height = {
1481                            let layout_info_v = component
1482                                .as_ref()
1483                                .layout_info(crate::layout::Orientation::Vertical);
1484                            let h = layout_info_v.min.min(layout_info_v.max);
1485                            window_item.height.set(LogicalLength::new(h));
1486                            h
1487                        };
1488
1489                        (
1490                            old_popup_region,
1491                            LogicalRect::new(
1492                                (popup.position_access)().to_euclid(),
1493                                crate::lengths::LogicalSize::new(width, height),
1494                            ),
1495                        )
1496                    });
1497
1498                // Set new location
1499                *old_location = offset;
1500
1501                if let Some(adapter) = self.window_adapter_weak.upgrade() {
1502                    if !old_popup_region.is_empty() {
1503                        adapter.renderer().mark_dirty_region(old_popup_region.into());
1504                    }
1505
1506                    if !new_popup_region.is_empty() {
1507                        adapter.renderer().mark_dirty_region(new_popup_region.into());
1508                    }
1509                    adapter.request_redraw();
1510                }
1511            }
1512            PopupWindowLocation::TopLevel(adapter) => {
1513                // The size is already tracked in the windowadapter
1514                let mut new_position: Option<LogicalPosition> = None;
1515                popup.properties_tracker.as_ref().evaluate_as_dependency_root(|| {
1516                    (popup.position_access)(); // Dummy access to track position changes
1517                    new_position = Some(LogicalPosition::from_euclid(offset));
1518                });
1519                if let Some(pos) = new_position {
1520                    adapter.window().set_position(pos);
1521                }
1522            }
1523        }
1524    }
1525
1526    /// Calls the render_components to render the main component and any sub-window components, tracked by a
1527    /// property dependency tracker.
1528    ///
1529    /// The closure also receives a `post_render` callback. The renderer must invoke it
1530    /// once with its `ItemRenderer` after walking the components but before flushing,
1531    /// so the runtime can draw overlays that sit on top of the scene without being part
1532    /// of any item tree.
1533    ///
1534    /// Returns None if no component is set yet.
1535    pub fn draw_contents<T>(
1536        &self,
1537        render_components: impl FnOnce(
1538            &[(ItemTreeWeak, LogicalPoint)],
1539            &dyn Fn(&mut dyn crate::item_rendering::ItemRenderer),
1540        ) -> T,
1541    ) -> Option<T> {
1542        crate::properties::evaluate_no_tracking(|| self.ensure_tree_instantiated());
1543        let component_weak = ItemTreeRc::downgrade(&self.try_component()?);
1544        let post_render = |renderer: &mut dyn crate::item_rendering::ItemRenderer| {
1545            self.render_drag_image_overlay(renderer);
1546        };
1547        Some(self.pinned_fields.as_ref().project_ref().redraw_tracker.evaluate_as_dependency_root(
1548            || {
1549                if !self
1550                    .active_popups
1551                    .borrow()
1552                    .iter()
1553                    .any(|p| matches!(p.location, PopupWindowLocation::ChildWindow(..)))
1554                {
1555                    render_components(&[(component_weak, LogicalPoint::default())], &post_render)
1556                } else {
1557                    let borrow = self.active_popups.borrow();
1558                    let mut item_trees = Vec::with_capacity(borrow.len() + 1);
1559                    item_trees.push((component_weak, LogicalPoint::default()));
1560                    for popup in borrow.iter() {
1561                        // If the popup is not a real window and does not have its own coordinate system.
1562                        // We have to draw the popup and consider the location for subelements because everything must
1563                        // be rendered relative to the main window position
1564                        if let PopupWindowLocation::ChildWindow(location) = &popup.location {
1565                            item_trees.push((ItemTreeRc::downgrade(&popup.component), *location));
1566                        }
1567                    }
1568                    drop(borrow);
1569                    render_components(&item_trees, &post_render)
1570                }
1571            },
1572        ))
1573    }
1574
1575    /// Draws the source `DragArea`'s `drag-image` under the cursor when a drag is in flight.
1576    /// No-op when no drag is active or the source has no image set.
1577    ///
1578    /// Marks the painted rect dirty for partial renderers, so the next frame clears the area
1579    /// before redrawing — same trick the linuxkms cursor injection uses, no per-frame state needed.
1580    fn render_drag_image_overlay(
1581        &self,
1582        item_renderer: &mut dyn crate::item_rendering::ItemRenderer,
1583    ) {
1584        let state = self.mouse_input_state.take();
1585        let cursor = state.drag_data.as_ref().map(|d| d.event.position);
1586        let source = state.drag_source.as_ref().and_then(|w| w.upgrade());
1587        self.mouse_input_state.set(state);
1588
1589        let (Some(cursor), Some(source)) = (cursor, source) else { return };
1590        let Some(drag_area) = source.downcast::<crate::items::DragArea>() else { return };
1591        let drag_area = drag_area.as_pin_ref();
1592        let image = drag_area.drag_image();
1593        let size = crate::lengths::LogicalSize::from_untyped(image.size().cast());
1594        if size.is_empty() {
1595            return;
1596        }
1597        let cursor = crate::lengths::logical_point_from_api(cursor);
1598        let offset = LogicalVector::new(
1599            drag_area.drag_image_offset_x() as Coord,
1600            drag_area.drag_image_offset_y() as Coord,
1601        );
1602        let top_left = cursor - offset;
1603
1604        item_renderer.save_state();
1605        item_renderer.translate(top_left.to_vector());
1606        item_renderer.draw_image_direct(image);
1607        item_renderer.restore_state();
1608
1609        self.window_adapter().renderer().mark_dirty_region(LogicalRect::new(top_left, size).into());
1610    }
1611
1612    /// Registers the window with the windowing system, in order to render the component's items and react
1613    /// to input events once the event loop spins.
1614    pub fn show(&self) -> Result<(), PlatformError> {
1615        if let Some(component) = self.try_component() {
1616            let was_visible = self.strong_component_ref.replace(Some(component)).is_some();
1617            if !was_visible {
1618                self.context().acquire_keepalive();
1619            }
1620        }
1621
1622        self.ensure_tree_instantiated();
1623        self.update_window_properties();
1624        self.window_adapter().set_visible(true)?;
1625        // Make sure that the window's inner size is in sync with the root window item's
1626        // width/height.
1627        let size = self.window_adapter().size();
1628        let scale_factor = self.scale_factor();
1629        self.set_window_item_geometry(size.to_logical(scale_factor).to_euclid());
1630        let inset = self
1631            .window_adapter()
1632            .internal(crate::InternalToken)
1633            .map(|internal| internal.safe_area_inset())
1634            .unwrap_or_default();
1635        self.set_window_item_safe_area(inset.to_logical(scale_factor));
1636        self.window_adapter().renderer().resize(size).unwrap();
1637        if let Some(hook) = self.context().0.window_shown_hook.borrow_mut().as_mut() {
1638            hook(&self.window_adapter());
1639        }
1640        Ok(())
1641    }
1642
1643    /// De-registers the window with the windowing system.
1644    pub fn hide(&self) -> Result<(), PlatformError> {
1645        let result = self.window_adapter().set_visible(false);
1646        let was_visible = self.strong_component_ref.borrow_mut().take().is_some();
1647        if was_visible {
1648            self.context().release_keepalive();
1649        }
1650        result
1651    }
1652
1653    /// Return whether the platform supports native menu bars
1654    pub fn supports_native_menu_bar(&self) -> bool {
1655        self.window_adapter()
1656            .internal(crate::InternalToken)
1657            .is_some_and(|x| x.supports_native_menu_bar())
1658    }
1659
1660    /// Setup the native menu bar
1661    pub fn setup_menubar(&self, menubar: vtable::VRc<MenuVTable>) {
1662        if let Some(x) = self.window_adapter().internal(crate::InternalToken) {
1663            x.setup_menubar(menubar);
1664        }
1665    }
1666
1667    /// Setup the shortcuts for the menubar
1668    /// Note: We still register the same shortcuts if the native menubar is active.
1669    /// Generally, the native menubar should capture the shortcuts first,
1670    /// but in case it doesn't, the window can still match them manually.
1671    pub fn setup_menubar_shortcuts(&self, menubar: VRc<MenuVTable>) {
1672        *self.menubar.borrow_mut() = Some(VRc::downgrade(&menubar));
1673        let weak = VRc::downgrade(&menubar);
1674        self.pinned_fields.menubar_shortcuts.set_binding(move || {
1675            fn flatten_menu(
1676                root: vtable::VRef<'_, MenuVTable>,
1677                parent: Option<&MenuEntry>,
1678            ) -> SharedVector<MenuEntry> {
1679                let mut menu_entries = Default::default();
1680                root.sub_menu(parent, &mut menu_entries);
1681
1682                let mut result = menu_entries.clone();
1683
1684                for entry in menu_entries {
1685                    result.extend(flatten_menu(root, Some(&entry)));
1686                }
1687                result
1688            }
1689
1690            let Some(menubar) = weak.upgrade() else {
1691                return SharedVector::default();
1692            };
1693            flatten_menu(VRc::borrow(&menubar), None)
1694                .into_iter()
1695                .filter(|entry| entry.enabled && entry.shortcut != Keys::default())
1696                .collect()
1697        });
1698    }
1699    /// Create a new popup window adapter
1700    /// This window adapter can be used on a popup component and shown with show_popup()
1701    pub fn create_child_window_adapter(&self, kind: WindowKind) -> Option<Rc<dyn WindowAdapter>> {
1702        self.window_adapter()
1703            .internal(crate::InternalToken)
1704            .and_then(|s| s.create_child_window_adapter(kind))
1705    }
1706
1707    /// Show a popup at the given position relative to the `parent_item` and returns its ID.
1708    /// The returned ID will always be non-zero.
1709    ///
1710    /// `is_open_setter` keeps the parent component's `PopupWindow::is-open` property in sync with this
1711    /// popup: it is invoked immediately with `true`, and again with `false` when the popup is closed
1712    /// through any path (the `Drop` impl of [`PopupWindow`] handles the `false`). Pass a no-op closure
1713    /// for popups (such as menus) that do not expose `is-open`.
1714    pub fn show_popup(
1715        &self,
1716        popup_componentrc: &ItemTreeRc,
1717        popup_access_position: Box<dyn Fn() -> LogicalPosition>,
1718        close_policy: PopupClosePolicy,
1719        parent_item: &ItemRc,
1720        window_kind: WindowKind,
1721        is_open_setter: Box<dyn Fn(bool)>,
1722    ) -> NonZeroU32 {
1723        // Popups live in their own ItemTree, which was invisible to any
1724        // earlier instantiation pass; materialize it before the layout queries below.
1725        crate::item_tree::ensure_item_tree_instantiated(popup_componentrc);
1726        let position = parent_item.map_to_native_window(
1727            parent_item.geometry().origin + popup_access_position().to_euclid().to_vector(),
1728        );
1729        let popup_component = ItemTreeRc::borrow_pin(popup_componentrc);
1730        let popup_root = popup_component.as_ref().get_item_ref(0);
1731
1732        let (mut w, mut h) = if let Some(window_item) =
1733            ItemRef::downcast_pin::<crate::items::WindowItem>(popup_root)
1734        {
1735            (window_item.width(), window_item.height())
1736        } else {
1737            (LogicalLength::zero(), LogicalLength::zero())
1738        };
1739
1740        let layout_info_h =
1741            popup_component.as_ref().layout_info(crate::layout::Orientation::Horizontal);
1742        let layout_info_v =
1743            popup_component.as_ref().layout_info(crate::layout::Orientation::Vertical);
1744
1745        if w <= LogicalLength::zero() {
1746            w = LogicalLength::new(layout_info_h.preferred);
1747        }
1748        if h <= LogicalLength::zero() {
1749            h = LogicalLength::new(layout_info_v.preferred);
1750        }
1751        w = w.max(LogicalLength::new(layout_info_h.min)).min(LogicalLength::new(layout_info_h.max));
1752        h = h.max(LogicalLength::new(layout_info_v.min)).min(LogicalLength::new(layout_info_v.max));
1753
1754        let size = crate::lengths::LogicalSize::from_lengths(w, h);
1755
1756        if let Some(window_item) = ItemRef::downcast_pin(popup_root) {
1757            let width_property =
1758                crate::items::WindowItem::FIELD_OFFSETS.width().apply_pin(window_item);
1759            let height_property =
1760                crate::items::WindowItem::FIELD_OFFSETS.height().apply_pin(window_item);
1761            width_property.set(size.width_length());
1762            height_property.set(size.height_length());
1763        };
1764
1765        let popup_id = self.next_popup_id.get();
1766        self.next_popup_id.set(popup_id.checked_add(1).unwrap());
1767        let parent_window_adapter_weak = Rc::downgrade(&self.window_adapter());
1768
1769        // Close active popups before creating a new one.
1770        let siblings: Vec<_> = self
1771            .active_popups
1772            .borrow()
1773            .iter()
1774            .filter(|p| p.parent_item == parent_item.downgrade())
1775            .map(|p| p.popup_id)
1776            .collect();
1777
1778        for sibling in siblings {
1779            self.close_popup(sibling);
1780        }
1781
1782        let root_of = |mut item_tree: ItemTreeRc| loop {
1783            if ItemRc::new_root(item_tree.clone()).downcast::<crate::items::WindowItem>().is_some()
1784            {
1785                return item_tree;
1786            }
1787            let mut r = crate::item_tree::ItemWeak::default();
1788            ItemTreeRc::borrow_pin(&item_tree).as_ref().parent_node(&mut r);
1789            match r.upgrade() {
1790                None => return item_tree,
1791                Some(x) => item_tree = x.item_tree().clone(),
1792            }
1793        };
1794
1795        let parent_root_item_tree = root_of(parent_item.item_tree().clone());
1796        let parent_window_adapter = if let Some(parent_popup) = self
1797            .active_popups
1798            .borrow()
1799            .iter()
1800            .find(|p| ItemTreeRc::ptr_eq(&p.component, &parent_root_item_tree))
1801        {
1802            // Popup in a popup
1803            match &parent_popup.location {
1804                PopupWindowLocation::TopLevel(wa) => wa.clone(),
1805                PopupWindowLocation::ChildWindow(_) => self.window_adapter(),
1806            }
1807        } else {
1808            self.window_adapter()
1809        };
1810
1811        let popup_window_adapter = {
1812            let mut popup_window_adapter = None;
1813            ItemTreeRc::borrow_pin(popup_componentrc)
1814                .as_ref()
1815                .window_adapter(false, &mut popup_window_adapter);
1816            popup_window_adapter.expect("It must be there because we set the global")
1817        };
1818
1819        // If the window adapter of the popup window and the parent window are equal, create a ChildWindow
1820        // because we weren't able to create a dedicated popup adapter (for example if the backend does not support it).
1821        let (location, properties_tracker) =
1822            if Rc::ptr_eq(&parent_window_adapter, &popup_window_adapter) {
1823                // Tooltips may extend past the window (e.g. above/left of the anchor); do not clamp.
1824                let clip_region = Some(LogicalRect::new(
1825                    LogicalPoint::new(0.0 as crate::Coord, 0.0 as crate::Coord),
1826                    self.window_adapter().size().to_logical(self.scale_factor()).to_euclid(),
1827                ));
1828                let rect = popup::place_popup(
1829                    popup::Placement::Fixed(LogicalRect::new(position, size)),
1830                    &clip_region,
1831                );
1832                self.window_adapter().request_redraw();
1833                (
1834                    PopupWindowLocation::ChildWindow(rect.origin),
1835                    Box::pin(PropertyTracker::new_with_dirty_handler(
1836                        PopupWindowPropertiesTracker {
1837                            parent_window_adapter_weak: parent_window_adapter_weak.clone(),
1838                            popup_id,
1839                        },
1840                    )),
1841                )
1842            } else {
1843                let popup_window = popup_window_adapter.window();
1844                WindowInner::from_pub(popup_window).set_component(popup_componentrc);
1845                popup_window.set_position(LogicalPosition::from_euclid(position));
1846                popup_window.set_size(WindowSize::Logical(LogicalSize::from_euclid(size)));
1847
1848                popup_window_adapter.set_visible(true).expect("unable to show popup window");
1849                (
1850                    PopupWindowLocation::TopLevel(popup_window_adapter),
1851                    Box::pin(PropertyTracker::new_with_dirty_handler(
1852                        PopupWindowPropertiesTracker {
1853                            parent_window_adapter_weak: parent_window_adapter_weak.clone(),
1854                            popup_id,
1855                        },
1856                    )),
1857                )
1858            };
1859
1860        let focus_item = if matches!(window_kind, WindowKind::ToolTip) {
1861            Default::default()
1862        } else {
1863            self.take_focus_item(&FocusEvent::FocusOut(FocusReason::PopupActivation))
1864                .map(|item| item.downgrade())
1865                .unwrap_or_default()
1866        };
1867
1868        // Reflect the freshly shown popup in the parent's `is-open` property; the matching `false` is
1869        // emitted when the stored `PopupWindow` is dropped (see its `Drop` impl), which every close
1870        // path funnels through. Called before the popup is stored so we do not hold a borrow on
1871        // `active_popups` while running user-provided code.
1872        is_open_setter(true);
1873
1874        self.active_popups.borrow_mut().push(PopupWindow {
1875            popup_id,
1876            location,
1877            component: popup_componentrc.clone(),
1878            close_policy,
1879            focus_item_in_parent: focus_item,
1880            parent_item: parent_item.downgrade(),
1881            window_kind,
1882            position_access: popup_access_position,
1883            is_open_setter,
1884            properties_tracker,
1885        });
1886
1887        self.update_popup_properties(popup_id);
1888
1889        popup_id
1890    }
1891
1892    /// Attempt to show a native popup menu
1893    ///
1894    /// context_menu_item is an instance of a ContextMenu
1895    ///
1896    /// Returns false if the native platform doesn't support it
1897    pub fn show_native_popup_menu(
1898        &self,
1899        context_menu_item: vtable::VRc<MenuVTable>,
1900        position: LogicalPosition,
1901        parent_item: &ItemRc,
1902    ) -> bool {
1903        if let Some(x) = self.window_adapter().internal(crate::InternalToken) {
1904            let position = parent_item.map_to_native_window(
1905                parent_item.geometry().origin + position.to_euclid().to_vector(),
1906            );
1907            let position = crate::lengths::logical_position_to_api(position);
1908            x.show_native_popup_menu(context_menu_item, position)
1909        } else {
1910            false
1911        }
1912    }
1913
1914    // Close the popup associated with the given popup window.
1915    // The parent's `is-open` property is reset to false when `current_popup` is dropped (see the
1916    // `Drop` impl for `PopupWindow`), which every close path eventually does.
1917    fn close_popup_impl(&self, current_popup: &PopupWindow) {
1918        match &current_popup.location {
1919            PopupWindowLocation::ChildWindow(offset) => {
1920                // Refresh the area that was previously covered by the popup.
1921                let popup_region = crate::properties::evaluate_no_tracking(|| {
1922                    let popup_component = ItemTreeRc::borrow_pin(&current_popup.component);
1923                    popup_component.as_ref().item_geometry(0)
1924                })
1925                .translate(offset.to_vector());
1926
1927                if !popup_region.is_empty() {
1928                    let window_adapter = self.window_adapter();
1929                    window_adapter.renderer().mark_dirty_region(popup_region.into());
1930                    window_adapter.request_redraw();
1931                }
1932            }
1933            PopupWindowLocation::TopLevel(adapter) => {
1934                let _ = adapter.set_visible(false);
1935            }
1936        }
1937        if let Some(focus) = current_popup.focus_item_in_parent.upgrade() {
1938            self.set_focus_item(&focus, true, FocusReason::PopupActivation);
1939        }
1940    }
1941
1942    /// Removes the popup matching the given ID.
1943    pub fn close_popup(&self, popup_id: NonZeroU32) {
1944        let mut active_popups = self.active_popups.borrow_mut();
1945        let maybe_index = active_popups.iter().position(|popup| popup.popup_id == popup_id);
1946
1947        if let Some(popup_index) = maybe_index {
1948            let p = active_popups.remove(popup_index);
1949            drop(active_popups);
1950            self.close_popup_impl(&p);
1951            if matches!(p.window_kind, WindowKind::Menu) {
1952                // close all sub-menus
1953                while self
1954                    .active_popups
1955                    .borrow()
1956                    .get(popup_index)
1957                    .is_some_and(|p| matches!(p.window_kind, WindowKind::Menu))
1958                {
1959                    let p = self.active_popups.borrow_mut().remove(popup_index);
1960                    self.close_popup_impl(&p);
1961                }
1962            }
1963        }
1964    }
1965
1966    /// Close all active popups.
1967    pub fn close_all_popups(&self) {
1968        for popup in self.active_popups.take() {
1969            self.close_popup_impl(&popup);
1970        }
1971    }
1972
1973    /// Close the top-most popup.
1974    pub fn close_top_popup(&self) {
1975        let popup = self.active_popups.borrow_mut().pop();
1976        if let Some(popup) = popup {
1977            self.close_popup_impl(&popup);
1978        }
1979    }
1980
1981    /// Returns the scale factor set on the window, as provided by the windowing system.
1982    pub fn scale_factor(&self) -> f32 {
1983        self.pinned_fields.as_ref().project_ref().scale_factor.get()
1984    }
1985
1986    /// Sets the scale factor for the window. This is set by the backend or for testing.
1987    pub(crate) fn set_scale_factor(&self, factor: f32) {
1988        if !self.pinned_fields.scale_factor.is_constant() {
1989            self.pinned_fields.scale_factor.set(factor)
1990        }
1991    }
1992
1993    /// Sets the scale factor for the window.
1994    /// From that point on, the scale factor is constant and cannot be changed anymore.
1995    pub fn set_const_scale_factor(&self, factor: f32) {
1996        if !self.pinned_fields.scale_factor.is_constant() {
1997            self.pinned_fields.scale_factor.set(factor);
1998            self.pinned_fields.scale_factor.set_constant();
1999        }
2000    }
2001
2002    /// Reads the global property `TextInputInterface.text-input-focused`
2003    pub fn text_input_focused(&self) -> bool {
2004        self.pinned_fields.as_ref().project_ref().text_input_focused.get()
2005    }
2006
2007    /// Sets the global property `TextInputInterface.text-input-focused`
2008    pub fn set_text_input_focused(&self, value: bool) {
2009        if !value && let Some(window_adapter) = self.window_adapter().internal(crate::InternalToken)
2010        {
2011            window_adapter.input_method_request(InputMethodRequest::Disable);
2012        }
2013        self.pinned_fields.text_input_focused.set(value)
2014    }
2015
2016    /// Returns true if the window is visible
2017    pub fn is_visible(&self) -> bool {
2018        self.strong_component_ref.borrow().is_some()
2019    }
2020
2021    /// Returns the window item that is the first item in the component. When Some()
2022    /// is returned, it's guaranteed to be safe to downcast to `WindowItem`.
2023    pub fn window_item_rc(&self) -> Option<ItemRc> {
2024        self.try_component().and_then(|component_rc| {
2025            let item_rc = ItemRc::new_root(component_rc);
2026            if item_rc.downcast::<crate::items::WindowItem>().is_some() {
2027                Some(item_rc)
2028            } else {
2029                None
2030            }
2031        })
2032    }
2033
2034    /// Returns the window item that is the first item in the component.
2035    pub fn window_item(&self) -> Option<VRcMapped<ItemTreeVTable, crate::items::WindowItem>> {
2036        self.try_component().and_then(|component_rc| {
2037            ItemRc::new_root(component_rc).downcast::<crate::items::WindowItem>()
2038        })
2039    }
2040
2041    /// Sets the size of the window item. This method is typically called in response to receiving a
2042    /// window resize event from the windowing system.
2043    pub(crate) fn set_window_item_geometry(&self, size: crate::lengths::LogicalSize) {
2044        if let Some(component_rc) = self.try_component() {
2045            let component = ItemTreeRc::borrow_pin(&component_rc);
2046            let root_item = component.as_ref().get_item_ref(0);
2047            if let Some(window_item) = ItemRef::downcast_pin::<crate::items::WindowItem>(root_item)
2048            {
2049                window_item.width.set(size.width_length());
2050                window_item.height.set(size.height_length());
2051            }
2052        }
2053    }
2054
2055    /// The safe area of the window has changed.
2056    pub fn set_window_item_safe_area(&self, inset: crate::lengths::LogicalEdges) {
2057        if let Some(component_rc) = self.try_component() {
2058            let component = ItemTreeRc::borrow_pin(&component_rc);
2059            let root_item = component.as_ref().get_item_ref(0);
2060            if let Some(window_item) = ItemRef::downcast_pin::<crate::items::WindowItem>(root_item)
2061            {
2062                window_item.safe_area_insets.set(inset);
2063            }
2064        }
2065    }
2066
2067    pub(crate) fn set_window_item_virtual_keyboard(
2068        &self,
2069        origin: crate::lengths::LogicalPoint,
2070        size: crate::lengths::LogicalSize,
2071    ) {
2072        let Some(component_rc) = self.try_component() else {
2073            return;
2074        };
2075        let component = ItemTreeRc::borrow_pin(&component_rc);
2076        let root_item = component.as_ref().get_item_ref(0);
2077        let Some(window_item) = ItemRef::downcast_pin::<crate::items::WindowItem>(root_item) else {
2078            return;
2079        };
2080        window_item.virtual_keyboard_position.set(origin);
2081        window_item.virtual_keyboard_size.set(size);
2082        if let Some(focus_item) = self.focus_item.borrow().upgrade() {
2083            focus_item.try_scroll_into_visible();
2084        }
2085    }
2086
2087    // Get geometry of the virtual keyboard if available
2088    pub(crate) fn window_item_virtual_keyboard(
2089        &self,
2090    ) -> Option<(crate::lengths::LogicalPoint, crate::lengths::LogicalSize)> {
2091        let component_rc = self.try_component()?;
2092        let component = ItemTreeRc::borrow_pin(&component_rc);
2093        let root_item = component.as_ref().get_item_ref(0);
2094        let window_item = ItemRef::downcast_pin::<crate::items::WindowItem>(root_item)?;
2095        let keyboard_size = window_item.virtual_keyboard_size();
2096        if keyboard_size.width == 0. as Coord || keyboard_size.height == 0. as Coord {
2097            None
2098        } else {
2099            Some((window_item.virtual_keyboard_position(), keyboard_size))
2100        }
2101    }
2102
2103    /// Sets the close_requested callback. The callback will be run when the user tries to close a window.
2104    pub fn on_close_requested(&self, mut callback: impl FnMut() -> CloseRequestResponse + 'static) {
2105        self.close_requested.set_handler(move |()| callback());
2106    }
2107
2108    /// Runs the close_requested callback.
2109    /// If the callback returns KeepWindowShown, this function returns false. That should prevent the Window from closing.
2110    /// Otherwise it returns true, which allows the Window to hide.
2111    pub fn request_close(&self) -> bool {
2112        match self.close_requested.call(&()) {
2113            CloseRequestResponse::HideWindow => true,
2114            CloseRequestResponse::KeepWindowShown => false,
2115        }
2116    }
2117
2118    /// Returns if the window is currently in fullscreen mode
2119    pub fn is_fullscreen(&self) -> bool {
2120        if let Some(window_item) = self.window_item() {
2121            window_item.as_pin_ref().full_screen()
2122        } else {
2123            false
2124        }
2125    }
2126
2127    /// Set or unset the window to display fullscreen.
2128    pub fn set_fullscreen(&self, enabled: bool) {
2129        if let Some(window_item) = self.window_item() {
2130            window_item.as_pin_ref().full_screen.set(enabled);
2131            self.update_window_properties()
2132        }
2133    }
2134
2135    /// Returns if the window is currently maximized
2136    pub fn is_maximized(&self) -> bool {
2137        self.window_item().is_some_and(|window_item| window_item.as_pin_ref().maximized())
2138    }
2139
2140    /// Set the window as maximized or unmaximized
2141    pub fn set_maximized(&self, maximized: bool) {
2142        if let Some(window_item) = self.window_item() {
2143            window_item.as_pin_ref().maximized.set(maximized);
2144            self.update_window_properties()
2145        }
2146    }
2147
2148    /// Returns if the window is currently minimized
2149    pub fn is_minimized(&self) -> bool {
2150        self.window_item().is_some_and(|window_item| window_item.as_pin_ref().minimized())
2151    }
2152
2153    /// Set the window as minimized or unminimized
2154    pub fn set_minimized(&self, minimized: bool) {
2155        if let Some(window_item) = self.window_item() {
2156            window_item.as_pin_ref().minimized.set(minimized);
2157            self.update_window_properties()
2158        }
2159    }
2160
2161    /// Returns the (context global) xdg app id for use with wayland and x11.
2162    pub fn xdg_app_id(&self) -> Option<SharedString> {
2163        self.context().xdg_app_id()
2164    }
2165
2166    /// Returns the upgraded window adapter
2167    pub fn window_adapter(&self) -> Rc<dyn WindowAdapter> {
2168        self.window_adapter_weak.upgrade().unwrap()
2169    }
2170
2171    /// Private access to the WindowInner for a given window.
2172    pub fn from_pub(window: &crate::api::Window) -> &Self {
2173        &window.0
2174    }
2175
2176    /// Provides access to the Windows' Slint context.
2177    pub fn context(&self) -> &crate::SlintContext {
2178        self.ctx
2179            .get_or_init(|| crate::context::GLOBAL_CONTEXT.with(|ctx| ctx.get().unwrap().clone()))
2180    }
2181
2182    /// Like [`Self::context`], but returns `None` instead of panicking when no context is
2183    /// available yet.
2184    pub fn try_context(&self) -> Option<&crate::SlintContext> {
2185        if self.ctx.get().is_none()
2186            && let Some(ctx) = crate::context::GLOBAL_CONTEXT.with(|ctx| ctx.get().cloned())
2187        {
2188            let _ = self.ctx.set(ctx);
2189        }
2190        self.ctx.get()
2191    }
2192
2193    /// Set the SlintContext.
2194    /// This needs to be called once before any other functions that would use the context.
2195    pub fn set_context(&self, ctx: crate::SlintContext) {
2196        self.ctx.set(ctx).map_err(|_| ()).expect("context shouldn't have been set before")
2197    }
2198}
2199
2200/// Internal alias for `Rc<dyn WindowAdapter>`.
2201pub type WindowAdapterRc = Rc<dyn WindowAdapter>;
2202
2203/// Resolve the [`crate::SlintContext`] associated with a component root by
2204/// asking it for (or creating) its window adapter and reading the context off
2205/// the resulting window. Returns `None` only when no adapter can be produced.
2206pub fn context_for_root(root: &ItemTreeRc) -> Option<crate::SlintContext> {
2207    let comp_ref_pin = vtable::VRc::borrow_pin(root);
2208    let mut adapter = None;
2209    comp_ref_pin.as_ref().window_adapter(true, &mut adapter);
2210    adapter.map(|a| WindowInner::from_pub(a.window()).context().clone())
2211}
2212
2213/// Runtime entry point for `BuiltinFunction::AccentColor`. Returns the accent color
2214/// from the component's [`crate::SlintContext`] reached via its window adapter, or
2215/// transparent if none is associated.
2216pub fn accent_color(root: &crate::item_tree::ItemTreeRc) -> crate::graphics::Color {
2217    let comp_ref_pin = vtable::VRc::borrow_pin(root);
2218    let mut adapter = None;
2219    comp_ref_pin.as_ref().window_adapter(true, &mut adapter);
2220    adapter.map_or(crate::graphics::Color::default(), |a| {
2221        WindowInner::from_pub(a.window()).context().accent_color()
2222    })
2223}
2224
2225/// This module contains the functions needed to interface with the event loop and window traits
2226/// from outside the Rust language.
2227#[cfg(feature = "ffi")]
2228pub mod ffi {
2229    #![allow(unsafe_code)]
2230    #![allow(clippy::missing_safety_doc)]
2231    #![allow(missing_docs)]
2232
2233    use super::*;
2234    use crate::SharedVector;
2235    use crate::api::{RenderingNotifier, RenderingState, SetRenderingNotifierError};
2236    use crate::graphics::Size;
2237    use crate::graphics::{IntSize, Rgba8Pixel};
2238    use crate::items::WindowItem;
2239    use core::ffi::c_void;
2240
2241    /// This enum describes a low-level access to specific graphics APIs used
2242    /// by the renderer.
2243    #[repr(u8)]
2244    pub enum GraphicsAPI {
2245        /// The rendering is done using OpenGL.
2246        NativeOpenGL,
2247        /// The rendering is done using APIs inaccessible from C++, such as WGPU.
2248        Inaccessible,
2249    }
2250
2251    struct WithUserData<T> {
2252        callback: T,
2253        drop_user_data: extern "C" fn(*mut c_void),
2254        user_data: *mut c_void,
2255    }
2256
2257    impl<T> Drop for WithUserData<T> {
2258        fn drop(&mut self) {
2259            (self.drop_user_data)(self.user_data)
2260        }
2261    }
2262
2263    impl WithUserData<extern "C" fn(user_data: *mut c_void, pos: &mut LogicalPosition)> {
2264        fn call(&self) -> LogicalPosition {
2265            let mut logical_position = LogicalPosition::default();
2266            (self.callback)(self.user_data, &mut logical_position);
2267            logical_position
2268        }
2269    }
2270
2271    impl WithUserData<extern "C" fn(user_data: *mut c_void) -> CloseRequestResponse> {
2272        fn call(&self) -> CloseRequestResponse {
2273            (self.callback)(self.user_data)
2274        }
2275    }
2276
2277    impl WithUserData<extern "C" fn(user_data: *mut c_void, is_open: bool)> {
2278        fn call(&self, is_open: bool) {
2279            (self.callback)(self.user_data, is_open)
2280        }
2281    }
2282
2283    /// Same layout as WindowAdapterRc
2284    #[repr(C)]
2285    pub struct WindowAdapterRcOpaque(*const c_void, *const c_void);
2286
2287    /// Releases the reference to the windowrc held by handle.
2288    #[unsafe(no_mangle)]
2289    pub unsafe extern "C" fn slint_windowrc_drop(handle: *mut WindowAdapterRcOpaque) {
2290        unsafe {
2291            assert_eq!(
2292                core::mem::size_of::<Rc<dyn WindowAdapter>>(),
2293                core::mem::size_of::<WindowAdapterRcOpaque>()
2294            );
2295            assert_eq!(
2296                core::mem::size_of::<Option<Rc<dyn WindowAdapter>>>(),
2297                core::mem::size_of::<WindowAdapterRcOpaque>()
2298            );
2299            drop(core::ptr::read(handle as *mut Option<Rc<dyn WindowAdapter>>));
2300        }
2301    }
2302
2303    /// Releases the reference to the component window held by handle.
2304    #[unsafe(no_mangle)]
2305    pub unsafe extern "C" fn slint_windowrc_clone(
2306        source: *const WindowAdapterRcOpaque,
2307        target: *mut WindowAdapterRcOpaque,
2308    ) {
2309        unsafe {
2310            assert_eq!(
2311                core::mem::size_of::<Rc<dyn WindowAdapter>>(),
2312                core::mem::size_of::<WindowAdapterRcOpaque>()
2313            );
2314            let window = &*(source as *const Rc<dyn WindowAdapter>);
2315            core::ptr::write(target as *mut Rc<dyn WindowAdapter>, window.clone());
2316        }
2317    }
2318
2319    /// Ensure repeaters, conditionals and component containers are instantiated.
2320    #[unsafe(no_mangle)]
2321    pub unsafe extern "C" fn slint_windowrc_ensure_tree_instantiated(
2322        handle: *const WindowAdapterRcOpaque,
2323    ) {
2324        unsafe {
2325            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2326            WindowInner::from_pub(window_adapter.window()).ensure_tree_instantiated();
2327        }
2328    }
2329
2330    /// Spins an event loop and renders the items of the provided component in this window.
2331    #[unsafe(no_mangle)]
2332    pub unsafe extern "C" fn slint_windowrc_show(handle: *const WindowAdapterRcOpaque) {
2333        unsafe {
2334            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2335
2336            window_adapter.window().show().unwrap();
2337        }
2338    }
2339
2340    /// Spins an event loop and renders the items of the provided component in this window.
2341    #[unsafe(no_mangle)]
2342    pub unsafe extern "C" fn slint_windowrc_hide(handle: *const WindowAdapterRcOpaque) {
2343        unsafe {
2344            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2345            window_adapter.window().hide().unwrap();
2346        }
2347    }
2348
2349    /// Returns the visibility state of the window. This function can return false even if you previously called show()
2350    /// on it, for example if the user minimized the window.
2351    #[unsafe(no_mangle)]
2352    pub unsafe extern "C" fn slint_windowrc_is_visible(
2353        handle: *const WindowAdapterRcOpaque,
2354    ) -> bool {
2355        unsafe {
2356            let window = &*(handle as *const Rc<dyn WindowAdapter>);
2357            window.window().is_visible()
2358        }
2359    }
2360
2361    /// Returns the window scale factor.
2362    #[unsafe(no_mangle)]
2363    pub unsafe extern "C" fn slint_windowrc_get_scale_factor(
2364        handle: *const WindowAdapterRcOpaque,
2365    ) -> f32 {
2366        unsafe {
2367            assert_eq!(
2368                core::mem::size_of::<Rc<dyn WindowAdapter>>(),
2369                core::mem::size_of::<WindowAdapterRcOpaque>()
2370            );
2371            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2372            WindowInner::from_pub(window_adapter.window()).scale_factor()
2373        }
2374    }
2375
2376    /// Sets the window scale factor, merely for testing purposes.
2377    #[unsafe(no_mangle)]
2378    pub unsafe extern "C" fn slint_windowrc_set_const_scale_factor(
2379        handle: *const WindowAdapterRcOpaque,
2380        value: f32,
2381    ) {
2382        unsafe {
2383            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2384            WindowInner::from_pub(window_adapter.window()).set_const_scale_factor(value)
2385        }
2386    }
2387
2388    /// Returns the text-input-focused property value.
2389    #[unsafe(no_mangle)]
2390    pub unsafe extern "C" fn slint_windowrc_get_text_input_focused(
2391        handle: *const WindowAdapterRcOpaque,
2392    ) -> bool {
2393        unsafe {
2394            assert_eq!(
2395                core::mem::size_of::<Rc<dyn WindowAdapter>>(),
2396                core::mem::size_of::<WindowAdapterRcOpaque>()
2397            );
2398            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2399            WindowInner::from_pub(window_adapter.window()).text_input_focused()
2400        }
2401    }
2402
2403    /// Set the text-input-focused property.
2404    #[unsafe(no_mangle)]
2405    pub unsafe extern "C" fn slint_windowrc_set_text_input_focused(
2406        handle: *const WindowAdapterRcOpaque,
2407        value: bool,
2408    ) {
2409        unsafe {
2410            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2411            WindowInner::from_pub(window_adapter.window()).set_text_input_focused(value)
2412        }
2413    }
2414
2415    /// Sets the focus item.
2416    #[unsafe(no_mangle)]
2417    pub unsafe extern "C" fn slint_windowrc_set_focus_item(
2418        handle: *const WindowAdapterRcOpaque,
2419        focus_item: &ItemRc,
2420        set_focus: bool,
2421        reason: FocusReason,
2422    ) {
2423        unsafe {
2424            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2425            WindowInner::from_pub(window_adapter.window())
2426                .set_focus_item(focus_item, set_focus, reason)
2427        }
2428    }
2429
2430    /// Associates the window with the given component.
2431    #[unsafe(no_mangle)]
2432    pub unsafe extern "C" fn slint_windowrc_set_component(
2433        handle: *const WindowAdapterRcOpaque,
2434        component: &ItemTreeRc,
2435    ) {
2436        unsafe {
2437            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2438            WindowInner::from_pub(window_adapter.window()).set_component(component)
2439        }
2440    }
2441
2442    /// Show a popup and return its ID. The returned ID will always be non-zero.
2443    #[unsafe(no_mangle)]
2444    pub unsafe extern "C" fn slint_windowrc_show_popup(
2445        handle: *const WindowAdapterRcOpaque,
2446        popup: &ItemTreeRc,
2447        position: extern "C" fn(user_data: *mut c_void, pos: &mut LogicalPosition),
2448        drop_user_data: extern "C" fn(user_data: *mut c_void),
2449        user_data: *mut c_void,
2450        close_policy: PopupClosePolicy,
2451        parent_item: &ItemRc,
2452        window_kind: WindowKind,
2453        is_open_setter: extern "C" fn(user_data: *mut c_void, is_open: bool),
2454        is_open_setter_drop_user_data: extern "C" fn(user_data: *mut c_void),
2455        is_open_setter_user_data: *mut c_void,
2456    ) -> NonZeroU32 {
2457        unsafe {
2458            let with_user_data = WithUserData { callback: position, drop_user_data, user_data };
2459            let is_open_with_user_data = WithUserData {
2460                callback: is_open_setter,
2461                drop_user_data: is_open_setter_drop_user_data,
2462                user_data: is_open_setter_user_data,
2463            };
2464            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2465            WindowInner::from_pub(window_adapter.window()).show_popup(
2466                popup,
2467                Box::new(move || with_user_data.call()),
2468                close_policy,
2469                parent_item,
2470                window_kind,
2471                Box::new(move |is_open| is_open_with_user_data.call(is_open)),
2472            )
2473        }
2474    }
2475
2476    /// Create a popup window adapter. Returns true if a new adapter was created and written to result.
2477    /// Returns false if the backend does not support top-level popups.
2478    /// This can be used to set the correct window adapter on a popup component before showing it.
2479    #[unsafe(no_mangle)]
2480    pub unsafe extern "C" fn slint_windowrc_create_child_window_adapter(
2481        handle: *const WindowAdapterRcOpaque,
2482        window_kind: WindowKind,
2483        result: *mut WindowAdapterRcOpaque,
2484    ) -> bool {
2485        unsafe {
2486            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2487            match WindowInner::from_pub(window_adapter.window())
2488                .create_child_window_adapter(window_kind)
2489            {
2490                Some(wa) => {
2491                    core::ptr::write(result as *mut Rc<dyn WindowAdapter>, wa);
2492                    true
2493                }
2494                None => false,
2495            }
2496        }
2497    }
2498
2499    /// Close the popup by the given ID.
2500    #[unsafe(no_mangle)]
2501    pub unsafe extern "C" fn slint_windowrc_close_popup(
2502        handle: *const WindowAdapterRcOpaque,
2503        popup_id: NonZeroU32,
2504    ) {
2505        unsafe {
2506            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2507            WindowInner::from_pub(window_adapter.window()).close_popup(popup_id);
2508        }
2509    }
2510
2511    /// C binding to the set_rendering_notifier() API of Window
2512    #[unsafe(no_mangle)]
2513    pub unsafe extern "C" fn slint_windowrc_set_rendering_notifier(
2514        handle: *const WindowAdapterRcOpaque,
2515        callback: extern "C" fn(
2516            rendering_state: RenderingState,
2517            graphics_api: GraphicsAPI,
2518            user_data: *mut c_void,
2519        ),
2520        drop_user_data: extern "C" fn(user_data: *mut c_void),
2521        user_data: *mut c_void,
2522        error: *mut SetRenderingNotifierError,
2523    ) -> bool {
2524        unsafe {
2525            struct CNotifier {
2526                callback: extern "C" fn(
2527                    rendering_state: RenderingState,
2528                    graphics_api: GraphicsAPI,
2529                    user_data: *mut c_void,
2530                ),
2531                drop_user_data: extern "C" fn(*mut c_void),
2532                user_data: *mut c_void,
2533            }
2534
2535            impl Drop for CNotifier {
2536                fn drop(&mut self) {
2537                    (self.drop_user_data)(self.user_data)
2538                }
2539            }
2540
2541            impl RenderingNotifier for CNotifier {
2542                fn notify(
2543                    &mut self,
2544                    state: RenderingState,
2545                    graphics_api: &crate::api::GraphicsAPI,
2546                ) {
2547                    let cpp_graphics_api = match graphics_api {
2548                        crate::api::GraphicsAPI::NativeOpenGL { .. } => GraphicsAPI::NativeOpenGL,
2549                        crate::api::GraphicsAPI::WebGL { .. } => unreachable!(), // We don't support wasm with C++
2550                        #[cfg(feature = "unstable-wgpu-28")]
2551                        crate::api::GraphicsAPI::WGPU28 { .. } => GraphicsAPI::Inaccessible, // There is no C++ API for wgpu (maybe wgpu c in the future?)
2552                        #[cfg(feature = "unstable-wgpu-29")]
2553                        crate::api::GraphicsAPI::WGPU29 { .. } => GraphicsAPI::Inaccessible, // There is no C++ API for wgpu (maybe wgpu c in the future?)
2554                    };
2555                    (self.callback)(state, cpp_graphics_api, self.user_data)
2556                }
2557            }
2558
2559            let window = &*(handle as *const Rc<dyn WindowAdapter>);
2560            match window.renderer().set_rendering_notifier(Box::new(CNotifier {
2561                callback,
2562                drop_user_data,
2563                user_data,
2564            })) {
2565                Ok(()) => true,
2566                Err(err) => {
2567                    *error = err;
2568                    false
2569                }
2570            }
2571        }
2572    }
2573
2574    /// C binding to the on_close_requested() API of Window
2575    #[unsafe(no_mangle)]
2576    pub unsafe extern "C" fn slint_windowrc_on_close_requested(
2577        handle: *const WindowAdapterRcOpaque,
2578        callback: extern "C" fn(user_data: *mut c_void) -> CloseRequestResponse,
2579        drop_user_data: extern "C" fn(user_data: *mut c_void),
2580        user_data: *mut c_void,
2581    ) {
2582        unsafe {
2583            let with_user_data = WithUserData { callback, drop_user_data, user_data };
2584            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2585            window_adapter.window().on_close_requested(move || with_user_data.call());
2586        }
2587    }
2588
2589    /// This function issues a request to the windowing system to redraw the contents of the window.
2590    #[unsafe(no_mangle)]
2591    pub unsafe extern "C" fn slint_windowrc_request_redraw(handle: *const WindowAdapterRcOpaque) {
2592        unsafe {
2593            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2594            window_adapter.request_redraw();
2595        }
2596    }
2597
2598    /// Returns the position of the window on the screen, in physical screen coordinates and including
2599    /// a window frame (if present).
2600    #[unsafe(no_mangle)]
2601    pub unsafe extern "C" fn slint_windowrc_position(
2602        handle: *const WindowAdapterRcOpaque,
2603        pos: &mut euclid::default::Point2D<i32>,
2604    ) {
2605        unsafe {
2606            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2607            *pos = window_adapter.position().unwrap_or_default().to_euclid()
2608        }
2609    }
2610
2611    /// Sets the position of the window on the screen, in physical screen coordinates and including
2612    /// a window frame (if present).
2613    /// Note that on some windowing systems, such as Wayland, this functionality is not available.
2614    #[unsafe(no_mangle)]
2615    pub unsafe extern "C" fn slint_windowrc_set_physical_position(
2616        handle: *const WindowAdapterRcOpaque,
2617        pos: &euclid::default::Point2D<i32>,
2618    ) {
2619        unsafe {
2620            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2621            window_adapter.set_position(crate::api::PhysicalPosition::new(pos.x, pos.y).into());
2622        }
2623    }
2624
2625    /// Sets the position of the window on the screen, in physical screen coordinates and including
2626    /// a window frame (if present).
2627    /// Note that on some windowing systems, such as Wayland, this functionality is not available.
2628    #[unsafe(no_mangle)]
2629    pub unsafe extern "C" fn slint_windowrc_set_logical_position(
2630        handle: *const WindowAdapterRcOpaque,
2631        pos: &euclid::default::Point2D<f32>,
2632    ) {
2633        unsafe {
2634            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2635            window_adapter.set_position(LogicalPosition::new(pos.x, pos.y).into());
2636        }
2637    }
2638
2639    /// Returns the size of the window on the screen, in physical screen coordinates and excluding
2640    /// a window frame (if present).
2641    #[unsafe(no_mangle)]
2642    pub unsafe extern "C" fn slint_windowrc_size(handle: *const WindowAdapterRcOpaque) -> IntSize {
2643        unsafe {
2644            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2645            window_adapter.size().to_euclid().cast()
2646        }
2647    }
2648
2649    /// Resizes the window to the specified size on the screen, in physical pixels and excluding
2650    /// a window frame (if present).
2651    #[unsafe(no_mangle)]
2652    pub unsafe extern "C" fn slint_windowrc_set_physical_size(
2653        handle: *const WindowAdapterRcOpaque,
2654        size: &IntSize,
2655    ) {
2656        unsafe {
2657            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2658            window_adapter
2659                .window()
2660                .set_size(crate::api::PhysicalSize::new(size.width, size.height));
2661        }
2662    }
2663
2664    /// Resizes the window to the specified size on the screen, in physical pixels and excluding
2665    /// a window frame (if present).
2666    #[unsafe(no_mangle)]
2667    pub unsafe extern "C" fn slint_windowrc_set_logical_size(
2668        handle: *const WindowAdapterRcOpaque,
2669        size: &Size,
2670    ) {
2671        unsafe {
2672            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2673            window_adapter.window().set_size(crate::api::LogicalSize::new(size.width, size.height));
2674        }
2675    }
2676
2677    /// Return whether the platform supports native menu bars
2678    #[unsafe(no_mangle)]
2679    pub unsafe extern "C" fn slint_windowrc_supports_native_menu_bar(
2680        handle: *const WindowAdapterRcOpaque,
2681    ) -> bool {
2682        unsafe {
2683            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2684            window_adapter
2685                .internal(crate::InternalToken)
2686                .is_some_and(|x| x.supports_native_menu_bar())
2687        }
2688    }
2689
2690    /// Setup the native menu bar
2691    #[unsafe(no_mangle)]
2692    pub unsafe extern "C" fn slint_windowrc_setup_native_menu_bar(
2693        handle: *const WindowAdapterRcOpaque,
2694        menu_instance: &vtable::VRc<MenuVTable>,
2695    ) {
2696        let window_adapter = unsafe { &*(handle as *const Rc<dyn WindowAdapter>) };
2697        let window = window_adapter.window();
2698        window.0.setup_menubar(vtable::VRc::clone(menu_instance));
2699    }
2700
2701    #[unsafe(no_mangle)]
2702    pub unsafe extern "C" fn slint_windowrc_setup_menu_bar_shortcuts(
2703        handle: *const WindowAdapterRcOpaque,
2704        menu_instance: &vtable::VRc<MenuVTable>,
2705    ) {
2706        let window_adapter = unsafe { &*(handle as *const Rc<dyn WindowAdapter>) };
2707        let window = window_adapter.window();
2708        window.0.setup_menubar_shortcuts(vtable::VRc::clone(menu_instance));
2709    }
2710
2711    /// Show a native context menu
2712    #[unsafe(no_mangle)]
2713    pub unsafe extern "C" fn slint_windowrc_show_native_popup_menu(
2714        handle: *const WindowAdapterRcOpaque,
2715        context_menu: &vtable::VRc<MenuVTable>,
2716        position: LogicalPosition,
2717        parent_item: &ItemRc,
2718    ) -> bool {
2719        unsafe {
2720            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2721            WindowInner::from_pub(window_adapter.window()).show_native_popup_menu(
2722                context_menu.clone(),
2723                position,
2724                parent_item,
2725            )
2726        }
2727    }
2728
2729    /// Return the default-font-size property of the WindowItem
2730    #[unsafe(no_mangle)]
2731    pub unsafe extern "C" fn slint_windowrc_resolved_default_font_size(
2732        item_tree: &ItemTreeRc,
2733    ) -> f32 {
2734        WindowItem::resolved_default_font_size(item_tree.clone()).get()
2735    }
2736
2737    /// Dispatch a key pressed or release event
2738    #[unsafe(no_mangle)]
2739    pub unsafe extern "C" fn slint_windowrc_dispatch_key_event(
2740        handle: *const WindowAdapterRcOpaque,
2741        event_type: crate::input::KeyEventType,
2742        text: &SharedString,
2743        repeat: bool,
2744    ) {
2745        unsafe {
2746            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2747            window_adapter.window().0.process_key_input(InternalKeyEvent {
2748                event_type,
2749                key_event: crate::items::KeyEvent {
2750                    text: text.clone(),
2751                    repeat,
2752                    ..Default::default()
2753                },
2754                ..Default::default()
2755            });
2756        }
2757    }
2758
2759    /// Dispatch a mouse event
2760    #[unsafe(no_mangle)]
2761    pub unsafe extern "C" fn slint_windowrc_dispatch_pointer_event(
2762        handle: *const WindowAdapterRcOpaque,
2763        event: &crate::input::MouseEvent,
2764    ) {
2765        unsafe {
2766            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2767            window_adapter.window().0.process_mouse_input(event.clone());
2768        }
2769    }
2770
2771    /// Dispatch a window event
2772    #[unsafe(no_mangle)]
2773    pub unsafe extern "C" fn slint_windowrc_dispatch_event(
2774        handle: *const WindowAdapterRcOpaque,
2775        event: &crate::platform::WindowEvent,
2776    ) {
2777        unsafe {
2778            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2779            window_adapter.window().dispatch_event(event.clone());
2780        }
2781    }
2782
2783    #[unsafe(no_mangle)]
2784    pub unsafe extern "C" fn slint_windowrc_is_fullscreen(
2785        handle: *const WindowAdapterRcOpaque,
2786    ) -> bool {
2787        unsafe {
2788            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2789            window_adapter.window().is_fullscreen()
2790        }
2791    }
2792
2793    #[unsafe(no_mangle)]
2794    pub unsafe extern "C" fn slint_windowrc_is_minimized(
2795        handle: *const WindowAdapterRcOpaque,
2796    ) -> bool {
2797        unsafe {
2798            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2799            window_adapter.window().is_minimized()
2800        }
2801    }
2802
2803    #[unsafe(no_mangle)]
2804    pub unsafe extern "C" fn slint_windowrc_is_maximized(
2805        handle: *const WindowAdapterRcOpaque,
2806    ) -> bool {
2807        unsafe {
2808            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2809            window_adapter.window().is_maximized()
2810        }
2811    }
2812
2813    #[unsafe(no_mangle)]
2814    pub unsafe extern "C" fn slint_windowrc_set_fullscreen(
2815        handle: *const WindowAdapterRcOpaque,
2816        value: bool,
2817    ) {
2818        unsafe {
2819            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2820            window_adapter.window().set_fullscreen(value)
2821        }
2822    }
2823
2824    #[unsafe(no_mangle)]
2825    pub unsafe extern "C" fn slint_windowrc_set_minimized(
2826        handle: *const WindowAdapterRcOpaque,
2827        value: bool,
2828    ) {
2829        unsafe {
2830            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2831            window_adapter.window().set_minimized(value)
2832        }
2833    }
2834
2835    #[unsafe(no_mangle)]
2836    pub unsafe extern "C" fn slint_windowrc_set_maximized(
2837        handle: *const WindowAdapterRcOpaque,
2838        value: bool,
2839    ) {
2840        unsafe {
2841            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2842            window_adapter.window().set_maximized(value)
2843        }
2844    }
2845
2846    /// Takes a snapshot of the window contents and returns it as RGBA8 encoded pixel buffer.
2847    #[unsafe(no_mangle)]
2848    pub unsafe extern "C" fn slint_windowrc_take_snapshot(
2849        handle: *const WindowAdapterRcOpaque,
2850        data: &mut SharedVector<Rgba8Pixel>,
2851        width: &mut u32,
2852        height: &mut u32,
2853    ) -> bool {
2854        unsafe {
2855            let window_adapter = &*(handle as *const Rc<dyn WindowAdapter>);
2856            if let Ok(snapshot) = window_adapter.window().take_snapshot() {
2857                *data = snapshot.data.clone();
2858                *width = snapshot.width();
2859                *height = snapshot.height();
2860                true
2861            } else {
2862                false
2863            }
2864        }
2865    }
2866}
2867
2868/// This module contains the functions needed to interface with window handles from outside the Rust language.
2869#[cfg(all(feature = "ffi", feature = "raw-window-handle-06"))]
2870pub mod ffi_window {
2871    #![allow(unsafe_code)]
2872    #![allow(clippy::missing_safety_doc)]
2873
2874    use super::ffi::WindowAdapterRcOpaque;
2875    use super::*;
2876    use std::ffi::c_void;
2877    use std::ptr::null_mut;
2878    use std::sync::Arc;
2879
2880    /// Helper to grab the `HasWindowHandle` for the `WindowAdapter` behind `handle`.
2881    fn has_window_handle(
2882        handle: *const WindowAdapterRcOpaque,
2883    ) -> Option<Arc<dyn raw_window_handle_06::HasWindowHandle>> {
2884        let window_adapter = unsafe { &*(handle as *const Rc<dyn WindowAdapter>) };
2885        let window_adapter = window_adapter.internal(crate::InternalToken)?;
2886        window_adapter.window_handle_06_rc().ok()
2887    }
2888
2889    /// Helper to grab the `HasDisplayHandle` for the `WindowAdapter` behind `handle`.
2890    fn has_display_handle(
2891        handle: *const WindowAdapterRcOpaque,
2892    ) -> Option<Arc<dyn raw_window_handle_06::HasDisplayHandle>> {
2893        let window_adapter = unsafe { &*(handle as *const Rc<dyn WindowAdapter>) };
2894        let window_adapter = window_adapter.internal(crate::InternalToken)?;
2895        window_adapter.display_handle_06_rc().ok()
2896    }
2897
2898    /// Returns the `HWND` associated with this window, or null if it doesn't exist or isn't created yet.
2899    #[unsafe(no_mangle)]
2900    pub unsafe extern "C" fn slint_windowrc_hwnd_win32(
2901        handle: *const WindowAdapterRcOpaque,
2902    ) -> *mut c_void {
2903        use raw_window_handle_06::HasWindowHandle;
2904
2905        if let Some(has_window_handle) = has_window_handle(handle)
2906            && let Ok(window_handle) = has_window_handle.window_handle()
2907            && let raw_window_handle_06::RawWindowHandle::Win32(win32) = window_handle.as_raw()
2908        {
2909            isize::from(win32.hwnd) as *mut c_void
2910        } else {
2911            null_mut()
2912        }
2913    }
2914
2915    /// Returns the `HINSTANCE` associated with this window, or null if it doesn't exist or isn't created yet.
2916    #[unsafe(no_mangle)]
2917    pub unsafe extern "C" fn slint_windowrc_hinstance_win32(
2918        handle: *const WindowAdapterRcOpaque,
2919    ) -> *mut c_void {
2920        use raw_window_handle_06::HasWindowHandle;
2921
2922        if let Some(has_window_handle) = has_window_handle(handle)
2923            && let Ok(window_handle) = has_window_handle.window_handle()
2924            && let raw_window_handle_06::RawWindowHandle::Win32(win32) = window_handle.as_raw()
2925        {
2926            win32
2927                .hinstance
2928                .map(|hinstance| isize::from(hinstance) as *mut c_void)
2929                .unwrap_or_default()
2930        } else {
2931            null_mut()
2932        }
2933    }
2934
2935    /// Returns the `wl_surface` associated with this window, or null if it doesn't exist or isn't created yet.
2936    #[unsafe(no_mangle)]
2937    pub unsafe extern "C" fn slint_windowrc_wlsurface_wayland(
2938        handle: *const WindowAdapterRcOpaque,
2939    ) -> *mut c_void {
2940        use raw_window_handle_06::HasWindowHandle;
2941
2942        if let Some(has_window_handle) = has_window_handle(handle)
2943            && let Ok(window_handle) = has_window_handle.window_handle()
2944            && let raw_window_handle_06::RawWindowHandle::Wayland(wayland) = window_handle.as_raw()
2945        {
2946            wayland.surface.as_ptr()
2947        } else {
2948            null_mut()
2949        }
2950    }
2951
2952    /// Returns the `wl_display` associated with this window, or null if it doesn't exist or isn't created yet.
2953    #[unsafe(no_mangle)]
2954    pub unsafe extern "C" fn slint_windowrc_wldisplay_wayland(
2955        handle: *const WindowAdapterRcOpaque,
2956    ) -> *mut c_void {
2957        use raw_window_handle_06::HasDisplayHandle;
2958
2959        if let Some(has_display_handle) = has_display_handle(handle)
2960            && let Ok(display_handle) = has_display_handle.display_handle()
2961            && let raw_window_handle_06::RawDisplayHandle::Wayland(wayland) =
2962                display_handle.as_raw()
2963        {
2964            wayland.display.as_ptr()
2965        } else {
2966            null_mut()
2967        }
2968    }
2969
2970    /// Returns the `NSView` associated with this window, or null if it doesn't exist or isn't created yet.
2971    #[unsafe(no_mangle)]
2972    pub unsafe extern "C" fn slint_windowrc_nsview_appkit(
2973        handle: *const WindowAdapterRcOpaque,
2974    ) -> *mut c_void {
2975        use raw_window_handle_06::HasWindowHandle;
2976
2977        if let Some(has_window_handle) = has_window_handle(handle)
2978            && let Ok(window_handle) = has_window_handle.window_handle()
2979            && let raw_window_handle_06::RawWindowHandle::AppKit(appkit) = window_handle.as_raw()
2980        {
2981            appkit.ns_view.as_ptr()
2982        } else {
2983            null_mut()
2984        }
2985    }
2986}