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