Skip to main content

i_slint_core/
api.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/*!
5This module contains types that are public and re-exported in the slint-rs as well as the slint-interpreter crate as public API.
6*/
7
8#![warn(missing_docs)]
9
10use crate::context::WindowEventDispatchResult;
11use crate::input::{InternalKeyEvent, KeyEventType, MouseEvent, TouchPhase};
12use crate::window::{WindowAdapter, WindowInner};
13use alloc::boxed::Box;
14use alloc::string::String;
15
16pub use crate::data_transfer::DataTransfer;
17#[cfg(target_has_atomic = "ptr")]
18pub use crate::future::*;
19pub use crate::graphics::{
20    Brush, Color, Image, LoadImageError, OklchColor, Rgb8Pixel, Rgba8Pixel, RgbaColor,
21    SharedPixelBuffer,
22};
23pub use crate::input::Keys;
24pub use crate::sharedvector::SharedVector;
25pub use crate::{format, string::SharedString, string::ToSharedString};
26
27impl From<crate::input::KeyEventResult> for WindowEventDispatchResult {
28    fn from(value: crate::input::KeyEventResult) -> Self {
29        match value {
30            crate::input::KeyEventResult::EventAccepted => Self::Accepted,
31            crate::input::KeyEventResult::EventIgnored => Self::Ignored,
32        }
33    }
34}
35
36impl From<Option<crate::window::MouseDispatchResult>> for WindowEventDispatchResult {
37    /// `None` (no component to dispatch to) and `accepted: false` both map to `Ignored`.
38    fn from(value: Option<crate::window::MouseDispatchResult>) -> Self {
39        if value.is_some_and(|r| r.accepted) { Self::Accepted } else { Self::Ignored }
40    }
41}
42
43/// A position represented in the coordinate space of logical pixels. That is the space before applying
44/// a display device specific scale factor.
45#[derive(Debug, Default, Copy, Clone, PartialEq)]
46#[repr(C)]
47#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
48pub struct LogicalPosition {
49    /// The x coordinate.
50    pub x: f32,
51    /// The y coordinate.
52    pub y: f32,
53}
54
55impl LogicalPosition {
56    /// Construct a new logical position from the given x and y coordinates, that are assumed to be
57    /// in the logical coordinate space.
58    pub const fn new(x: f32, y: f32) -> Self {
59        Self { x, y }
60    }
61
62    /// Convert a given physical position to a logical position by dividing the coordinates with the
63    /// specified scale factor.
64    pub fn from_physical(physical_pos: PhysicalPosition, scale_factor: f32) -> Self {
65        Self::new(physical_pos.x as f32 / scale_factor, physical_pos.y as f32 / scale_factor)
66    }
67
68    /// Convert this logical position to a physical position by multiplying the coordinates with the
69    /// specified scale factor.
70    pub fn to_physical(&self, scale_factor: f32) -> PhysicalPosition {
71        PhysicalPosition::from_logical(*self, scale_factor)
72    }
73
74    pub(crate) fn to_euclid(self) -> crate::lengths::LogicalPoint {
75        [self.x as _, self.y as _].into()
76    }
77    pub(crate) fn from_euclid(p: crate::lengths::LogicalPoint) -> Self {
78        Self::new(p.x as _, p.y as _)
79    }
80}
81
82/// A position represented in the coordinate space of physical device pixels. That is the space after applying
83/// a display device specific scale factor to pixels from the logical coordinate space.
84#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)]
85#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
86pub struct PhysicalPosition {
87    /// The x coordinate.
88    pub x: i32,
89    /// The y coordinate.
90    pub y: i32,
91}
92
93impl PhysicalPosition {
94    /// Construct a new physical position from the given x and y coordinates, that are assumed to be
95    /// in the physical coordinate space.
96    pub const fn new(x: i32, y: i32) -> Self {
97        Self { x, y }
98    }
99
100    /// Convert a given logical position to a physical position by multiplying the coordinates with the
101    /// specified scale factor.
102    pub fn from_logical(logical_pos: LogicalPosition, scale_factor: f32) -> Self {
103        Self::new((logical_pos.x * scale_factor) as i32, (logical_pos.y * scale_factor) as i32)
104    }
105
106    /// Convert this physical position to a logical position by dividing the coordinates with the
107    /// specified scale factor.
108    pub fn to_logical(&self, scale_factor: f32) -> LogicalPosition {
109        LogicalPosition::from_physical(*self, scale_factor)
110    }
111
112    #[cfg(feature = "ffi")]
113    pub(crate) fn to_euclid(self) -> crate::graphics::euclid::default::Point2D<i32> {
114        [self.x, self.y].into()
115    }
116
117    #[cfg(feature = "ffi")]
118    pub(crate) fn from_euclid(p: crate::graphics::euclid::default::Point2D<i32>) -> Self {
119        Self::new(p.x as _, p.y as _)
120    }
121}
122
123/// The position of the window in either physical or logical pixels. This is used
124/// with [`Window::set_position`].
125#[derive(Clone, Debug, derive_more::From, PartialEq)]
126pub enum WindowPosition {
127    /// The position in physical pixels.
128    Physical(PhysicalPosition),
129    /// The position in logical pixels.
130    Logical(LogicalPosition),
131}
132
133impl WindowPosition {
134    /// Turn the `WindowPosition` into a `PhysicalPosition`.
135    pub fn to_physical(&self, scale_factor: f32) -> PhysicalPosition {
136        match self {
137            WindowPosition::Physical(pos) => *pos,
138            WindowPosition::Logical(pos) => pos.to_physical(scale_factor),
139        }
140    }
141}
142
143/// A size represented in the coordinate space of logical pixels. That is the space before applying
144/// a display device specific scale factor.
145#[repr(C)]
146#[derive(Debug, Default, Copy, Clone, PartialEq)]
147#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
148pub struct LogicalSize {
149    /// The width in logical pixels.
150    pub width: f32,
151    /// The height in logical.
152    pub height: f32,
153}
154
155impl LogicalSize {
156    /// Construct a new logical size from the given width and height values, that are assumed to be
157    /// in the logical coordinate space.
158    pub const fn new(width: f32, height: f32) -> Self {
159        Self { width, height }
160    }
161
162    /// Convert a given physical size to a logical size by dividing width and height by the
163    /// specified scale factor.
164    pub fn from_physical(physical_size: PhysicalSize, scale_factor: f32) -> Self {
165        Self::new(
166            physical_size.width as f32 / scale_factor,
167            physical_size.height as f32 / scale_factor,
168        )
169    }
170
171    /// Convert this logical size to a physical size by multiplying width and height with the
172    /// specified scale factor.
173    pub fn to_physical(&self, scale_factor: f32) -> PhysicalSize {
174        PhysicalSize::from_logical(*self, scale_factor)
175    }
176
177    pub(crate) fn to_euclid(self) -> crate::lengths::LogicalSize {
178        [self.width as _, self.height as _].into()
179    }
180
181    pub(crate) fn from_euclid(p: crate::lengths::LogicalSize) -> Self {
182        Self::new(p.width as _, p.height as _)
183    }
184}
185
186/// A size represented in the coordinate space of physical device pixels. That is the space after applying
187/// a display device specific scale factor to pixels from the logical coordinate space.
188#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)]
189#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
190pub struct PhysicalSize {
191    /// The width in physical pixels.
192    pub width: u32,
193    /// The height in physical pixels;
194    pub height: u32,
195}
196
197impl PhysicalSize {
198    /// Construct a new physical size from the width and height values, that are assumed to be
199    /// in the physical coordinate space.
200    pub const fn new(width: u32, height: u32) -> Self {
201        Self { width, height }
202    }
203
204    /// Convert a given logical size to a physical size by multiplying width and height with the
205    /// specified scale factor.
206    pub fn from_logical(logical_size: LogicalSize, scale_factor: f32) -> Self {
207        Self::new(
208            (logical_size.width * scale_factor) as u32,
209            (logical_size.height * scale_factor) as u32,
210        )
211    }
212
213    /// Convert this physical size to a logical size by dividing width and height by the
214    /// specified scale factor.
215    pub fn to_logical(&self, scale_factor: f32) -> LogicalSize {
216        LogicalSize::from_physical(*self, scale_factor)
217    }
218
219    #[cfg(feature = "ffi")]
220    pub(crate) fn to_euclid(self) -> crate::graphics::euclid::default::Size2D<u32> {
221        [self.width, self.height].into()
222    }
223}
224
225/// The size of a window represented in either physical or logical pixels. This is used
226/// with [`Window::set_size`].
227#[derive(Clone, Debug, derive_more::From, PartialEq)]
228pub enum WindowSize {
229    /// The size in physical pixels.
230    Physical(PhysicalSize),
231    /// The size in logical screen pixels.
232    Logical(LogicalSize),
233}
234
235impl WindowSize {
236    /// Turn the `WindowSize` into a `PhysicalSize`.
237    pub fn to_physical(&self, scale_factor: f32) -> PhysicalSize {
238        match self {
239            WindowSize::Physical(size) => *size,
240            WindowSize::Logical(size) => size.to_physical(scale_factor),
241        }
242    }
243
244    /// Turn the `WindowSize` into a `LogicalSize`.
245    pub fn to_logical(&self, scale_factor: f32) -> LogicalSize {
246        match self {
247            WindowSize::Physical(size) => size.to_logical(scale_factor),
248            WindowSize::Logical(size) => *size,
249        }
250    }
251}
252
253#[test]
254fn logical_physical_pos() {
255    use crate::graphics::euclid::approxeq::ApproxEq;
256
257    let phys = PhysicalPosition::new(100, 50);
258    let logical = phys.to_logical(2.);
259    assert!(logical.x.approx_eq(&50.));
260    assert!(logical.y.approx_eq(&25.));
261
262    assert_eq!(logical.to_physical(2.), phys);
263}
264
265#[test]
266fn logical_physical_size() {
267    use crate::graphics::euclid::approxeq::ApproxEq;
268
269    let phys = PhysicalSize::new(100, 50);
270    let logical = phys.to_logical(2.);
271    assert!(logical.width.approx_eq(&50.));
272    assert!(logical.height.approx_eq(&25.));
273
274    assert_eq!(logical.to_physical(2.), phys);
275}
276
277#[i_slint_core_macros::slint_doc]
278/// This enum describes a low-level access to specific graphics APIs used
279/// by the renderer.
280#[derive(Clone)]
281#[non_exhaustive]
282pub enum GraphicsAPI<'a> {
283    /// The rendering is done using OpenGL.
284    NativeOpenGL {
285        /// Use this function pointer to obtain access to the OpenGL implementation - similar to `eglGetProcAddress`.
286        get_proc_address: &'a dyn Fn(&core::ffi::CStr) -> *const core::ffi::c_void,
287    },
288    /// The rendering is done on a HTML Canvas element using WebGL.
289    WebGL {
290        /// The DOM element id of the HTML Canvas element used for rendering.
291        canvas_element_id: &'a str,
292        /// The drawing context type used on the HTML Canvas element for rendering. This is the argument to the
293        /// `getContext` function on the HTML Canvas element.
294        context_type: &'a str,
295    },
296    /// The rendering is based on WGPU 29.x. Use the provided fields to submit commits to the provided
297    /// WGPU command queue.
298    ///
299    /// *Note*: This function is behind the [`unstable-wgpu-28` feature flag](slint:rust:slint/docs/cargo_features/#backends)
300    ///         and may be removed or changed in future minor releases, as new major WGPU releases become available.
301    ///
302    /// See also the [`slint::wgpu_28`](slint:rust:slint/wgpu_28) module.
303    #[cfg(feature = "unstable-wgpu-28")]
304    #[non_exhaustive]
305    WGPU28 {
306        /// The WGPU instance used for rendering.
307        instance: wgpu_28::Instance,
308        /// The WGPU device used for rendering.
309        device: wgpu_28::Device,
310        /// The WGPU queue for used for command submission.
311        queue: wgpu_28::Queue,
312    },
313    /// WGPU command queue.
314    ///
315    /// *Note*: This function is behind the [`unstable-wgpu-29` feature flag](slint:rust:slint/docs/cargo_features/#backends)
316    ///         and may be removed or changed in future minor releases, as new major WGPU releases become available.
317    ///
318    /// See also the [`slint::wgpu_29`](slint:rust:slint/wgpu_29) module.
319    #[cfg(feature = "unstable-wgpu-29")]
320    #[non_exhaustive]
321    WGPU29 {
322        /// The WGPU instance used for rendering.
323        instance: wgpu_29::Instance,
324        /// The WGPU device used for rendering.
325        device: wgpu_29::Device,
326        /// The WGPU queue for used for command submission.
327        queue: wgpu_29::Queue,
328    },
329}
330
331impl core::fmt::Debug for GraphicsAPI<'_> {
332    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
333        match self {
334            GraphicsAPI::NativeOpenGL { .. } => write!(f, "GraphicsAPI::NativeOpenGL"),
335            GraphicsAPI::WebGL { context_type, .. } => {
336                write!(f, "GraphicsAPI::WebGL(context_type = {context_type})")
337            }
338            #[cfg(feature = "unstable-wgpu-28")]
339            GraphicsAPI::WGPU28 { .. } => write!(f, "GraphicsAPI::WGPU28"),
340            #[cfg(feature = "unstable-wgpu-29")]
341            GraphicsAPI::WGPU29 { .. } => write!(f, "GraphicsAPI::WGPU29"),
342        }
343    }
344}
345
346/// This enum describes the different rendering states, that will be provided
347/// to the parameter of the callback for `set_rendering_notifier` on the `slint::Window`.
348///
349/// When OpenGL is used for rendering, the context will be current.
350/// It's safe to call OpenGL functions, but it is crucial that the state of the context is
351/// preserved. So make sure to save and restore state such as `TEXTURE_BINDING_2D` or
352/// `ARRAY_BUFFER_BINDING` perfectly.
353#[derive(Debug, Clone)]
354#[repr(u8)]
355#[non_exhaustive]
356pub enum RenderingState {
357    /// The window has been created and the graphics adapter/context initialized.
358    RenderingSetup,
359    /// The scene of items is about to be rendered.
360    BeforeRendering,
361    /// The scene of items was rendered, but the back buffer was not sent for display presentation
362    /// yet (for example GL swap buffers).
363    AfterRendering,
364    /// The window will be destroyed and/or graphics resources need to be released due to other
365    /// constraints.
366    RenderingTeardown,
367}
368
369/// Internal trait that's used to map rendering state callbacks to either a Rust-API provided
370/// impl FnMut or a struct that invokes a C callback and implements Drop to release the closure
371/// on the C++ side.
372#[doc(hidden)]
373pub trait RenderingNotifier {
374    /// Called to notify that rendering has reached a certain state.
375    fn notify(&mut self, state: RenderingState, graphics_api: &GraphicsAPI);
376}
377
378impl<F: FnMut(RenderingState, &GraphicsAPI)> RenderingNotifier for F {
379    fn notify(&mut self, state: RenderingState, graphics_api: &GraphicsAPI) {
380        self(state, graphics_api)
381    }
382}
383
384/// This enum describes the different error scenarios that may occur when the application
385/// registers a rendering notifier on a `slint::Window`.
386#[derive(Debug, Clone)]
387#[repr(u8)]
388#[non_exhaustive]
389pub enum SetRenderingNotifierError {
390    /// The rendering backend does not support rendering notifiers.
391    Unsupported,
392    /// There is already a rendering notifier set, multiple notifiers are not supported.
393    AlreadySet,
394}
395
396impl core::fmt::Display for SetRenderingNotifierError {
397    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
398        match self {
399            Self::Unsupported => {
400                f.write_str("The rendering backend does not support rendering notifiers.")
401            }
402            Self::AlreadySet => f.write_str(
403                "There is already a rendering notifier set, multiple notifiers are not supported.",
404            ),
405        }
406    }
407}
408
409#[cfg(feature = "std")]
410impl std::error::Error for SetRenderingNotifierError {}
411
412#[cfg(feature = "raw-window-handle-06")]
413#[derive(Clone)]
414enum WindowHandleInner {
415    HandleByAdapter(alloc::rc::Rc<dyn WindowAdapter>),
416    #[cfg(feature = "std")]
417    HandleByRcRWH {
418        window_handle_provider: std::sync::Arc<dyn raw_window_handle_06::HasWindowHandle>,
419        display_handle_provider: std::sync::Arc<dyn raw_window_handle_06::HasDisplayHandle>,
420    },
421}
422
423/// This struct represents a persistent handle to a window and implements the
424/// [`raw_window_handle_06::HasWindowHandle`] and [`raw_window_handle_06::HasDisplayHandle`]
425/// traits for accessing exposing raw window and display handles.
426/// Obtain an instance of this by calling [`Window::window_handle()`].
427#[cfg(feature = "raw-window-handle-06")]
428#[derive(Clone)]
429pub struct WindowHandle {
430    inner: WindowHandleInner,
431}
432
433#[cfg(feature = "raw-window-handle-06")]
434impl raw_window_handle_06::HasWindowHandle for WindowHandle {
435    fn window_handle(
436        &self,
437    ) -> Result<raw_window_handle_06::WindowHandle<'_>, raw_window_handle_06::HandleError> {
438        match &self.inner {
439            WindowHandleInner::HandleByAdapter(adapter) => adapter.window_handle_06(),
440            #[cfg(feature = "std")]
441            WindowHandleInner::HandleByRcRWH { window_handle_provider, .. } => {
442                window_handle_provider.window_handle()
443            }
444        }
445    }
446}
447
448#[cfg(feature = "raw-window-handle-06")]
449impl raw_window_handle_06::HasDisplayHandle for WindowHandle {
450    fn display_handle(
451        &self,
452    ) -> Result<raw_window_handle_06::DisplayHandle<'_>, raw_window_handle_06::HandleError> {
453        match &self.inner {
454            WindowHandleInner::HandleByAdapter(adapter) => adapter.display_handle_06(),
455            #[cfg(feature = "std")]
456            WindowHandleInner::HandleByRcRWH { display_handle_provider, .. } => {
457                display_handle_provider.display_handle()
458            }
459        }
460    }
461}
462
463/// This type represents a window towards the windowing system, that's used to render the
464/// scene of a component. It provides API to control windowing system specific aspects such
465/// as the position on the screen.
466#[repr(transparent)]
467pub struct Window(pub(crate) WindowInner);
468
469/// This enum describes whether a Window is allowed to be hidden when the user tries to close the window.
470/// It is the return type of the callback provided to [Window::on_close_requested].
471#[derive(Copy, Clone, Debug, PartialEq, Default)]
472#[repr(u8)]
473pub enum CloseRequestResponse {
474    /// The Window will be hidden (default action)
475    #[default]
476    HideWindow = 0,
477    /// The close request is rejected and the window will be kept shown.
478    KeepWindowShown = 1,
479}
480
481impl Window {
482    /// Create a new window from a window adapter
483    ///
484    /// You only need to create the window yourself when you create a [`WindowAdapter`] from
485    /// [`Platform::create_window_adapter`](crate::platform::Platform::create_window_adapter)
486    ///
487    /// Since the window adapter must own the Window, this function is meant to be used with
488    /// [`Rc::new_cyclic`](alloc::rc::Rc::new_cyclic)
489    ///
490    /// # Example
491    /// ```rust
492    /// use std::rc::Rc;
493    /// use slint::platform::{WindowAdapter, Renderer};
494    /// use slint::{Window, PhysicalSize};
495    /// struct MyWindowAdapter {
496    ///     window: Window,
497    ///     //...
498    /// }
499    /// impl WindowAdapter for MyWindowAdapter {
500    ///    fn window(&self) -> &Window { &self.window }
501    ///    fn size(&self) -> PhysicalSize { unimplemented!() }
502    ///    fn renderer(&self) -> &dyn Renderer { unimplemented!() }
503    /// }
504    ///
505    /// fn create_window_adapter() -> Rc<dyn WindowAdapter> {
506    ///    Rc::<MyWindowAdapter>::new_cyclic(|weak| {
507    ///        MyWindowAdapter {
508    ///           window: Window::new(weak.clone()),
509    ///           //...
510    ///        }
511    ///    })
512    /// }
513    /// ```
514    pub fn new(window_adapter_weak: alloc::rc::Weak<dyn WindowAdapter>) -> Self {
515        Self(WindowInner::new(window_adapter_weak))
516    }
517
518    /// Shows the window on the screen. An additional strong reference on the
519    /// associated component is maintained while the window is visible.
520    ///
521    /// Call [`Self::hide()`] to make the window invisible again, and drop the additional
522    /// strong reference.
523    pub fn show(&self) -> Result<(), PlatformError> {
524        self.0.show()
525    }
526
527    /// Hides the window, so that it is not visible anymore. The additional strong
528    /// reference on the associated component, that was created when [`Self::show()`] was called, is
529    /// dropped.
530    pub fn hide(&self) -> Result<(), PlatformError> {
531        self.0.hide()
532    }
533
534    /// This function allows registering a callback that's invoked during the different phases of
535    /// rendering. This allows custom rendering on top or below of the scene.
536    pub fn set_rendering_notifier(
537        &self,
538        callback: impl FnMut(RenderingState, &GraphicsAPI) + 'static,
539    ) -> Result<(), SetRenderingNotifierError> {
540        self.0.window_adapter().renderer().set_rendering_notifier(Box::new(callback))
541    }
542
543    /// This function allows registering a callback that's invoked when the user tries to close a window.
544    /// The callback has to return a [CloseRequestResponse].
545    pub fn on_close_requested(&self, callback: impl FnMut() -> CloseRequestResponse + 'static) {
546        self.0.on_close_requested(callback);
547    }
548
549    /// This function issues a request to the windowing system to redraw the contents of the window.
550    pub fn request_redraw(&self) {
551        self.0.window_adapter().request_redraw()
552    }
553
554    /// This function returns the scale factor that allows converting between logical and
555    /// physical pixels.
556    pub fn scale_factor(&self) -> f32 {
557        self.0.scale_factor()
558    }
559
560    /// Returns the position of the window on the screen, in physical screen coordinates and including
561    /// a window frame (if present).
562    pub fn position(&self) -> PhysicalPosition {
563        self.0.window_adapter().position().unwrap_or_default()
564    }
565
566    /// Sets the position of the window on the screen, in physical screen coordinates and including
567    /// a window frame (if present).
568    /// Note that on some windowing systems, such as Wayland, this functionality is not available.
569    pub fn set_position(&self, position: impl Into<WindowPosition>) {
570        let position = position.into();
571        self.0.window_adapter().set_position(position)
572    }
573
574    /// Returns the size of the window on the screen, in physical screen coordinates and excluding
575    /// a window frame (if present).
576    pub fn size(&self) -> PhysicalSize {
577        self.0.window_adapter().size()
578    }
579
580    /// Resizes the window to the specified size on the screen, in physical pixels and excluding
581    /// a window frame (if present).
582    pub fn set_size(&self, size: impl Into<WindowSize>) {
583        let size = size.into();
584        crate::window::WindowAdapter::set_size(&*self.0.window_adapter(), size);
585    }
586
587    /// Returns if the window is currently fullscreen
588    pub fn is_fullscreen(&self) -> bool {
589        self.0.is_fullscreen()
590    }
591
592    /// Set or unset the window to display fullscreen.
593    pub fn set_fullscreen(&self, fullscreen: bool) {
594        self.0.set_fullscreen(fullscreen);
595    }
596
597    /// Returns if the window is currently maximized
598    pub fn is_maximized(&self) -> bool {
599        self.0.is_maximized()
600    }
601
602    /// Maximize or unmaximize the window.
603    pub fn set_maximized(&self, maximized: bool) {
604        self.0.set_maximized(maximized);
605    }
606
607    /// Returns if the window is currently minimized
608    pub fn is_minimized(&self) -> bool {
609        self.0.is_minimized()
610    }
611
612    /// Minimize or unminimize the window.
613    pub fn set_minimized(&self, minimized: bool) {
614        self.0.set_minimized(minimized);
615    }
616
617    /// The area of the window covered by the software keyboard is changing (animated).
618    #[doc(hidden)]
619    pub fn set_virtual_keyboard(
620        &self,
621        origin: LogicalPosition,
622        size: LogicalSize,
623        _: crate::InternalToken,
624    ) {
625        self.0.set_window_item_virtual_keyboard(origin.to_euclid(), size.to_euclid());
626    }
627
628    #[doc(hidden)]
629    pub fn virtual_keyboard(
630        &self,
631        _: crate::InternalToken,
632    ) -> Option<(LogicalPosition, LogicalSize)> {
633        self.0.window_item_virtual_keyboard().map(|(origin, size)| {
634            (LogicalPosition::from_euclid(origin), LogicalSize::from_euclid(size))
635        })
636    }
637
638    /// Dispatch a window event to the scene.
639    ///
640    /// Use this when you're implementing your own backend and want to forward user input events.
641    ///
642    /// Any position fields in the event must be in the logical pixel coordinate system relative to
643    /// the top left corner of the window.
644    ///
645    /// This function panics if there is an error processing the event.
646    /// Use [`Self::try_dispatch_event()`] to handle the error.
647    #[track_caller]
648    pub fn dispatch_event(&self, event: crate::platform::WindowEvent) {
649        self.try_dispatch_event(event).unwrap()
650    }
651
652    /// Dispatch a window event to the scene.
653    ///
654    /// Use this when you're implementing your own backend and want to forward user input events.
655    ///
656    /// Any position fields in the event must be in the logical pixel coordinate system relative to
657    /// the top left corner of the window.
658    pub fn try_dispatch_event(
659        &self,
660        event: crate::platform::WindowEvent,
661    ) -> Result<(), PlatformError> {
662        // Only clone the event when a hook is installed to avoid allocation on the hot path.
663        let event_for_hook = self
664            .0
665            .try_context()
666            .and_then(|ctx| ctx.0.window_event_hook.borrow().is_some().then(|| event.clone()));
667        let dispatch_result = match event {
668            crate::platform::WindowEvent::PointerPressed { position, button } => self
669                .0
670                .process_mouse_input(MouseEvent::Pressed {
671                    position: position.to_euclid().cast(),
672                    button,
673                    click_count: 0,
674                    touch_finger_id: 0,
675                })
676                .into(),
677            crate::platform::WindowEvent::PointerReleased { position, button } => self
678                .0
679                .process_mouse_input(MouseEvent::Released {
680                    position: position.to_euclid().cast(),
681                    button,
682                    click_count: 0,
683                    touch_finger_id: 0,
684                })
685                .into(),
686            crate::platform::WindowEvent::PointerMoved { position } => self
687                .0
688                .process_mouse_input(MouseEvent::Moved {
689                    position: position.to_euclid().cast(),
690                    touch_finger_id: 0,
691                })
692                .into(),
693            crate::platform::WindowEvent::PointerScrolled { position, delta_x, delta_y } => self
694                .0
695                .process_mouse_input(MouseEvent::Wheel {
696                    position: position.to_euclid().cast(),
697                    delta_x: delta_x as _,
698                    delta_y: delta_y as _,
699                    phase: TouchPhase::Cancelled,
700                })
701                .into(),
702            crate::platform::WindowEvent::PointerExited => {
703                // Teardown event — the runtime always acts on it (clears hover/grab state
704                // and dispatches Exit to the item stack), so report Accepted unconditionally
705                // rather than asking the hit-test whether anything consumed it.
706                self.0.process_mouse_input(MouseEvent::Exit);
707                WindowEventDispatchResult::Accepted
708            }
709
710            crate::platform::WindowEvent::KeyPressed { text } => self
711                .0
712                .process_key_input(InternalKeyEvent {
713                    event_type: KeyEventType::KeyPressed,
714                    key_event: crate::input::KeyEvent { text, ..Default::default() },
715                    ..Default::default()
716                })
717                .into(),
718            crate::platform::WindowEvent::KeyPressRepeated { text } => self
719                .0
720                .process_key_input(InternalKeyEvent {
721                    event_type: KeyEventType::KeyPressed,
722                    key_event: crate::input::KeyEvent { text, repeat: true, ..Default::default() },
723                    ..Default::default()
724                })
725                .into(),
726            crate::platform::WindowEvent::KeyReleased { text } => self
727                .0
728                .process_key_input(InternalKeyEvent {
729                    event_type: KeyEventType::KeyReleased,
730                    key_event: crate::input::KeyEvent { text, ..Default::default() },
731                    ..Default::default()
732                })
733                .into(),
734            crate::platform::WindowEvent::ScaleFactorChanged { scale_factor } => {
735                self.0.set_scale_factor(scale_factor);
736                WindowEventDispatchResult::Accepted
737            }
738            crate::platform::WindowEvent::Resized { size } => {
739                self.0.set_window_item_geometry(size.to_euclid());
740                self.0.window_adapter().renderer().resize(size.to_physical(self.scale_factor()))?;
741                if let Some(item_rc) = self.0.focus_item.borrow().upgrade() {
742                    item_rc.try_scroll_into_visible();
743                }
744                WindowEventDispatchResult::Accepted
745            }
746            crate::platform::WindowEvent::CloseRequested => {
747                if self.0.request_close() {
748                    self.hide()?;
749                    WindowEventDispatchResult::Accepted
750                } else {
751                    WindowEventDispatchResult::Rejected
752                }
753            }
754            crate::platform::WindowEvent::WindowActiveChanged(bool) => {
755                self.0.set_active(bool);
756                WindowEventDispatchResult::Accepted
757            }
758        };
759        if let Some(event_for_hook) = event_for_hook
760            && let Some(ctx) = self.0.try_context()
761            && let Some(hook) = ctx.0.window_event_hook.borrow().as_ref()
762        {
763            hook(&self.0.window_adapter(), &event_for_hook, dispatch_result);
764        }
765        Ok(())
766    }
767
768    /// Returns true if there is an animation currently active on any property in the Window; false otherwise.
769    pub fn has_active_animations(&self) -> bool {
770        // TODO make it really per window.
771        crate::animations::CURRENT_ANIMATION_DRIVER.with(|driver| driver.has_active_animations())
772    }
773
774    /// Returns the visibility state of the window. This function can return false even if you previously called show()
775    /// on it, for example if the user minimized the window.
776    pub fn is_visible(&self) -> bool {
777        self.0.is_visible()
778    }
779
780    /// Returns a struct that implements the raw window handle traits to access the windowing system specific window
781    /// and display handles.
782    ///
783    /// Note that the window handle may only become available after the window has been created by the window manager,
784    /// which typically occurs after at least one iteration of the event loop following a call to `show()`.
785    ///
786    /// Support for this function depends on the platform backend.
787    ///
788    /// This function is only accessible if you enable the `raw-window-handle-06` crate feature.
789    #[cfg(feature = "raw-window-handle-06")]
790    pub fn window_handle(&self) -> WindowHandle {
791        let adapter = self.0.window_adapter();
792        #[cfg(feature = "std")]
793        if let Some((window_handle_provider, display_handle_provider)) =
794            adapter.internal(crate::InternalToken).and_then(|internal| {
795                internal.window_handle_06_rc().ok().zip(internal.display_handle_06_rc().ok())
796            })
797        {
798            return WindowHandle {
799                inner: WindowHandleInner::HandleByRcRWH {
800                    window_handle_provider,
801                    display_handle_provider,
802                },
803            };
804        }
805
806        WindowHandle { inner: WindowHandleInner::HandleByAdapter(adapter) }
807    }
808
809    /// Takes a snapshot of the window contents and returns it as RGBA8 encoded pixel buffer.
810    ///
811    /// Note that this function may be slow to call as it may need to re-render the scene.
812    pub fn take_snapshot(&self) -> Result<SharedPixelBuffer<Rgba8Pixel>, PlatformError> {
813        self.0.window_adapter().renderer().take_snapshot()
814    }
815}
816
817#[i_slint_core_macros::slint_doc]
818/// This trait is used to obtain references to global singletons exported in `.slint`
819/// markup. Alternatively, you can use [`ComponentHandle::global`] to obtain access.
820///
821/// This trait is implemented by the compiler for each global singleton that's exported.
822///
823/// # Example
824/// The following example of `.slint` markup defines a global singleton called `Palette`, exports
825/// it and modifies it from Rust code:
826/// ```rust
827/// # i_slint_backend_testing::init_no_event_loop();
828/// slint::slint!{
829/// export global Palette {
830///     in property<color> foreground-color;
831///     in property<color> background-color;
832/// }
833///
834/// export component App inherits Window {
835///    background: Palette.background-color;
836///    Text {
837///       text: "Hello";
838///       color: Palette.foreground-color;
839///    }
840///    // ...
841/// }
842/// }
843/// let app = App::new().unwrap();
844/// app.global::<Palette>().set_background_color(slint::Color::from_rgb_u8(0, 0, 0));
845///
846/// // alternate way to access the global singleton:
847/// Palette::get(&app).set_foreground_color(slint::Color::from_rgb_u8(255, 255, 255));
848/// ```
849///
850/// See also the [language documentation for global singletons](slint:globals) for more information.
851///
852/// **Note:** Only globals that are exported or re-exported from the main .slint file will
853/// be exposed in the API
854///
855/// # Storing References to Globals
856///
857/// Globals are strong references to the window they are attached to, unless stored in a `Weak`
858/// reference (see the [`StrongHandle`] trait).
859/// This means that if you store a reference to a global, it will keep the entire window alive
860/// and prevent it from being dropped.
861///
862/// To make this less error-prone, when accessing a global from a window, it is initially bound to
863/// the lifetime of the Window it belongs to.
864/// This prevents you from accidentally capturing the global in a callback closure, which
865/// would result in the window never being dropped.
866///
867/// To store references to a global in a callback or Rust struct, you can convert it into
868/// a weak reference using the [`Global::as_weak`] function.
869/// This will also extend the lifetime of the global to `'static`.
870///
871/// Once the window is dropped, upgrading the weak reference will return `None`.
872///
873/// ## Example
874///
875/// ```rust
876/// # i_slint_backend_testing::init_no_event_loop();
877/// slint::slint!{
878/// export global Palette {
879///     in property<color> foreground-color;
880///     in property<color> background-color;
881/// }
882///
883/// export component App inherits Window {
884///    background: Palette.background-color;
885///    // ...
886/// }
887/// }
888///
889/// struct PaletteBackend {
890///     global: slint::Weak<Palette<'static>>,
891/// }
892///
893/// impl PaletteBackend {
894///     fn global(&self) -> Palette<'static> {
895///         self.global.upgrade().expect("The window was dropped, the global is no longer available")
896///     }
897/// }
898///
899/// let app = App::new().unwrap();
900///
901/// let palette_backend = PaletteBackend { global: app.global::<Palette>().as_weak() };
902/// ```
903pub trait Global<'a, Component> {
904    /// The `Self` type, with a `'static` lifetime.
905    type StaticSelf: 'static + StrongHandle;
906
907    /// Returns a reference to the global.
908    fn get(component: &'a Component) -> Self;
909
910    /// Convert this Global reference into a weak reference.
911    ///
912    /// This will also extend the lifetime of this global to `'static`, to allow storing
913    /// the Weak reference in a struct that does not have a lifetime itself.
914    fn as_weak(&self) -> Weak<Self::StaticSelf>;
915}
916
917/// This trait marks types that hold a strong reference to a Slint component.
918///
919/// The Slint compiler automatically implements this trait for [generated components](index.html#generated-components) and the `'static` variant of [generated Globals](index.html#exported-global-singletons).
920/// Do not try to implement it manually.
921///
922/// All types that implement this trait can be used in a [`Weak`] reference.
923///
924/// > ⚠️ Strong references should not be captured by a lambda given to a callback,
925/// > as this would produce a reference loop and leak the component.
926/// > Instead, the callback function should capture a [`Weak`] reference.
927///
928/// **Example:**
929/// ```
930/// # i_slint_backend_testing::init_no_event_loop();
931/// slint::slint!{
932///     export component App inherits Window {
933///         in-out property <int> counter: 0;
934///         callback do_something;
935///     }
936/// }
937///
938/// let app = App::new().unwrap();
939/// // ⚠️ Incorrect: This will capture a strong reference to the app in the closure,
940/// // which will never be released and leak the app!
941/// app.on_do_something({
942///     let app = app.clone_strong();
943///     move || {
944///         app.set_counter(app.get_counter() + 1);
945///     }
946/// });
947///
948/// // Correct: Use a weak reference to the app, which will be released
949/// // when the app is dropped.
950/// app.on_do_something({
951///     let app = app.as_weak();
952///     move || {
953///         let Some(app) = app.upgrade() else {
954///             return;
955///         };
956///         app.set_counter(app.get_counter() + 1);
957///     }
958/// });
959/// ```
960///
961/// # Common issues
962///
963/// To use a global with a [`Weak`] reference, you need to use the `'static` variant of the Global.
964///
965/// **Example:**
966/// ```
967/// # i_slint_backend_testing::init_no_event_loop();
968/// slint::slint!{
969///    export global MyGlobal {}
970///
971///    export component App inherits Window {}
972/// }
973/// struct MyStruct {
974///    // Use the 'static variant of MyGlobal, which implements
975///    // StrongHandle and can be used in a Weak reference.
976///    global: slint::Weak<MyGlobal<'static>>,
977/// }
978///
979/// let app = App::new().unwrap();
980/// let my_global: MyGlobal = app.global();
981///
982/// let my_struct = MyStruct {
983///     // Calling as_weak() on the global automatically converts it to 'static
984///     global: my_global.as_weak()
985/// };
986/// ```
987///
988/// Otherwise you may encounter issues like this:
989///
990/// ```text
991/// error[E0106]: missing lifetime specifier
992///   --> /path/to/file.rs:10:19
993///    |
994/// 10 |         global: Weak<MyGlobal>,
995///    |                      ^^^^^^^^ expected named lifetime parameter
996///    |
997/// help: consider introducing a named lifetime parameter
998///    |
999///  9 ~     struct MyStruct<'a> {
1000/// 10 ~         global: Weak<MyGlobal<'a>>,
1001/// ```
1002///
1003/// The compiler suggests to introduce a lifetime parameter for the struct,
1004/// This is not correct - use a `'static` lifetime instead!
1005///
1006/// Otherwise you will run into the following error:
1007///
1008/// ```text
1009/// error: incompatible lifetime on type
1010///   --> /path/to/file.rs:9:10
1011///    |
1012///  9 |     global: slint::Weak<MyGlobal<'a>>,
1013///    |             ^^^^^^^^^^^^^^^^^^^^^^^^^
1014///    |
1015///note: because this has an unmet lifetime requirement
1016///   --> slint/internal/core/api.rs:954:24
1017///    |
1018///954 |     pub struct Weak<T: StrongHandle> {
1019///    |                        ^^^^^^^^^^^^ introduces a `'static` lifetime requirement
1020///note: the lifetime `'a` as defined here...
1021///   --> /path/to/file.rs:8:17
1022///    |
1023///  8 | struct MyStruct<'a> {
1024///    |                 ^^
1025///note: ...does not necessarily outlive the static lifetime introduced by the compatible `impl`
1026///   --> /path/to/file.rs:246:6
1027///    |
1028///246 |      impl slint :: StrongHandle for r#MyGlobal < 'static > {
1029/// ```
1030pub trait StrongHandle {
1031    /// The internal Inner type for `Weak<Self>::inner`.
1032    #[doc(hidden)]
1033    type WeakInner: Clone + Default;
1034
1035    /// Internal function used when upgrading a weak reference to a strong one.
1036    #[doc(hidden)]
1037    fn upgrade_from_weak_inner(_: &Self::WeakInner) -> Option<Self>
1038    where
1039        Self: Sized;
1040}
1041
1042/// This trait describes the common public API of a strongly referenced Slint component.
1043/// It allows creating strongly-referenced clones, a conversion into a weak pointer as well
1044/// as other convenience functions.
1045///
1046/// This trait is implemented by the [generated component](index.html#generated-components)
1047pub trait ComponentHandle: StrongHandle {
1048    /// Returns a new weak pointer.
1049    // Note: It would be great if we could move this function into the StrongHandle trait. But
1050    // that would be a backwards-incompatible change.
1051    fn as_weak(&self) -> Weak<Self>
1052    where
1053        Self: Sized;
1054
1055    /// Returns a clone of this handle that's a strong reference.
1056    #[must_use]
1057    fn clone_strong(&self) -> Self;
1058
1059    /// Convenience function for [`crate::Window::show()`](struct.Window.html#method.show).
1060    /// This shows the window on the screen and maintains an extra strong reference while
1061    /// the window is visible. To react to events from the windowing system, such as draw
1062    /// requests or mouse/touch input, it is still necessary to spin the event loop,
1063    /// using [`crate::run_event_loop`](fn.run_event_loop.html).
1064    fn show(&self) -> Result<(), PlatformError>;
1065
1066    /// Convenience function for [`crate::Window::hide()`](struct.Window.html#method.hide).
1067    /// Hides the window, so that it is not visible anymore. The additional strong reference
1068    /// on the associated component, that was created when show() was called, is dropped.
1069    fn hide(&self) -> Result<(), PlatformError>;
1070
1071    /// Returns the Window associated with this component. The window API can be used
1072    /// to control different aspects of the integration into the windowing system,
1073    /// such as the position on the screen.
1074    fn window(&self) -> &Window;
1075
1076    /// This is a convenience function that first calls [`Self::show`], followed by [`crate::run_event_loop()`](fn.run_event_loop.html)
1077    /// and [`Self::hide`].
1078    fn run(&self) -> Result<(), PlatformError>;
1079
1080    /// This function provides access to instances of global singletons exported in `.slint`.
1081    /// See [`Global`] for an example how to export and access globals from `.slint` markup.
1082    fn global<'a, T: Global<'a, Self>>(&'a self) -> T
1083    where
1084        Self: Sized;
1085}
1086
1087mod weak_handle {
1088
1089    use super::*;
1090
1091    /// Struct that's used to hold weak references of a [Slint component or global](index.html#generated-components)
1092    ///
1093    /// In order to create a Weak, you should use [`ComponentHandle::as_weak`] or
1094    /// [`Global::as_weak`].
1095    ///
1096    /// Strong references should not be captured by the functions given to a lambda,
1097    /// as this would produce a reference loop and leak the component.
1098    /// Instead, the callback function should capture a weak component.
1099    ///
1100    /// The Weak component also implement `Send` and can be send to another thread.
1101    /// but the upgrade function will only return a valid component from the same thread
1102    /// as the one it has been created from.
1103    /// This is useful to use with [`invoke_from_event_loop()`] or [`Self::upgrade_in_event_loop()`].
1104    pub struct Weak<T: StrongHandle> {
1105        inner: T::WeakInner,
1106        #[cfg(feature = "std")]
1107        thread: std::thread::ThreadId,
1108    }
1109
1110    impl<T: StrongHandle> Default for Weak<T> {
1111        fn default() -> Self {
1112            Self {
1113                inner: T::WeakInner::default(),
1114                #[cfg(feature = "std")]
1115                thread: std::thread::current().id(),
1116            }
1117        }
1118    }
1119
1120    impl<T: StrongHandle> Clone for Weak<T> {
1121        fn clone(&self) -> Self {
1122            Self {
1123                inner: self.inner.clone(),
1124                #[cfg(feature = "std")]
1125                thread: self.thread,
1126            }
1127        }
1128    }
1129
1130    impl<T: StrongHandle> Weak<T> {
1131        #[doc(hidden)]
1132        pub fn new(inner: T::WeakInner) -> Self {
1133            Self {
1134                inner,
1135                #[cfg(feature = "std")]
1136                thread: std::thread::current().id(),
1137            }
1138        }
1139
1140        /// Returns a new strongly referenced component if some other instance still
1141        /// holds a strong reference. Otherwise, returns None.
1142        ///
1143        /// This also returns None if the current thread is not the thread that created
1144        /// the component
1145        pub fn upgrade(&self) -> Option<T> {
1146            #[cfg(feature = "std")]
1147            if std::thread::current().id() != self.thread {
1148                return None;
1149            }
1150            T::upgrade_from_weak_inner(&self.inner)
1151        }
1152
1153        /// Convenience function that returns a new strongly referenced component if
1154        /// some other instance still holds a strong reference and the current thread
1155        /// is the thread that created this component.
1156        /// Otherwise, this function panics.
1157        #[track_caller]
1158        pub fn unwrap(&self) -> T {
1159            #[cfg(feature = "std")]
1160            if std::thread::current().id() != self.thread {
1161                panic!(
1162                    "Trying to upgrade a Weak from a different thread than the one it belongs to"
1163                );
1164            }
1165            T::upgrade_from_weak_inner(&self.inner)
1166                .expect("The Weak doesn't hold a valid component")
1167        }
1168
1169        /// A helper function to allow creation on `component_factory::Component` from
1170        /// a `ComponentHandle`
1171        pub(crate) fn inner(&self) -> T::WeakInner {
1172            self.inner.clone()
1173        }
1174
1175        /// Convenience function that combines [`invoke_from_event_loop()`] with [`Self::upgrade()`]
1176        ///
1177        /// The given functor will be added to an internal queue and will wake the event loop.
1178        /// On the next iteration of the event loop, the functor will be executed with a `T` as an argument.
1179        ///
1180        /// If the component was dropped because there are no more strong reference to the component,
1181        /// the functor will not be called.
1182        ///
1183        /// # Example
1184        /// ```rust
1185        /// # i_slint_backend_testing::init_no_event_loop();
1186        /// slint::slint! { export component MyApp inherits Window { in property <int> foo; /* ... */ } }
1187        /// let handle = MyApp::new().unwrap();
1188        /// let handle_weak = handle.as_weak();
1189        /// let thread = std::thread::spawn(move || {
1190        ///     // ... Do some computation in the thread
1191        ///     let foo = 42;
1192        ///     # assert!(handle_weak.upgrade().is_none()); // note that upgrade fails in a thread
1193        ///     # return; // don't upgrade_in_event_loop in our examples
1194        ///     // now forward the data to the main thread using upgrade_in_event_loop
1195        ///     handle_weak.upgrade_in_event_loop(move |handle| handle.set_foo(foo));
1196        /// });
1197        /// # thread.join().unwrap(); return; // don't run the event loop in examples
1198        /// handle.run().unwrap();
1199        /// ```
1200        #[cfg(any(feature = "std", feature = "unsafe-single-threaded"))]
1201        pub fn upgrade_in_event_loop(
1202            &self,
1203            func: impl FnOnce(T) + Send + 'static,
1204        ) -> Result<(), EventLoopError>
1205        where
1206            T: 'static,
1207        {
1208            let weak_handle = self.clone();
1209            super::invoke_from_event_loop(move || {
1210                if let Some(h) = weak_handle.upgrade() {
1211                    func(h);
1212                }
1213            })
1214        }
1215    }
1216
1217    // Safety: we make sure in upgrade that the thread is the proper one,
1218    // and the VWeak only use atomic pointer so it is safe to clone and drop in another thread
1219    #[allow(unsafe_code)]
1220    #[cfg(any(feature = "std", feature = "unsafe-single-threaded"))]
1221    unsafe impl<T: StrongHandle> Send for Weak<T> {}
1222    #[allow(unsafe_code)]
1223    #[cfg(any(feature = "std", feature = "unsafe-single-threaded"))]
1224    unsafe impl<T: StrongHandle> Sync for Weak<T> {}
1225}
1226
1227pub use weak_handle::*;
1228
1229/// Adds the specified function to an internal queue, notifies the event loop to wake up.
1230/// Once woken up, any queued up functions will be invoked.
1231///
1232/// This function is thread-safe and can be called from any thread, including the one
1233/// running the event loop. The provided functions will only be invoked from the thread
1234/// that started the event loop.
1235///
1236/// You can use this to set properties or use any other Slint APIs from other threads,
1237/// by collecting the code in a functor and queuing it up for invocation within the event loop.
1238///
1239/// If you want to capture non-Send types to run in the next event loop iteration,
1240/// you can use the `slint::spawn_local` function instead.
1241///
1242/// See also [`Weak::upgrade_in_event_loop`].
1243///
1244/// # Example
1245/// ```rust
1246/// slint::slint! { export component MyApp inherits Window { in property <int> foo; /* ... */ } }
1247/// # i_slint_backend_testing::init_no_event_loop();
1248/// let handle = MyApp::new().unwrap();
1249/// let handle_weak = handle.as_weak();
1250/// # return; // don't run the event loop in examples
1251/// let thread = std::thread::spawn(move || {
1252///     // ... Do some computation in the thread
1253///     let foo = 42;
1254///      // now forward the data to the main thread using invoke_from_event_loop
1255///     let handle_copy = handle_weak.clone();
1256///     slint::invoke_from_event_loop(move || handle_copy.unwrap().set_foo(foo));
1257/// });
1258/// handle.run().unwrap();
1259/// ```
1260pub fn invoke_from_event_loop(func: impl FnOnce() + Send + 'static) -> Result<(), EventLoopError> {
1261    crate::platform::with_event_loop_proxy(|proxy| {
1262        proxy
1263            .ok_or(EventLoopError::NoEventLoopProvider)?
1264            .invoke_from_event_loop(alloc::boxed::Box::new(func))
1265    })
1266}
1267
1268/// Schedules the main event loop for termination. This function is meant
1269/// to be called from callbacks triggered by the UI. After calling the function,
1270/// it will return immediately and once control is passed back to the event loop,
1271/// the initial call to `slint::run_event_loop()` will return.
1272///
1273/// This function can be called from any thread
1274///
1275/// Any previously queued events may or may not be processed before the loop terminates.
1276/// This is platform dependent behavior.
1277pub fn quit_event_loop() -> Result<(), EventLoopError> {
1278    crate::platform::with_event_loop_proxy(|proxy| {
1279        proxy.ok_or(EventLoopError::NoEventLoopProvider)?.quit_event_loop()
1280    })
1281}
1282
1283#[derive(Debug, Clone, Eq, PartialEq)]
1284#[non_exhaustive]
1285/// Error returned from the [`invoke_from_event_loop()`] and [`quit_event_loop()`] function
1286pub enum EventLoopError {
1287    /// The event could not be sent because the event loop was terminated already
1288    EventLoopTerminated,
1289    /// The event could not be sent because the Slint platform abstraction was not yet initialized,
1290    /// or the platform does not support event loop.
1291    NoEventLoopProvider,
1292}
1293
1294impl core::fmt::Display for EventLoopError {
1295    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1296        match self {
1297            EventLoopError::EventLoopTerminated => {
1298                f.write_str("The event loop was already terminated")
1299            }
1300            EventLoopError::NoEventLoopProvider => {
1301                f.write_str("The Slint platform does not provide an event loop")
1302            }
1303        }
1304    }
1305}
1306
1307#[cfg(feature = "std")]
1308impl std::error::Error for EventLoopError {}
1309
1310/// The platform encountered a fatal error.
1311///
1312/// This error typically indicates an issue with initialization or connecting to the windowing system.
1313///
1314/// This can be constructed from a `String`:
1315/// ```rust
1316/// use slint::platform::PlatformError;
1317/// PlatformError::from(format!("Could not load resource {}", 1234));
1318/// ```
1319#[non_exhaustive]
1320pub enum PlatformError {
1321    /// No default platform was selected, or no platform could be initialized.
1322    ///
1323    /// If you encounter this error, make sure to either selected trough the `backend-*` cargo features flags,
1324    /// or call [`platform::set_platform()`](crate::platform::set_platform)
1325    /// before running the event loop
1326    NoPlatform,
1327
1328    /// The Slint Platform does not provide an event loop.
1329    ///
1330    /// The [`Platform::run_event_loop`](crate::platform::Platform::run_event_loop)
1331    /// is not implemented for the current platform.
1332    NoEventLoopProvider,
1333
1334    /// There is already a platform set from another thread.
1335    SetPlatformError(crate::platform::SetPlatformError),
1336
1337    /// The operation is not supported by the current platform.
1338    Unsupported,
1339
1340    /// Another platform-specific error occurred
1341    Other(String),
1342
1343    /// Another platform-specific error occurred.
1344    OtherError(Box<dyn core::error::Error + Send + Sync>),
1345}
1346
1347#[cfg(target_arch = "wasm32")]
1348impl From<PlatformError> for wasm_bindgen::JsValue {
1349    fn from(err: PlatformError) -> wasm_bindgen::JsValue {
1350        wasm_bindgen::JsError::from(err).into()
1351    }
1352}
1353
1354impl core::fmt::Debug for PlatformError {
1355    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1356        core::fmt::Display::fmt(self, f)
1357    }
1358}
1359
1360impl core::fmt::Display for PlatformError {
1361    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1362        match self {
1363            PlatformError::NoPlatform => f.write_str(
1364                "No default Slint platform was selected, and no Slint platform was initialized",
1365            ),
1366            PlatformError::NoEventLoopProvider => {
1367                f.write_str("The Slint platform does not provide an event loop")
1368            }
1369            PlatformError::SetPlatformError(_) => {
1370                f.write_str("The Slint platform was initialized in another thread")
1371            }
1372            PlatformError::Unsupported => {
1373                f.write_str("The operation is not supported by the current platform")
1374            }
1375            PlatformError::Other(str) => f.write_str(str),
1376            PlatformError::OtherError(error) => error.fmt(f),
1377        }
1378    }
1379}
1380
1381impl From<String> for PlatformError {
1382    fn from(value: String) -> Self {
1383        Self::Other(value)
1384    }
1385}
1386impl From<&str> for PlatformError {
1387    fn from(value: &str) -> Self {
1388        Self::Other(value.into())
1389    }
1390}
1391
1392#[cfg(feature = "std")]
1393impl From<Box<dyn std::error::Error + Send + Sync>> for PlatformError {
1394    fn from(error: Box<dyn std::error::Error + Send + Sync>) -> Self {
1395        Self::OtherError(error)
1396    }
1397}
1398
1399#[cfg(feature = "std")]
1400impl std::error::Error for PlatformError {
1401    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
1402        match self {
1403            PlatformError::OtherError(err) => Some(err.as_ref()),
1404            _ => None,
1405        }
1406    }
1407}
1408
1409#[test]
1410#[cfg(feature = "std")]
1411fn error_is_send() {
1412    let _: Box<dyn std::error::Error + Send + Sync + 'static> = PlatformError::NoPlatform.into();
1413}
1414
1415/// Sets the application id for use on Wayland or X11 with [xdg](https://specifications.freedesktop.org/desktop-entry-spec/latest/)
1416/// compliant window managers. This must be set before the window is shown, and has only an effect on Wayland or X11.
1417pub fn set_xdg_app_id(app_id: impl Into<SharedString>) -> Result<(), PlatformError> {
1418    crate::context::with_global_context(
1419        || Err(crate::platform::PlatformError::NoPlatform),
1420        |ctx| ctx.set_xdg_app_id(app_id.into()),
1421    )
1422}