Skip to main content

rio_window/
window.rs

1//! The [`Window`] struct and associated types.
2use std::fmt;
3
4/// Background blur / liquid-glass style for a window.
5///
6/// `Off` and `System` are the legacy bool states (`false` / `true`)
7/// preserved for backward compatibility. The macOS variants request
8/// the `NSGlassEffectView`-backed liquid-glass effect introduced in
9/// macOS 26 (Tahoe). Platforms that don't support a requested style
10/// degrade to `System` and emit a `tracing::warn` rather than failing.
11#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
12pub enum BlurStyle {
13    #[default]
14    Off,
15    /// Native system blur — CGS backdrop on macOS, KWin blur on
16    /// Wayland, DWM acrylic on Windows.
17    System,
18    /// macOS 26+: liquid glass with the `regular` style (some opacity).
19    MacosGlassRegular,
20    /// macOS 26+: liquid glass with the `clear` style (highly transparent).
21    MacosGlassClear,
22}
23
24impl BlurStyle {
25    /// True for any non-`Off` variant.
26    #[inline]
27    pub fn is_enabled(self) -> bool {
28        !matches!(self, BlurStyle::Off)
29    }
30
31    /// True for the macOS liquid-glass variants.
32    #[inline]
33    pub fn is_glass(self) -> bool {
34        matches!(
35            self,
36            BlurStyle::MacosGlassRegular | BlurStyle::MacosGlassClear
37        )
38    }
39}
40
41use crate::dpi::{PhysicalPosition, PhysicalSize, Position, Size};
42use crate::error::{ExternalError, NotSupportedError};
43use crate::monitor::{MonitorHandle, VideoModeHandle};
44use crate::platform_impl::{self, PlatformSpecificWindowAttributes};
45
46pub use crate::cursor::{
47    BadImage, Cursor, CustomCursor, CustomCursorSource, MAX_CURSOR_SIZE,
48};
49pub use crate::icon::{BadIcon, Icon};
50
51#[doc(inline)]
52pub use cursor_icon::{CursorIcon, ParseError as CursorIconParseError};
53
54/// Represents a window.
55///
56/// The window is closed when dropped.
57///
58/// ## Threading
59///
60/// This is `Send + Sync`, meaning that it can be freely used from other
61/// threads.
62///
63/// However, some platforms (macOS, Web and iOS) only allow user interface
64/// interactions on the main thread, so on those platforms, if you use the
65/// window from a thread other than the main, the code is scheduled to run on
66/// the main thread, and your thread may be blocked until that completes.
67///
68/// ## Platform-specific
69///
70/// **Web:** The [`Window`], which is represented by a `HTMLElementCanvas`, can
71/// not be closed by dropping the [`Window`].
72pub struct Window {
73    pub(crate) window: platform_impl::Window,
74}
75
76impl fmt::Debug for Window {
77    fn fmt(&self, fmtr: &mut fmt::Formatter<'_>) -> fmt::Result {
78        fmtr.pad("Window { .. }")
79    }
80}
81
82impl Drop for Window {
83    /// This will close the [`Window`].
84    ///
85    /// See [`Window`] for more details.
86    fn drop(&mut self) {
87        self.window.maybe_wait_on_main(|w| {
88            // If the window is in exclusive fullscreen, we must restore the desktop
89            // video mode (generally this would be done on application exit, but
90            // closing the window doesn't necessarily always mean application exit,
91            // such as when there are multiple windows)
92            if let Some(Fullscreen::Exclusive(_)) = w.fullscreen().map(|f| f.into()) {
93                w.set_fullscreen(None);
94            }
95        })
96    }
97}
98
99/// Identifier of a window. Unique for each window.
100///
101/// Can be obtained with [`window.id()`][`Window::id`].
102///
103/// Whenever you receive an event specific to a window, this event contains a `WindowId` which you
104/// can then compare to the ids of your windows.
105#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
106pub struct WindowId(pub(crate) platform_impl::WindowId);
107
108impl WindowId {
109    /// Returns a dummy id, useful for unit testing.
110    ///
111    /// # Safety
112    ///
113    /// The only guarantee made about the return value of this function is that
114    /// it will always be equal to itself and to future values returned by this function.
115    /// No other guarantees are made. This may be equal to a real [`WindowId`].
116    ///
117    /// **Passing this into a winit function will result in undefined behavior.**
118    pub const unsafe fn dummy() -> Self {
119        #[allow(unused_unsafe)]
120        WindowId(unsafe { platform_impl::WindowId::dummy() })
121    }
122}
123
124impl fmt::Debug for WindowId {
125    fn fmt(&self, fmtr: &mut fmt::Formatter<'_>) -> fmt::Result {
126        self.0.fmt(fmtr)
127    }
128}
129
130impl From<WindowId> for u64 {
131    fn from(window_id: WindowId) -> Self {
132        window_id.0.into()
133    }
134}
135
136impl From<u64> for WindowId {
137    fn from(raw_id: u64) -> Self {
138        Self(raw_id.into())
139    }
140}
141
142/// Attributes used when creating a window.
143#[derive(Debug, Clone)]
144pub struct WindowAttributes {
145    pub inner_size: Option<Size>,
146    pub min_inner_size: Option<Size>,
147    pub max_inner_size: Option<Size>,
148    pub position: Option<Position>,
149    pub resizable: bool,
150    pub enabled_buttons: WindowButtons,
151    pub title: String,
152    pub maximized: bool,
153    pub visible: bool,
154    pub transparent: bool,
155    pub blur: BlurStyle,
156    pub decorations: bool,
157    pub window_icon: Option<Icon>,
158    pub preferred_theme: Option<Theme>,
159    pub resize_increments: Option<Size>,
160    pub content_protected: bool,
161    pub window_level: WindowLevel,
162    pub active: bool,
163    pub cursor: Cursor,
164    pub(crate) parent_window: Option<SendSyncRawWindowHandle>,
165    pub fullscreen: Option<Fullscreen>,
166    // Platform-specific configuration.
167    #[allow(dead_code)]
168    pub(crate) platform_specific: PlatformSpecificWindowAttributes,
169}
170
171impl Default for WindowAttributes {
172    #[inline]
173    fn default() -> WindowAttributes {
174        WindowAttributes {
175            inner_size: None,
176            min_inner_size: None,
177            max_inner_size: None,
178            position: None,
179            resizable: true,
180            enabled_buttons: WindowButtons::all(),
181            title: "winit window".to_owned(),
182            maximized: false,
183            fullscreen: None,
184            visible: true,
185            transparent: false,
186            blur: BlurStyle::default(),
187            decorations: true,
188            window_level: Default::default(),
189            window_icon: None,
190            preferred_theme: None,
191            resize_increments: None,
192            content_protected: false,
193            cursor: Cursor::default(),
194            parent_window: None,
195            active: true,
196            platform_specific: Default::default(),
197        }
198    }
199}
200
201/// Wrapper for [`raw_window_handle::RawWindowHandle`] for [`WindowAttributes::parent_window`].
202///
203/// # Safety
204///
205/// The user has to account for that when using [`WindowAttributes::with_parent_window()`],
206/// which is `unsafe`.
207#[derive(Debug, Clone)]
208pub(crate) struct SendSyncRawWindowHandle(pub(crate) raw_window_handle::RawWindowHandle);
209
210unsafe impl Send for SendSyncRawWindowHandle {}
211unsafe impl Sync for SendSyncRawWindowHandle {}
212
213impl WindowAttributes {
214    /// Initializes new attributes with default values.
215    #[inline]
216    #[deprecated = "use `Window::default_attributes` instead"]
217    pub fn new() -> Self {
218        Default::default()
219    }
220}
221
222impl WindowAttributes {
223    /// Get the parent window stored on the attributes.
224    pub fn parent_window(&self) -> Option<&raw_window_handle::RawWindowHandle> {
225        self.parent_window.as_ref().map(|handle| &handle.0)
226    }
227
228    /// Requests the window to be of specific dimensions.
229    ///
230    /// If this is not set, some platform-specific dimensions will be used.
231    ///
232    /// See [`Window::request_inner_size`] for details.
233    #[inline]
234    pub fn with_inner_size<S: Into<Size>>(mut self, size: S) -> Self {
235        self.inner_size = Some(size.into());
236        self
237    }
238
239    /// Sets the minimum dimensions a window can have.
240    ///
241    /// If this is not set, the window will have no minimum dimensions (aside
242    /// from reserved).
243    ///
244    /// See [`Window::set_min_inner_size`] for details.
245    #[inline]
246    pub fn with_min_inner_size<S: Into<Size>>(mut self, min_size: S) -> Self {
247        self.min_inner_size = Some(min_size.into());
248        self
249    }
250
251    /// Sets the maximum dimensions a window can have.
252    ///
253    /// If this is not set, the window will have no maximum or will be set to
254    /// the primary monitor's dimensions by the platform.
255    ///
256    /// See [`Window::set_max_inner_size`] for details.
257    #[inline]
258    pub fn with_max_inner_size<S: Into<Size>>(mut self, max_size: S) -> Self {
259        self.max_inner_size = Some(max_size.into());
260        self
261    }
262
263    /// Sets a desired initial position for the window.
264    ///
265    /// If this is not set, some platform-specific position will be chosen.
266    ///
267    /// See [`Window::set_outer_position`] for details.
268    ///
269    /// ## Platform-specific
270    ///
271    /// - **macOS:** The top left corner position of the window content, the window's "inner"
272    ///   position. The window title bar will be placed above it. The window will be positioned such
273    ///   that it fits on screen, maintaining set `inner_size` if any. If you need to precisely
274    ///   position the top left corner of the whole window you have to use
275    ///   [`Window::set_outer_position`] after creating the window.
276    /// - **Windows:** The top left corner position of the window title bar, the window's "outer"
277    ///   position. There may be a small gap between this position and the window due to the
278    ///   specifics of the Window Manager.
279    /// - **X11:** The top left corner of the window, the window's "outer" position.
280    /// - **Others:** Ignored.
281    #[inline]
282    pub fn with_position<P: Into<Position>>(mut self, position: P) -> Self {
283        self.position = Some(position.into());
284        self
285    }
286
287    /// Sets whether the window is resizable or not.
288    ///
289    /// The default is `true`.
290    ///
291    /// See [`Window::set_resizable`] for details.
292    #[inline]
293    pub fn with_resizable(mut self, resizable: bool) -> Self {
294        self.resizable = resizable;
295        self
296    }
297
298    /// Sets the enabled window buttons.
299    ///
300    /// The default is [`WindowButtons::all`]
301    ///
302    /// See [`Window::set_enabled_buttons`] for details.
303    #[inline]
304    pub fn with_enabled_buttons(mut self, buttons: WindowButtons) -> Self {
305        self.enabled_buttons = buttons;
306        self
307    }
308
309    /// Sets the initial title of the window in the title bar.
310    ///
311    /// The default is `"winit window"`.
312    ///
313    /// See [`Window::set_title`] for details.
314    #[inline]
315    pub fn with_title<T: Into<String>>(mut self, title: T) -> Self {
316        self.title = title.into();
317        self
318    }
319
320    /// Sets whether the window should be put into fullscreen upon creation.
321    ///
322    /// The default is `None`.
323    ///
324    /// See [`Window::set_fullscreen`] for details.
325    #[inline]
326    pub fn with_fullscreen(mut self, fullscreen: Option<Fullscreen>) -> Self {
327        self.fullscreen = fullscreen;
328        self
329    }
330
331    /// Request that the window is maximized upon creation.
332    ///
333    /// The default is `false`.
334    ///
335    /// See [`Window::set_maximized`] for details.
336    #[inline]
337    pub fn with_maximized(mut self, maximized: bool) -> Self {
338        self.maximized = maximized;
339        self
340    }
341
342    /// Sets whether the window will be initially visible or hidden.
343    ///
344    /// The default is to show the window.
345    ///
346    /// See [`Window::set_visible`] for details.
347    #[inline]
348    pub fn with_visible(mut self, visible: bool) -> Self {
349        self.visible = visible;
350        self
351    }
352
353    /// Sets whether the background of the window should be transparent.
354    ///
355    /// If this is `true`, writing colors with alpha values different than
356    /// `1.0` will produce a transparent window. On some platforms this
357    /// is more of a hint for the system and you'd still have the alpha
358    /// buffer. To control it see [`Window::set_transparent`].
359    ///
360    /// The default is `false`.
361    #[inline]
362    pub fn with_transparent(mut self, transparent: bool) -> Self {
363        self.transparent = transparent;
364        self
365    }
366
367    /// Sets the window's background blur / liquid-glass style.
368    ///
369    /// The default is [`BlurStyle::Off`]. See [`Window::set_blur`].
370    #[inline]
371    pub fn with_blur(mut self, blur: BlurStyle) -> Self {
372        self.blur = blur;
373        self
374    }
375
376    /// Get whether the window will support transparency.
377    #[inline]
378    pub fn transparent(&self) -> bool {
379        self.transparent
380    }
381
382    /// Sets whether the window should have a border, a title bar, etc.
383    ///
384    /// The default is `true`.
385    ///
386    /// See [`Window::set_decorations`] for details.
387    #[inline]
388    pub fn with_decorations(mut self, decorations: bool) -> Self {
389        self.decorations = decorations;
390        self
391    }
392
393    /// Sets the window level.
394    ///
395    /// This is just a hint to the OS, and the system could ignore it.
396    ///
397    /// The default is [`WindowLevel::Normal`].
398    ///
399    /// See [`WindowLevel`] for details.
400    #[inline]
401    pub fn with_window_level(mut self, level: WindowLevel) -> Self {
402        self.window_level = level;
403        self
404    }
405
406    /// Sets the window icon.
407    ///
408    /// The default is `None`.
409    ///
410    /// See [`Window::set_window_icon`] for details.
411    #[inline]
412    pub fn with_window_icon(mut self, window_icon: Option<Icon>) -> Self {
413        self.window_icon = window_icon;
414        self
415    }
416
417    /// Sets a specific theme for the window.
418    ///
419    /// If `None` is provided, the window will use the system theme.
420    ///
421    /// The default is `None`.
422    ///
423    /// ## Platform-specific
424    ///
425    /// - **macOS:** This is an app-wide setting.
426    /// - **Wayland:** This controls only CSD. When using `None` it'll try to use dbus to get the
427    ///   system preference. When explicit theme is used, this will avoid dbus all together.
428    /// - **x11:** Build window with `_GTK_THEME_VARIANT` hint set to `dark` or `light`.
429    /// - **iOS / Android / Web / x11 / Orbital:** Ignored.
430    #[inline]
431    pub fn with_theme(mut self, theme: Option<Theme>) -> Self {
432        self.preferred_theme = theme;
433        self
434    }
435
436    /// Build window with resize increments hint.
437    ///
438    /// The default is `None`.
439    ///
440    /// See [`Window::set_resize_increments`] for details.
441    #[inline]
442    pub fn with_resize_increments<S: Into<Size>>(mut self, resize_increments: S) -> Self {
443        self.resize_increments = Some(resize_increments.into());
444        self
445    }
446
447    /// Prevents the window contents from being captured by other apps.
448    ///
449    /// The default is `false`.
450    ///
451    /// ## Platform-specific
452    ///
453    /// - **macOS**: if `false`, [`NSWindowSharingNone`] is used but doesn't completely
454    ///   prevent all apps from reading the window content, for instance, QuickTime.
455    /// - **iOS / Android / Web / x11 / Orbital:** Ignored.
456    ///
457    /// [`NSWindowSharingNone`]: https://developer.apple.com/documentation/appkit/nswindowsharingtype/nswindowsharingnone
458    #[inline]
459    pub fn with_content_protected(mut self, protected: bool) -> Self {
460        self.content_protected = protected;
461        self
462    }
463
464    /// Whether the window will be initially focused or not.
465    ///
466    /// The window should be assumed as not focused by default
467    /// following by the [`WindowEvent::Focused`].
468    ///
469    /// ## Platform-specific:
470    ///
471    /// **Android / iOS / X11 / Wayland / Orbital:** Unsupported.
472    ///
473    /// [`WindowEvent::Focused`]: crate::event::WindowEvent::Focused.
474    #[inline]
475    pub fn with_active(mut self, active: bool) -> Self {
476        self.active = active;
477        self
478    }
479
480    /// Modifies the cursor icon of the window.
481    ///
482    /// The default is [`CursorIcon::Default`].
483    ///
484    /// See [`Window::set_cursor()`] for more details.
485    #[inline]
486    pub fn with_cursor(mut self, cursor: impl Into<Cursor>) -> Self {
487        self.cursor = cursor.into();
488        self
489    }
490
491    #[inline]
492    pub unsafe fn with_parent_window(
493        mut self,
494        parent_window: Option<raw_window_handle::RawWindowHandle>,
495    ) -> Self {
496        self.parent_window = parent_window.map(SendSyncRawWindowHandle);
497        self
498    }
499}
500
501/// Base Window functions.
502impl Window {
503    /// Create a new [`WindowAttributes`] which allows modifying the window's attributes before
504    /// creation.
505    #[inline]
506    pub fn default_attributes() -> WindowAttributes {
507        WindowAttributes::default()
508    }
509
510    /// Returns an identifier unique to the window.
511    #[inline]
512    pub fn id(&self) -> WindowId {
513        let _span = tracing::debug_span!("rio_window::Window::id",).entered();
514
515        self.window.maybe_wait_on_main(|w| WindowId(w.id()))
516    }
517
518    /// Returns the scale factor that can be used to map logical pixels to physical pixels, and
519    /// vice versa.
520    ///
521    /// Note that this value can change depending on user action (for example if the window is
522    /// moved to another screen); as such, tracking [`WindowEvent::ScaleFactorChanged`] events is
523    /// the most robust way to track the DPI you need to use to draw.
524    ///
525    /// This value may differ from [`MonitorHandle::scale_factor`].
526    ///
527    /// See the [`dpi`] crate for more information.
528    ///
529    /// ## Platform-specific
530    ///
531    /// The scale factor is calculated differently on different platforms:
532    ///
533    /// - **Windows:** On Windows 8 and 10, per-monitor scaling is readily configured by users from
534    ///   the display settings. While users are free to select any option they want, they're only
535    ///   given a selection of "nice" scale factors, i.e. 1.0, 1.25, 1.5... on Windows 7. The scale
536    ///   factor is global and changing it requires logging out. See [this article][windows_1] for
537    ///   technical details.
538    /// - **macOS:** Recent macOS versions allow the user to change the scaling factor for specific
539    ///   displays. When available, the user may pick a per-monitor scaling factor from a set of
540    ///   pre-defined settings. All "retina displays" have a scaling factor above 1.0 by default,
541    ///   but the specific value varies across devices.
542    /// - **X11:** Many man-hours have been spent trying to figure out how to handle DPI in X11.
543    ///   Winit currently uses a three-pronged approach:
544    ///   + Use the value in the `WINIT_X11_SCALE_FACTOR` environment variable if present.
545    ///   + If not present, use the value set in `Xft.dpi` in Xresources.
546    ///   + Otherwise, calculate the scale factor based on the millimeter monitor dimensions
547    ///     provided by XRandR.
548    ///
549    ///   If `WINIT_X11_SCALE_FACTOR` is set to `randr`, it'll ignore the `Xft.dpi` field and use
550    ///   the   XRandR scaling method. Generally speaking, you should try to configure the
551    ///   standard system   variables to do what you want before resorting to
552    ///   `WINIT_X11_SCALE_FACTOR`.
553    /// - **Wayland:** The scale factor is suggested by the compositor for each window individually
554    ///   by using the wp-fractional-scale protocol if available. Falls back to integer-scale
555    ///   factors otherwise.
556    ///
557    ///   The monitor scale factor may differ from the window scale factor.
558    /// - **iOS:** Scale factors are set by Apple to the value that best suits the device, and range
559    ///   from `1.0` to `3.0`. See [this article][apple_1] and [this article][apple_2] for more
560    ///   information.
561    ///
562    ///   This uses the underlying `UIView`'s [`contentScaleFactor`].
563    /// - **Android:** Scale factors are set by the manufacturer to the value that best suits the
564    ///   device, and range from `1.0` to `4.0`. See [this article][android_1] for more information.
565    ///
566    ///   This is currently unimplemented, and this function always returns 1.0.
567    /// - **Web:** The scale factor is the ratio between CSS pixels and the physical device pixels.
568    ///   In other words, it is the value of [`window.devicePixelRatio`][web_1]. It is affected by
569    ///   both the screen scaling and the browser zoom level and can go below `1.0`.
570    /// - **Orbital:** This is currently unimplemented, and this function always returns 1.0.
571    ///
572    /// [`WindowEvent::ScaleFactorChanged`]: crate::event::WindowEvent::ScaleFactorChanged
573    /// [windows_1]: https://docs.microsoft.com/en-us/windows/win32/hidpi/high-dpi-desktop-application-development-on-windows
574    /// [apple_1]: https://developer.apple.com/library/archive/documentation/DeviceInformation/Reference/iOSDeviceCompatibility/Displays/Displays.html
575    /// [apple_2]: https://developer.apple.com/design/human-interface-guidelines/macos/icons-and-images/image-size-and-resolution/
576    /// [android_1]: https://developer.android.com/training/multiscreen/screendensities
577    /// [web_1]: https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio
578    /// [`contentScaleFactor`]: https://developer.apple.com/documentation/uikit/uiview/1622657-contentscalefactor?language=objc
579    #[inline]
580    pub fn scale_factor(&self) -> f64 {
581        let _span = tracing::debug_span!("rio_window::Window::scale_factor",).entered();
582
583        self.window.maybe_wait_on_main(|w| w.scale_factor())
584    }
585
586    /// Queues a [`WindowEvent::RedrawRequested`] event to be emitted that aligns with the windowing
587    /// system drawing loop.
588    ///
589    /// This is the **strongly encouraged** method of redrawing windows, as it can integrate with
590    /// OS-requested redraws (e.g. when a window gets resized). To improve the event delivery
591    /// consider using [`Window::pre_present_notify`] as described in docs.
592    ///
593    /// Applications should always aim to redraw whenever they receive a `RedrawRequested` event.
594    ///
595    /// There are no strong guarantees about when exactly a `RedrawRequest` event will be emitted
596    /// with respect to other events, since the requirements can vary significantly between
597    /// windowing systems.
598    ///
599    /// However as the event aligns with the windowing system drawing loop, it may not arrive in
600    /// same or even next event loop iteration.
601    ///
602    /// ## Platform-specific
603    ///
604    /// - **Windows** This API uses `RedrawWindow` to request a `WM_PAINT` message and
605    ///   `RedrawRequested` is emitted in sync with any `WM_PAINT` messages.
606    /// - **iOS:** Can only be called on the main thread.
607    /// - **Wayland:** The events are aligned with the frame callbacks when
608    ///   [`Window::pre_present_notify`] is used.
609    /// - **Web:** [`WindowEvent::RedrawRequested`] will be aligned with the
610    ///   `requestAnimationFrame`.
611    ///
612    /// [`WindowEvent::RedrawRequested`]: crate::event::WindowEvent::RedrawRequested
613    #[inline]
614    pub fn request_redraw(&self) {
615        let _span = tracing::debug_span!("rio_window::Window::request_redraw",).entered();
616
617        self.window.maybe_queue_on_main(|w| w.request_redraw())
618    }
619
620    /// Notify the windowing system before presenting to the window.
621    ///
622    /// You should call this event after your drawing operations, but before you submit
623    /// the buffer to the display or commit your drawings. Doing so will help winit to properly
624    /// schedule and make assumptions about its internal state. For example, it could properly
625    /// throttle [`WindowEvent::RedrawRequested`].
626    ///
627    /// ## Example
628    ///
629    /// This example illustrates how it looks with OpenGL, but it applies to other graphics
630    /// APIs and software rendering.
631    ///
632    /// ```no_run
633    /// # use rio_window::window::Window;
634    /// # fn swap_buffers() {}
635    /// # fn scope(window: &Window) {
636    /// // Do the actual drawing with OpenGL.
637    ///
638    /// // Notify winit that we're about to submit buffer to the windowing system.
639    /// window.pre_present_notify();
640    ///
641    /// // Submit buffer to the windowing system.
642    /// swap_buffers();
643    /// # }
644    /// ```
645    ///
646    /// ## Platform-specific
647    ///
648    /// **Wayland:** - schedules a frame callback to throttle [`WindowEvent::RedrawRequested`].
649    ///
650    /// [`WindowEvent::RedrawRequested`]: crate::event::WindowEvent::RedrawRequested
651    #[inline]
652    pub fn pre_present_notify(&self) {
653        let _span =
654            tracing::debug_span!("rio_window::Window::pre_present_notify",).entered();
655
656        self.window.maybe_queue_on_main(|w| w.pre_present_notify());
657    }
658
659    /// Reset the dead key state of the keyboard.
660    ///
661    /// This is useful when a dead key is bound to trigger an action. Then
662    /// this function can be called to reset the dead key state so that
663    /// follow-up text input won't be affected by the dead key.
664    ///
665    /// ## Platform-specific
666    /// - **Web, macOS:** Does nothing
667    // ---------------------------
668    // Developers' Note: If this cannot be implemented on every desktop platform
669    // at least, then this function should be provided through a platform specific
670    // extension trait
671    pub fn reset_dead_keys(&self) {
672        let _span =
673            tracing::debug_span!("rio_window::Window::reset_dead_keys",).entered();
674
675        self.window.maybe_queue_on_main(|w| w.reset_dead_keys())
676    }
677}
678
679/// Position and size functions.
680impl Window {
681    /// Returns the position of the top-left hand corner of the window's client area relative to the
682    /// top-left hand corner of the desktop.
683    ///
684    /// The same conditions that apply to [`Window::outer_position`] apply to this method.
685    ///
686    /// ## Platform-specific
687    ///
688    /// - **iOS:** Can only be called on the main thread. Returns the top left coordinates of the
689    ///   window's [safe area] in the screen space coordinate system.
690    /// - **Web:** Returns the top-left coordinates relative to the viewport. _Note: this returns
691    ///   the same value as [`Window::outer_position`]._
692    /// - **Android / Wayland:** Always returns [`NotSupportedError`].
693    ///
694    /// [safe area]: https://developer.apple.com/documentation/uikit/uiview/2891103-safeareainsets?language=objc
695    #[inline]
696    pub fn inner_position(&self) -> Result<PhysicalPosition<i32>, NotSupportedError> {
697        let _span = tracing::debug_span!("rio_window::Window::inner_position",).entered();
698
699        self.window.maybe_wait_on_main(|w| w.inner_position())
700    }
701
702    /// Returns the position of the top-left hand corner of the window relative to the
703    /// top-left hand corner of the desktop.
704    ///
705    /// Note that the top-left hand corner of the desktop is not necessarily the same as
706    /// the screen. If the user uses a desktop with multiple monitors, the top-left hand corner
707    /// of the desktop is the top-left hand corner of the monitor at the top-left of the desktop.
708    ///
709    /// The coordinates can be negative if the top-left hand corner of the window is outside
710    /// of the visible screen region.
711    ///
712    /// ## Platform-specific
713    ///
714    /// - **iOS:** Can only be called on the main thread. Returns the top left coordinates of the
715    ///   window in the screen space coordinate system.
716    /// - **Web:** Returns the top-left coordinates relative to the viewport.
717    /// - **Android / Wayland:** Always returns [`NotSupportedError`].
718    #[inline]
719    pub fn outer_position(&self) -> Result<PhysicalPosition<i32>, NotSupportedError> {
720        let _span = tracing::debug_span!("rio_window::Window::outer_position",).entered();
721
722        self.window.maybe_wait_on_main(|w| w.outer_position())
723    }
724
725    /// Modifies the position of the window.
726    ///
727    /// See [`Window::outer_position`] for more information about the coordinates.
728    /// This automatically un-maximizes the window if it's maximized.
729    ///
730    /// ```no_run
731    /// # use rio_window::dpi::{LogicalPosition, PhysicalPosition};
732    /// # use rio_window::window::Window;
733    /// # fn scope(window: &Window) {
734    /// // Specify the position in logical dimensions like this:
735    /// window.set_outer_position(LogicalPosition::new(400.0, 200.0));
736    ///
737    /// // Or specify the position in physical dimensions like this:
738    /// window.set_outer_position(PhysicalPosition::new(400, 200));
739    /// # }
740    /// ```
741    ///
742    /// ## Platform-specific
743    ///
744    /// - **iOS:** Can only be called on the main thread. Sets the top left coordinates of the
745    ///   window in the screen space coordinate system.
746    /// - **Web:** Sets the top-left coordinates relative to the viewport. Doesn't account for CSS
747    ///   [`transform`].
748    /// - **Android / Wayland:** Unsupported.
749    ///
750    /// [`transform`]: https://developer.mozilla.org/en-US/docs/Web/CSS/transform
751    #[inline]
752    pub fn set_outer_position<P: Into<Position>>(&self, position: P) {
753        let position = position.into();
754        let _span = tracing::debug_span!(
755            "rio_window::Window::set_outer_position",
756            position = ?position
757        )
758        .entered();
759
760        self.window
761            .maybe_queue_on_main(move |w| w.set_outer_position(position))
762    }
763
764    /// Returns the physical size of the window's client area.
765    ///
766    /// The client area is the content of the window, excluding the title bar and borders.
767    ///
768    /// ## Platform-specific
769    ///
770    /// - **iOS:** Can only be called on the main thread. Returns the `PhysicalSize` of the window's
771    ///   [safe area] in screen space coordinates.
772    /// - **Web:** Returns the size of the canvas element. Doesn't account for CSS [`transform`].
773    ///
774    /// [safe area]: https://developer.apple.com/documentation/uikit/uiview/2891103-safeareainsets?language=objc
775    /// [`transform`]: https://developer.mozilla.org/en-US/docs/Web/CSS/transform
776    #[inline]
777    pub fn inner_size(&self) -> PhysicalSize<u32> {
778        let _span = tracing::debug_span!("rio_window::Window::inner_size",).entered();
779
780        self.window.maybe_wait_on_main(|w| w.inner_size())
781    }
782
783    /// Request the new size for the window.
784    ///
785    /// On platforms where the size is entirely controlled by the user the
786    /// applied size will be returned immediately, resize event in such case
787    /// may not be generated.
788    ///
789    /// On platforms where resizing is disallowed by the windowing system, the current
790    /// inner size is returned immediately, and the user one is ignored.
791    ///
792    /// When `None` is returned, it means that the request went to the display system,
793    /// and the actual size will be delivered later with the [`WindowEvent::Resized`].
794    ///
795    /// See [`Window::inner_size`] for more information about the values.
796    ///
797    /// The request could automatically un-maximize the window if it's maximized.
798    ///
799    /// ```no_run
800    /// # use rio_window::dpi::{LogicalSize, PhysicalSize};
801    /// # use rio_window::window::Window;
802    /// # fn scope(window: &Window) {
803    /// // Specify the size in logical dimensions like this:
804    /// let _ = window.request_inner_size(LogicalSize::new(400.0, 200.0));
805    ///
806    /// // Or specify the size in physical dimensions like this:
807    /// let _ = window.request_inner_size(PhysicalSize::new(400, 200));
808    /// # }
809    /// ```
810    ///
811    /// ## Platform-specific
812    ///
813    /// - **Web:** Sets the size of the canvas element. Doesn't account for CSS [`transform`].
814    ///
815    /// [`WindowEvent::Resized`]: crate::event::WindowEvent::Resized
816    /// [`transform`]: https://developer.mozilla.org/en-US/docs/Web/CSS/transform
817    #[inline]
818    #[must_use]
819    pub fn request_inner_size<S: Into<Size>>(
820        &self,
821        size: S,
822    ) -> Option<PhysicalSize<u32>> {
823        let size = size.into();
824        let _span = tracing::debug_span!(
825            "rio_window::Window::request_inner_size",
826            size = ?size
827        )
828        .entered();
829        self.window
830            .maybe_wait_on_main(|w| w.request_inner_size(size))
831    }
832
833    /// Returns the physical size of the entire window.
834    ///
835    /// These dimensions include the title bar and borders. If you don't want that (and you usually
836    /// don't), use [`Window::inner_size`] instead.
837    ///
838    /// ## Platform-specific
839    ///
840    /// - **iOS:** Can only be called on the main thread. Returns the [`PhysicalSize`] of the window
841    ///   in screen space coordinates.
842    /// - **Web:** Returns the size of the canvas element. _Note: this returns the same value as
843    ///   [`Window::inner_size`]._
844    #[inline]
845    pub fn outer_size(&self) -> PhysicalSize<u32> {
846        let _span = tracing::debug_span!("rio_window::Window::outer_size",).entered();
847        self.window.maybe_wait_on_main(|w| w.outer_size())
848    }
849
850    /// Sets a minimum dimension size for the window.
851    ///
852    /// ```no_run
853    /// # use rio_window::dpi::{LogicalSize, PhysicalSize};
854    /// # use rio_window::window::Window;
855    /// # fn scope(window: &Window) {
856    /// // Specify the size in logical dimensions like this:
857    /// window.set_min_inner_size(Some(LogicalSize::new(400.0, 200.0)));
858    ///
859    /// // Or specify the size in physical dimensions like this:
860    /// window.set_min_inner_size(Some(PhysicalSize::new(400, 200)));
861    /// # }
862    /// ```
863    ///
864    /// ## Platform-specific
865    ///
866    /// - **iOS / Android / Orbital:** Unsupported.
867    #[inline]
868    pub fn set_min_inner_size<S: Into<Size>>(&self, min_size: Option<S>) {
869        let min_size = min_size.map(|s| s.into());
870        let _span = tracing::debug_span!(
871            "rio_window::Window::set_min_inner_size",
872            min_size = ?min_size
873        )
874        .entered();
875        self.window
876            .maybe_queue_on_main(move |w| w.set_min_inner_size(min_size))
877    }
878
879    /// Sets a maximum dimension size for the window.
880    ///
881    /// ```no_run
882    /// # use rio_window::dpi::{LogicalSize, PhysicalSize};
883    /// # use rio_window::window::Window;
884    /// # fn scope(window: &Window) {
885    /// // Specify the size in logical dimensions like this:
886    /// window.set_max_inner_size(Some(LogicalSize::new(400.0, 200.0)));
887    ///
888    /// // Or specify the size in physical dimensions like this:
889    /// window.set_max_inner_size(Some(PhysicalSize::new(400, 200)));
890    /// # }
891    /// ```
892    ///
893    /// ## Platform-specific
894    ///
895    /// - **iOS / Android / Orbital:** Unsupported.
896    #[inline]
897    pub fn set_max_inner_size<S: Into<Size>>(&self, max_size: Option<S>) {
898        let max_size = max_size.map(|s| s.into());
899        let _span = tracing::debug_span!(
900            "rio_window::Window::max_size",
901            max_size = ?max_size
902        )
903        .entered();
904        self.window
905            .maybe_queue_on_main(move |w| w.set_max_inner_size(max_size))
906    }
907
908    /// Returns window resize increments if any were set.
909    ///
910    /// ## Platform-specific
911    ///
912    /// - **iOS / Android / Web / Wayland / Orbital:** Always returns [`None`].
913    #[inline]
914    pub fn resize_increments(&self) -> Option<PhysicalSize<u32>> {
915        let _span =
916            tracing::debug_span!("rio_window::Window::resize_increments",).entered();
917        self.window.maybe_wait_on_main(|w| w.resize_increments())
918    }
919
920    /// Sets window resize increments.
921    ///
922    /// This is a niche constraint hint usually employed by terminal emulators
923    /// and other apps that need "blocky" resizes.
924    ///
925    /// ## Platform-specific
926    ///
927    /// - **macOS:** Increments are converted to logical size and then macOS rounds them to whole
928    ///   numbers.
929    /// - **Wayland:** Not implemented.
930    /// - **iOS / Android / Web / Orbital:** Unsupported.
931    #[inline]
932    pub fn set_resize_increments<S: Into<Size>>(&self, increments: Option<S>) {
933        let increments = increments.map(Into::into);
934        let _span = tracing::debug_span!(
935            "rio_window::Window::set_resize_increments",
936            increments = ?increments
937        )
938        .entered();
939        self.window
940            .maybe_queue_on_main(move |w| w.set_resize_increments(increments))
941    }
942}
943
944/// Misc. attribute functions.
945impl Window {
946    /// Modifies the title of the window.
947    ///
948    /// ## Platform-specific
949    ///
950    /// - **iOS / Android:** Unsupported.
951    #[inline]
952    pub fn set_title(&self, title: &str) {
953        let _span =
954            tracing::debug_span!("rio_window::Window::set_title", title).entered();
955        self.window.maybe_wait_on_main(|w| w.set_title(title))
956    }
957
958    #[inline]
959    #[cfg(target_os = "macos")]
960    pub fn set_subtitle(&self, title: &str) {
961        let _span =
962            tracing::debug_span!("rio_window::Window::set_title", title).entered();
963        self.window.maybe_wait_on_main(|w| w.set_subtitle(title))
964    }
965
966    /// Change the window transparency state.
967    ///
968    /// This is just a hint that may not change anything about
969    /// the window transparency, however doing a mismatch between
970    /// the content of your window and this hint may result in
971    /// visual artifacts.
972    ///
973    /// The default value follows the [`WindowAttributes::with_transparent`].
974    ///
975    /// ## Platform-specific
976    ///
977    /// - **macOS:** If you're not drawing to the window yourself, you might have to set the
978    ///   background color of the window to enable transparency.
979    /// - **Web / iOS / Android:** Unsupported.
980    /// - **X11:** Can only be set while building the window, with
981    ///   [`WindowAttributes::with_transparent`].
982    #[inline]
983    pub fn set_transparent(&self, transparent: bool) {
984        let _span =
985            tracing::debug_span!("rio_window::Window::set_transparent", transparent)
986                .entered();
987        self.window
988            .maybe_queue_on_main(move |w| w.set_transparent(transparent))
989    }
990
991    /// Change the window blur state.
992    ///
993    /// Apply a [`BlurStyle`] to the window background.
994    ///
995    /// ## Platform-specific
996    ///
997    /// - **Android / iOS / X11 / Web:** Unsupported.
998    /// - **Wayland:** `System` works with `org_kde_kwin_blur_manager`;
999    ///   glass values fall back to `System`.
1000    /// - **Windows:** `System` uses the DWM acrylic backdrop; glass
1001    ///   values fall back to `System`.
1002    /// - **macOS:** `System` uses the CGS backdrop blur. Glass
1003    ///   variants use `NSGlassEffectView` on macOS 26+ and fall back
1004    ///   to `System` with a warning on earlier versions.
1005    #[inline]
1006    pub fn set_blur(&self, blur: BlurStyle) {
1007        let _span = tracing::debug_span!("rio_window::Window::set_blur", ?blur).entered();
1008        self.window.maybe_queue_on_main(move |w| w.set_blur(blur))
1009    }
1010
1011    /// Modifies the window's visibility.
1012    ///
1013    /// If `false`, this will hide the window. If `true`, this will show the window.
1014    ///
1015    /// ## Platform-specific
1016    ///
1017    /// - **Android / Wayland / Web:** Unsupported.
1018    /// - **iOS:** Can only be called on the main thread.
1019    #[inline]
1020    pub fn set_visible(&self, visible: bool) {
1021        let _span =
1022            tracing::debug_span!("rio_window::Window::set_visible", visible).entered();
1023        self.window
1024            .maybe_queue_on_main(move |w| w.set_visible(visible))
1025    }
1026
1027    /// Gets the window's current visibility state.
1028    ///
1029    /// `None` means it couldn't be determined, so it is not recommended to use this to drive your
1030    /// rendering backend.
1031    ///
1032    /// ## Platform-specific
1033    ///
1034    /// - **X11:** Not implemented.
1035    /// - **Wayland / iOS / Android / Web:** Unsupported.
1036    #[inline]
1037    pub fn is_visible(&self) -> Option<bool> {
1038        let _span = tracing::debug_span!("rio_window::Window::is_visible",).entered();
1039        self.window.maybe_wait_on_main(|w| w.is_visible())
1040    }
1041
1042    /// Sets whether the window is resizable or not.
1043    ///
1044    /// Note that making the window unresizable doesn't exempt you from handling
1045    /// [`WindowEvent::Resized`], as that event can still be triggered by DPI scaling, entering
1046    /// fullscreen mode, etc. Also, the window could still be resized by calling
1047    /// [`Window::request_inner_size`].
1048    ///
1049    /// ## Platform-specific
1050    ///
1051    /// This only has an effect on desktop platforms.
1052    ///
1053    /// - **X11:** Due to a bug in XFCE, this has no effect on Xfwm.
1054    /// - **iOS / Android / Web:** Unsupported.
1055    ///
1056    /// [`WindowEvent::Resized`]: crate::event::WindowEvent::Resized
1057    #[inline]
1058    pub fn set_resizable(&self, resizable: bool) {
1059        let _span = tracing::debug_span!("rio_window::Window::set_resizable", resizable)
1060            .entered();
1061        self.window
1062            .maybe_queue_on_main(move |w| w.set_resizable(resizable))
1063    }
1064
1065    /// Gets the window's current resizable state.
1066    ///
1067    /// ## Platform-specific
1068    ///
1069    /// - **X11:** Not implemented.
1070    /// - **iOS / Android / Web:** Unsupported.
1071    #[inline]
1072    pub fn is_resizable(&self) -> bool {
1073        let _span = tracing::debug_span!("rio_window::Window::is_resizable",).entered();
1074        self.window.maybe_wait_on_main(|w| w.is_resizable())
1075    }
1076
1077    /// Sets the enabled window buttons.
1078    ///
1079    /// ## Platform-specific
1080    ///
1081    /// - **Wayland / X11 / Orbital:** Not implemented.
1082    /// - **Web / iOS / Android:** Unsupported.
1083    pub fn set_enabled_buttons(&self, buttons: WindowButtons) {
1084        let _span = tracing::debug_span!(
1085            "rio_window::Window::set_enabled_buttons",
1086            buttons = ?buttons
1087        )
1088        .entered();
1089        self.window
1090            .maybe_queue_on_main(move |w| w.set_enabled_buttons(buttons))
1091    }
1092
1093    /// Gets the enabled window buttons.
1094    ///
1095    /// ## Platform-specific
1096    ///
1097    /// - **Wayland / X11 / Orbital:** Not implemented. Always returns [`WindowButtons::all`].
1098    /// - **Web / iOS / Android:** Unsupported. Always returns [`WindowButtons::all`].
1099    pub fn enabled_buttons(&self) -> WindowButtons {
1100        let _span =
1101            tracing::debug_span!("rio_window::Window::enabled_buttons",).entered();
1102        self.window.maybe_wait_on_main(|w| w.enabled_buttons())
1103    }
1104
1105    /// Sets the window to minimized or back
1106    ///
1107    /// ## Platform-specific
1108    ///
1109    /// - **iOS / Android / Web / Orbital:** Unsupported.
1110    /// - **Wayland:** Un-minimize is unsupported.
1111    #[inline]
1112    pub fn set_minimized(&self, minimized: bool) {
1113        let _span = tracing::debug_span!("rio_window::Window::set_minimized", minimized)
1114            .entered();
1115        self.window
1116            .maybe_queue_on_main(move |w| w.set_minimized(minimized))
1117    }
1118
1119    /// Gets the window's current minimized state.
1120    ///
1121    /// `None` will be returned, if the minimized state couldn't be determined.
1122    ///
1123    /// ## Note
1124    ///
1125    /// - You shouldn't stop rendering for minimized windows, however you could lower the fps.
1126    ///
1127    /// ## Platform-specific
1128    ///
1129    /// - **Wayland**: always `None`.
1130    /// - **iOS / Android / Web / Orbital:** Unsupported.
1131    #[inline]
1132    pub fn is_minimized(&self) -> Option<bool> {
1133        let _span = tracing::debug_span!("rio_window::Window::is_minimized",).entered();
1134        self.window.maybe_wait_on_main(|w| w.is_minimized())
1135    }
1136
1137    /// Sets the window to maximized or back.
1138    ///
1139    /// ## Platform-specific
1140    ///
1141    /// - **iOS / Android / Web:** Unsupported.
1142    #[inline]
1143    pub fn set_maximized(&self, maximized: bool) {
1144        let _span = tracing::debug_span!("rio_window::Window::set_maximized", maximized)
1145            .entered();
1146        self.window
1147            .maybe_queue_on_main(move |w| w.set_maximized(maximized))
1148    }
1149
1150    /// Gets the window's current maximized state.
1151    ///
1152    /// ## Platform-specific
1153    ///
1154    /// - **iOS / Android / Web:** Unsupported.
1155    #[inline]
1156    pub fn is_maximized(&self) -> bool {
1157        let _span = tracing::debug_span!("rio_window::Window::is_maximized",).entered();
1158        self.window.maybe_wait_on_main(|w| w.is_maximized())
1159    }
1160
1161    /// Sets the window to fullscreen or back.
1162    ///
1163    /// ## Platform-specific
1164    ///
1165    /// - **macOS:** [`Fullscreen::Exclusive`] provides true exclusive mode with a video mode
1166    ///   change. *Caveat!* macOS doesn't provide task switching (or spaces!) while in exclusive
1167    ///   fullscreen mode. This mode should be used when a video mode change is desired, but for a
1168    ///   better user experience, borderless fullscreen might be preferred.
1169    ///
1170    ///   [`Fullscreen::Borderless`] provides a borderless fullscreen window on a
1171    ///   separate space. This is the idiomatic way for fullscreen games to work
1172    ///   on macOS. See `WindowExtMacOs::set_simple_fullscreen` if
1173    ///   separate spaces are not preferred.
1174    ///
1175    ///   The dock and the menu bar are disabled in exclusive fullscreen mode.
1176    /// - **iOS:** Can only be called on the main thread.
1177    /// - **Wayland:** Does not support exclusive fullscreen mode and will no-op a request.
1178    /// - **Windows:** Screen saver is disabled in fullscreen mode.
1179    /// - **Android / Orbital:** Unsupported.
1180    /// - **Web:** Does nothing without a [transient activation].
1181    ///
1182    /// [transient activation]: https://developer.mozilla.org/en-US/docs/Glossary/Transient_activation
1183    #[inline]
1184    pub fn set_fullscreen(&self, fullscreen: Option<Fullscreen>) {
1185        let _span = tracing::debug_span!(
1186            "rio_window::Window::set_fullscreen",
1187            fullscreen = ?fullscreen
1188        )
1189        .entered();
1190        self.window
1191            .maybe_queue_on_main(move |w| w.set_fullscreen(fullscreen.map(|f| f.into())))
1192    }
1193
1194    /// Gets the window's current fullscreen state.
1195    ///
1196    /// ## Platform-specific
1197    ///
1198    /// - **iOS:** Can only be called on the main thread.
1199    /// - **Android / Orbital:** Will always return `None`.
1200    /// - **Wayland:** Can return `Borderless(None)` when there are no monitors.
1201    /// - **Web:** Can only return `None` or `Borderless(None)`.
1202    #[inline]
1203    pub fn fullscreen(&self) -> Option<Fullscreen> {
1204        let _span = tracing::debug_span!("rio_window::Window::fullscreen",).entered();
1205        self.window
1206            .maybe_wait_on_main(|w| w.fullscreen().map(|f| f.into()))
1207    }
1208
1209    /// Turn window decorations on or off.
1210    ///
1211    /// Enable/disable window decorations provided by the server or Winit.
1212    /// By default this is enabled. Note that fullscreen windows and windows on
1213    /// mobile and web platforms naturally do not have decorations.
1214    ///
1215    /// ## Platform-specific
1216    ///
1217    /// - **iOS / Android / Web:** No effect.
1218    #[inline]
1219    pub fn set_decorations(&self, decorations: bool) {
1220        let _span =
1221            tracing::debug_span!("rio_window::Window::set_decorations", decorations)
1222                .entered();
1223        self.window
1224            .maybe_queue_on_main(move |w| w.set_decorations(decorations))
1225    }
1226
1227    /// Gets the window's current decorations state.
1228    ///
1229    /// Returns `true` when windows are decorated (server-side or by Winit).
1230    /// Also returns `true` when no decorations are required (mobile, web).
1231    ///
1232    /// ## Platform-specific
1233    ///
1234    /// - **iOS / Android / Web:** Always returns `true`.
1235    #[inline]
1236    pub fn is_decorated(&self) -> bool {
1237        let _span = tracing::debug_span!("rio_window::Window::is_decorated",).entered();
1238        self.window.maybe_wait_on_main(|w| w.is_decorated())
1239    }
1240
1241    /// Change the window level.
1242    ///
1243    /// This is just a hint to the OS, and the system could ignore it.
1244    ///
1245    /// See [`WindowLevel`] for details.
1246    pub fn set_window_level(&self, level: WindowLevel) {
1247        let _span = tracing::debug_span!(
1248            "rio_window::Window::set_window_level",
1249            level = ?level
1250        )
1251        .entered();
1252        self.window
1253            .maybe_queue_on_main(move |w| w.set_window_level(level))
1254    }
1255
1256    /// Sets the window icon.
1257    ///
1258    /// On Windows and X11, this is typically the small icon in the top-left
1259    /// corner of the titlebar.
1260    ///
1261    /// ## Platform-specific
1262    ///
1263    /// - **iOS / Android / Web / Wayland / macOS / Orbital:** Unsupported.
1264    ///
1265    /// - **Windows:** Sets `ICON_SMALL`. The base size for a window icon is 16x16, but it's
1266    ///   recommended to account for screen scaling and pick a multiple of that, i.e. 32x32.
1267    ///
1268    /// - **X11:** Has no universal guidelines for icon sizes, so you're at the whims of the WM.
1269    ///   That said, it's usually in the same ballpark as on Windows.
1270    #[inline]
1271    pub fn set_window_icon(&self, window_icon: Option<Icon>) {
1272        let _span =
1273            tracing::debug_span!("rio_window::Window::set_window_icon",).entered();
1274        self.window
1275            .maybe_queue_on_main(move |w| w.set_window_icon(window_icon))
1276    }
1277
1278    /// Set the IME cursor editing area, where the `position` is the top left corner of that area
1279    /// and `size` is the size of this area starting from the position. An example of such area
1280    /// could be a input field in the UI or line in the editor.
1281    ///
1282    /// The windowing system could place a candidate box close to that area, but try to not obscure
1283    /// the specified area, so the user input to it stays visible.
1284    ///
1285    /// The candidate box is the window / popup / overlay that allows you to select the desired
1286    /// characters. The look of this box may differ between input devices, even on the same
1287    /// platform.
1288    ///
1289    /// (Apple's official term is "candidate window", see their [chinese] and [japanese] guides).
1290    ///
1291    /// ## Example
1292    ///
1293    /// ```no_run
1294    /// # use rio_window::dpi::{LogicalPosition, PhysicalPosition, LogicalSize, PhysicalSize};
1295    /// # use rio_window::window::Window;
1296    /// # fn scope(window: &Window) {
1297    /// // Specify the position in logical dimensions like this:
1298    /// window.set_ime_cursor_area(LogicalPosition::new(400.0, 200.0), LogicalSize::new(100, 100));
1299    ///
1300    /// // Or specify the position in physical dimensions like this:
1301    /// window.set_ime_cursor_area(PhysicalPosition::new(400, 200), PhysicalSize::new(100, 100));
1302    /// # }
1303    /// ```
1304    ///
1305    /// ## Platform-specific
1306    ///
1307    /// - **X11:** - area is not supported, only position.
1308    /// - **iOS / Android / Web / Orbital:** Unsupported.
1309    ///
1310    /// [chinese]: https://support.apple.com/guide/chinese-input-method/use-the-candidate-window-cim12992/104/mac/12.0
1311    /// [japanese]: https://support.apple.com/guide/japanese-input-method/use-the-candidate-window-jpim10262/6.3/mac/12.0
1312    #[inline]
1313    pub fn set_ime_cursor_area<P: Into<Position>, S: Into<Size>>(
1314        &self,
1315        position: P,
1316        size: S,
1317    ) {
1318        let position = position.into();
1319        let size = size.into();
1320        let _span = tracing::debug_span!(
1321            "rio_window::Window::set_ime_cursor_area",
1322            position = ?position,
1323            size = ?size,
1324        )
1325        .entered();
1326        self.window
1327            .maybe_queue_on_main(move |w| w.set_ime_cursor_area(position, size))
1328    }
1329
1330    /// Sets whether the window should get IME events
1331    ///
1332    /// When IME is allowed, the window will receive [`Ime`] events, and during the
1333    /// preedit phase the window will NOT get [`KeyboardInput`] events. The window
1334    /// should allow IME while it is expecting text input.
1335    ///
1336    /// When IME is not allowed, the window won't receive [`Ime`] events, and will
1337    /// receive [`KeyboardInput`] events for every keypress instead. Not allowing
1338    /// IME is useful for games for example.
1339    ///
1340    /// IME is **not** allowed by default.
1341    ///
1342    /// ## Platform-specific
1343    ///
1344    /// - **macOS:** IME must be enabled to receive text-input where dead-key sequences are
1345    ///   combined.
1346    /// - **iOS / Android / Web / Orbital:** Unsupported.
1347    /// - **X11**: Enabling IME will disable dead keys reporting during compose.
1348    ///
1349    /// [`Ime`]: crate::event::WindowEvent::Ime
1350    /// [`KeyboardInput`]: crate::event::WindowEvent::KeyboardInput
1351    #[inline]
1352    pub fn set_ime_allowed(&self, allowed: bool) {
1353        let _span = tracing::debug_span!("rio_window::Window::set_ime_allowed", allowed)
1354            .entered();
1355        self.window
1356            .maybe_queue_on_main(move |w| w.set_ime_allowed(allowed))
1357    }
1358
1359    /// Sets the IME purpose for the window using [`ImePurpose`].
1360    ///
1361    /// ## Platform-specific
1362    ///
1363    /// - **iOS / Android / Web / Windows / X11 / macOS / Orbital:** Unsupported.
1364    #[inline]
1365    pub fn set_ime_purpose(&self, purpose: ImePurpose) {
1366        let _span = tracing::debug_span!(
1367            "rio_window::Window::set_ime_purpose",
1368            purpose = ?purpose
1369        )
1370        .entered();
1371        self.window
1372            .maybe_queue_on_main(move |w| w.set_ime_purpose(purpose))
1373    }
1374
1375    /// Brings the window to the front and sets input focus. Has no effect if the window is
1376    /// already in focus, minimized, or not visible.
1377    ///
1378    /// This method steals input focus from other applications. Do not use this method unless
1379    /// you are certain that's what the user wants. Focus stealing can cause an extremely disruptive
1380    /// user experience.
1381    ///
1382    /// ## Platform-specific
1383    ///
1384    /// - **iOS / Android / Wayland / Orbital:** Unsupported.
1385    #[inline]
1386    pub fn focus_window(&self) {
1387        let _span = tracing::debug_span!("rio_window::Window::focus_window",).entered();
1388        self.window.maybe_queue_on_main(|w| w.focus_window())
1389    }
1390
1391    /// Gets whether the window has keyboard focus.
1392    ///
1393    /// This queries the same state information as [`WindowEvent::Focused`].
1394    ///
1395    /// [`WindowEvent::Focused`]: crate::event::WindowEvent::Focused
1396    #[inline]
1397    pub fn has_focus(&self) -> bool {
1398        let _span = tracing::debug_span!("rio_window::Window::has_focus",).entered();
1399        self.window.maybe_wait_on_main(|w| w.has_focus())
1400    }
1401
1402    /// Requests user attention to the window, this has no effect if the application
1403    /// is already focused. How requesting for user attention manifests is platform dependent,
1404    /// see [`UserAttentionType`] for details.
1405    ///
1406    /// Providing `None` will unset the request for user attention. Unsetting the request for
1407    /// user attention might not be done automatically by the WM when the window receives input.
1408    ///
1409    /// ## Platform-specific
1410    ///
1411    /// - **iOS / Android / Web / Orbital:** Unsupported.
1412    /// - **macOS:** `None` has no effect.
1413    /// - **X11:** Requests for user attention must be manually cleared.
1414    /// - **Wayland:** Requires `xdg_activation_v1` protocol, `None` has no effect.
1415    #[inline]
1416    pub fn request_user_attention(&self, request_type: Option<UserAttentionType>) {
1417        let _span = tracing::debug_span!(
1418            "rio_window::Window::request_user_attention",
1419            request_type = ?request_type
1420        )
1421        .entered();
1422        self.window
1423            .maybe_queue_on_main(move |w| w.request_user_attention(request_type))
1424    }
1425
1426    /// Sets the current window theme. Use `None` to fallback to system default.
1427    ///
1428    /// ## Platform-specific
1429    ///
1430    /// - **macOS:** This is an app-wide setting.
1431    /// - **Wayland:** Sets the theme for the client side decorations. Using `None` will use dbus to
1432    ///   get the system preference.
1433    /// - **X11:** Sets `_GTK_THEME_VARIANT` hint to `dark` or `light` and if `None` is used, it
1434    ///   will default to  [`Theme::Dark`].
1435    /// - **iOS / Android / Web / Orbital:** Unsupported.
1436    #[inline]
1437    pub fn set_theme(&self, theme: Option<Theme>) {
1438        let _span = tracing::debug_span!(
1439            "rio_window::Window::set_theme",
1440            theme = ?theme
1441        )
1442        .entered();
1443        self.window.maybe_queue_on_main(move |w| w.set_theme(theme))
1444    }
1445
1446    /// Returns the current window theme.
1447    ///
1448    /// ## Platform-specific
1449    ///
1450    /// - **macOS:** This is an app-wide setting.
1451    /// - **iOS / Android / Wayland / x11 / Orbital:** Unsupported.
1452    #[inline]
1453    pub fn theme(&self) -> Option<Theme> {
1454        let _span = tracing::debug_span!("rio_window::Window::theme",).entered();
1455        self.window.maybe_wait_on_main(|w| w.theme())
1456    }
1457
1458    /// Prevents the window contents from being captured by other apps.
1459    ///
1460    /// ## Platform-specific
1461    ///
1462    /// - **macOS**: if `false`, [`NSWindowSharingNone`] is used but doesn't completely
1463    ///   prevent all apps from reading the window content, for instance, QuickTime.
1464    /// - **iOS / Android / x11 / Wayland / Web / Orbital:** Unsupported.
1465    ///
1466    /// [`NSWindowSharingNone`]: https://developer.apple.com/documentation/appkit/nswindowsharingtype/nswindowsharingnone
1467    pub fn set_content_protected(&self, protected: bool) {
1468        let _span =
1469            tracing::debug_span!("rio_window::Window::set_content_protected", protected)
1470                .entered();
1471        self.window
1472            .maybe_queue_on_main(move |w| w.set_content_protected(protected))
1473    }
1474
1475    /// Gets the current title of the window.
1476    ///
1477    /// ## Platform-specific
1478    ///
1479    /// - **iOS / Android / x11 / Wayland / Web:** Unsupported. Always returns an empty string.
1480    #[inline]
1481    pub fn title(&self) -> String {
1482        let _span = tracing::debug_span!("rio_window::Window::title",).entered();
1483        self.window.maybe_wait_on_main(|w| w.title())
1484    }
1485}
1486
1487/// Cursor functions.
1488impl Window {
1489    /// Modifies the cursor icon of the window.
1490    ///
1491    /// ## Platform-specific
1492    ///
1493    /// - **iOS / Android / Orbital:** Unsupported.
1494    /// - **Web:** Custom cursors have to be loaded and decoded first, until then the previous
1495    ///   cursor is shown.
1496    #[inline]
1497    pub fn set_cursor(&self, cursor: impl Into<Cursor>) {
1498        let cursor = cursor.into();
1499        let _span = tracing::debug_span!("rio_window::Window::set_cursor",).entered();
1500        self.window
1501            .maybe_queue_on_main(move |w| w.set_cursor(cursor))
1502    }
1503
1504    /// Deprecated! Use [`Window::set_cursor()`] instead.
1505    #[deprecated = "Renamed to `set_cursor`"]
1506    #[inline]
1507    pub fn set_cursor_icon(&self, icon: CursorIcon) {
1508        self.set_cursor(icon)
1509    }
1510
1511    /// Changes the position of the cursor in window coordinates.
1512    ///
1513    /// ```no_run
1514    /// # use rio_window::dpi::{LogicalPosition, PhysicalPosition};
1515    /// # use rio_window::window::Window;
1516    /// # fn scope(window: &Window) {
1517    /// // Specify the position in logical dimensions like this:
1518    /// window.set_cursor_position(LogicalPosition::new(400.0, 200.0));
1519    ///
1520    /// // Or specify the position in physical dimensions like this:
1521    /// window.set_cursor_position(PhysicalPosition::new(400, 200));
1522    /// # }
1523    /// ```
1524    ///
1525    /// ## Platform-specific
1526    ///
1527    /// - **Wayland**: Cursor must be in [`CursorGrabMode::Locked`].
1528    /// - **iOS / Android / Web / Orbital:** Always returns an [`ExternalError::NotSupported`].
1529    #[inline]
1530    pub fn set_cursor_position<P: Into<Position>>(
1531        &self,
1532        position: P,
1533    ) -> Result<(), ExternalError> {
1534        let position = position.into();
1535        let _span = tracing::debug_span!(
1536            "rio_window::Window::set_cursor_position",
1537            position = ?position
1538        )
1539        .entered();
1540        self.window
1541            .maybe_wait_on_main(|w| w.set_cursor_position(position))
1542    }
1543
1544    /// Set grabbing [mode][CursorGrabMode] on the cursor preventing it from leaving the window.
1545    ///
1546    /// # Example
1547    ///
1548    /// First try confining the cursor, and if that fails, try locking it instead.
1549    ///
1550    /// ```no_run
1551    /// # use rio_window::window::{CursorGrabMode, Window};
1552    /// # fn scope(window: &Window) {
1553    /// window
1554    ///     .set_cursor_grab(CursorGrabMode::Confined)
1555    ///     .or_else(|_e| window.set_cursor_grab(CursorGrabMode::Locked))
1556    ///     .unwrap();
1557    /// # }
1558    /// ```
1559    #[inline]
1560    pub fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), ExternalError> {
1561        let _span = tracing::debug_span!(
1562            "rio_window::Window::set_cursor_grab",
1563            mode = ?mode
1564        )
1565        .entered();
1566        self.window.maybe_wait_on_main(|w| w.set_cursor_grab(mode))
1567    }
1568
1569    /// Modifies the cursor's visibility.
1570    ///
1571    /// If `false`, this will hide the cursor. If `true`, this will show the cursor.
1572    ///
1573    /// ## Platform-specific
1574    ///
1575    /// - **Windows:** The cursor is only hidden within the confines of the window.
1576    /// - **X11:** The cursor is only hidden within the confines of the window.
1577    /// - **Wayland:** The cursor is only hidden within the confines of the window.
1578    /// - **macOS:** The cursor is hidden as long as the window has input focus, even if the cursor
1579    ///   is outside of the window.
1580    /// - **iOS / Android:** Unsupported.
1581    #[inline]
1582    pub fn set_cursor_visible(&self, visible: bool) {
1583        let _span =
1584            tracing::debug_span!("rio_window::Window::set_cursor_visible", visible)
1585                .entered();
1586        self.window
1587            .maybe_queue_on_main(move |w| w.set_cursor_visible(visible))
1588    }
1589
1590    /// Moves the window with the left mouse button until the button is released.
1591    ///
1592    /// There's no guarantee that this will work unless the left mouse button was pressed
1593    /// immediately before this function is called.
1594    ///
1595    /// ## Platform-specific
1596    ///
1597    /// - **X11:** Un-grabs the cursor.
1598    /// - **Wayland:** Requires the cursor to be inside the window to be dragged.
1599    /// - **macOS:** May prevent the button release event to be triggered.
1600    /// - **iOS / Android / Web:** Always returns an [`ExternalError::NotSupported`].
1601    #[inline]
1602    pub fn drag_window(&self) -> Result<(), ExternalError> {
1603        let _span = tracing::debug_span!("rio_window::Window::drag_window",).entered();
1604        self.window.maybe_wait_on_main(|w| w.drag_window())
1605    }
1606
1607    /// Resizes the window with the left mouse button until the button is released.
1608    ///
1609    /// There's no guarantee that this will work unless the left mouse button was pressed
1610    /// immediately before this function is called.
1611    ///
1612    /// ## Platform-specific
1613    ///
1614    /// - **macOS:** Always returns an [`ExternalError::NotSupported`]
1615    /// - **iOS / Android / Web:** Always returns an [`ExternalError::NotSupported`].
1616    #[inline]
1617    pub fn drag_resize_window(
1618        &self,
1619        direction: ResizeDirection,
1620    ) -> Result<(), ExternalError> {
1621        let _span = tracing::debug_span!(
1622            "rio_window::Window::drag_resize_window",
1623            direction = ?direction
1624        )
1625        .entered();
1626        self.window
1627            .maybe_wait_on_main(|w| w.drag_resize_window(direction))
1628    }
1629
1630    /// Show [window menu] at a specified position .
1631    ///
1632    /// This is the context menu that is normally shown when interacting with
1633    /// the title bar. This is useful when implementing custom decorations.
1634    ///
1635    /// ## Platform-specific
1636    /// **Android / iOS / macOS / Orbital / Wayland / Web / X11:** Unsupported.
1637    ///
1638    /// [window menu]: https://en.wikipedia.org/wiki/Common_menus_in_Microsoft_Windows#System_menu
1639    pub fn show_window_menu(&self, position: impl Into<Position>) {
1640        let position = position.into();
1641        let _span = tracing::debug_span!(
1642            "rio_window::Window::show_window_menu",
1643            position = ?position
1644        )
1645        .entered();
1646        self.window
1647            .maybe_queue_on_main(move |w| w.show_window_menu(position))
1648    }
1649
1650    /// Modifies whether the window catches cursor events.
1651    ///
1652    /// If `true`, the window will catch the cursor events. If `false`, events are passed through
1653    /// the window such that any other window behind it receives them. By default hittest is
1654    /// enabled.
1655    ///
1656    /// ## Platform-specific
1657    ///
1658    /// - **iOS / Android / Web / Orbital:** Always returns an [`ExternalError::NotSupported`].
1659    #[inline]
1660    pub fn set_cursor_hittest(&self, hittest: bool) -> Result<(), ExternalError> {
1661        let _span =
1662            tracing::debug_span!("rio_window::Window::set_cursor_hittest", hittest)
1663                .entered();
1664        self.window
1665            .maybe_wait_on_main(|w| w.set_cursor_hittest(hittest))
1666    }
1667}
1668
1669/// Monitor info functions.
1670impl Window {
1671    /// Returns the monitor on which the window currently resides.
1672    ///
1673    /// Returns `None` if current monitor can't be detected.
1674    #[inline]
1675    pub fn current_monitor(&self) -> Option<MonitorHandle> {
1676        let _span =
1677            tracing::debug_span!("rio_window::Window::current_monitor",).entered();
1678        self.window.maybe_wait_on_main(|w| {
1679            w.current_monitor().map(|inner| MonitorHandle { inner })
1680        })
1681    }
1682
1683    /// Returns the list of all the monitors available on the system.
1684    ///
1685    /// This is the same as [`ActiveEventLoop::available_monitors`], and is provided for
1686    /// convenience.
1687    ///
1688    /// [`ActiveEventLoop::available_monitors`]: crate::event_loop::ActiveEventLoop::available_monitors
1689    #[inline]
1690    pub fn available_monitors(&self) -> impl Iterator<Item = MonitorHandle> {
1691        let _span =
1692            tracing::debug_span!("rio_window::Window::available_monitors",).entered();
1693        self.window.maybe_wait_on_main(|w| {
1694            w.available_monitors()
1695                .into_iter()
1696                .map(|inner| MonitorHandle { inner })
1697        })
1698    }
1699
1700    /// Returns the primary monitor of the system.
1701    ///
1702    /// Returns `None` if it can't identify any monitor as a primary one.
1703    ///
1704    /// This is the same as [`ActiveEventLoop::primary_monitor`], and is provided for convenience.
1705    ///
1706    /// ## Platform-specific
1707    ///
1708    /// **Wayland / Web:** Always returns `None`.
1709    ///
1710    /// [`ActiveEventLoop::primary_monitor`]: crate::event_loop::ActiveEventLoop::primary_monitor
1711    #[inline]
1712    pub fn primary_monitor(&self) -> Option<MonitorHandle> {
1713        let _span =
1714            tracing::debug_span!("rio_window::Window::primary_monitor",).entered();
1715        self.window.maybe_wait_on_main(|w| {
1716            w.primary_monitor().map(|inner| MonitorHandle { inner })
1717        })
1718    }
1719}
1720
1721impl raw_window_handle::HasWindowHandle for Window {
1722    fn window_handle(
1723        &self,
1724    ) -> Result<raw_window_handle::WindowHandle<'_>, raw_window_handle::HandleError> {
1725        let raw = self.window.raw_window_handle_raw_window_handle()?;
1726
1727        // SAFETY: The window handle will never be deallocated while the window is alive,
1728        // and the main thread safety requirements are upheld internally by each platform.
1729        Ok(unsafe { raw_window_handle::WindowHandle::borrow_raw(raw) })
1730    }
1731}
1732
1733impl raw_window_handle::HasDisplayHandle for Window {
1734    fn display_handle(
1735        &self,
1736    ) -> Result<raw_window_handle::DisplayHandle<'_>, raw_window_handle::HandleError>
1737    {
1738        let raw = self.window.raw_display_handle_raw_window_handle()?;
1739
1740        // SAFETY: The window handle will never be deallocated while the window is alive,
1741        // and the main thread safety requirements are upheld internally by each platform.
1742        Ok(unsafe { raw_window_handle::DisplayHandle::borrow_raw(raw) })
1743    }
1744}
1745
1746/// The behavior of cursor grabbing.
1747///
1748/// Use this enum with [`Window::set_cursor_grab`] to grab the cursor.
1749#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1750pub enum CursorGrabMode {
1751    /// No grabbing of the cursor is performed.
1752    None,
1753
1754    /// The cursor is confined to the window area.
1755    ///
1756    /// There's no guarantee that the cursor will be hidden. You should hide it by yourself if you
1757    /// want to do so.
1758    ///
1759    /// ## Platform-specific
1760    ///
1761    /// - **macOS:** Not implemented. Always returns [`ExternalError::NotSupported`] for now.
1762    /// - **iOS / Android / Web:** Always returns an [`ExternalError::NotSupported`].
1763    Confined,
1764
1765    /// The cursor is locked inside the window area to the certain position.
1766    ///
1767    /// There's no guarantee that the cursor will be hidden. You should hide it by yourself if you
1768    /// want to do so.
1769    ///
1770    /// ## Platform-specific
1771    ///
1772    /// - **X11 / Windows:** Not implemented. Always returns [`ExternalError::NotSupported`] for
1773    ///   now.
1774    /// - **iOS / Android:** Always returns an [`ExternalError::NotSupported`].
1775    Locked,
1776}
1777
1778/// Defines the orientation that a window resize will be performed.
1779#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1780pub enum ResizeDirection {
1781    East,
1782    North,
1783    NorthEast,
1784    NorthWest,
1785    South,
1786    SouthEast,
1787    SouthWest,
1788    West,
1789}
1790
1791impl From<ResizeDirection> for CursorIcon {
1792    fn from(direction: ResizeDirection) -> Self {
1793        use ResizeDirection::*;
1794        match direction {
1795            East => CursorIcon::EResize,
1796            North => CursorIcon::NResize,
1797            NorthEast => CursorIcon::NeResize,
1798            NorthWest => CursorIcon::NwResize,
1799            South => CursorIcon::SResize,
1800            SouthEast => CursorIcon::SeResize,
1801            SouthWest => CursorIcon::SwResize,
1802            West => CursorIcon::WResize,
1803        }
1804    }
1805}
1806
1807/// Fullscreen modes.
1808#[derive(Clone, Debug, PartialEq, Eq)]
1809pub enum Fullscreen {
1810    Exclusive(VideoModeHandle),
1811
1812    /// Providing `None` to `Borderless` will fullscreen on the current monitor.
1813    Borderless(Option<MonitorHandle>),
1814}
1815
1816/// The theme variant to use.
1817#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1818pub enum Theme {
1819    /// Use the light variant.
1820    Light,
1821
1822    /// Use the dark variant.
1823    Dark,
1824}
1825
1826/// ## Platform-specific
1827///
1828/// - **X11:** Sets the WM's `XUrgencyHint`. No distinction between [`Critical`] and
1829///   [`Informational`].
1830///
1831/// [`Critical`]: Self::Critical
1832/// [`Informational`]: Self::Informational
1833#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
1834pub enum UserAttentionType {
1835    /// ## Platform-specific
1836    ///
1837    /// - **macOS:** Bounces the dock icon until the application is in focus.
1838    /// - **Windows:** Flashes both the window and the taskbar button until the application is in
1839    ///   focus.
1840    Critical,
1841
1842    /// ## Platform-specific
1843    ///
1844    /// - **macOS:** Bounces the dock icon once.
1845    /// - **Windows:** Flashes the taskbar button until the application is in focus.
1846    #[default]
1847    Informational,
1848}
1849
1850bitflags::bitflags! {
1851    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1852    pub struct WindowButtons: u32 {
1853        const CLOSE  = 1 << 0;
1854        const MINIMIZE  = 1 << 1;
1855        const MAXIMIZE  = 1 << 2;
1856    }
1857}
1858
1859/// A window level groups windows with respect to their z-position.
1860///
1861/// The relative ordering between windows in different window levels is fixed.
1862/// The z-order of a window within the same window level may change dynamically on user interaction.
1863///
1864/// ## Platform-specific
1865///
1866/// - **iOS / Android / Web / Wayland:** Unsupported.
1867#[derive(Debug, Default, PartialEq, Eq, Clone, Copy)]
1868pub enum WindowLevel {
1869    /// The window will always be below normal windows.
1870    ///
1871    /// This is useful for a widget-based app.
1872    AlwaysOnBottom,
1873
1874    /// The default.
1875    #[default]
1876    Normal,
1877
1878    /// The window will always be on top of normal windows.
1879    AlwaysOnTop,
1880}
1881
1882/// Generic IME purposes for use in [`Window::set_ime_purpose`].
1883///
1884/// The purpose may improve UX by optimizing the IME for the specific use case,
1885/// if winit can express the purpose to the platform and the platform reacts accordingly.
1886///
1887/// ## Platform-specific
1888///
1889/// - **iOS / Android / Web / Windows / X11 / macOS / Orbital:** Unsupported.
1890#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
1891#[non_exhaustive]
1892pub enum ImePurpose {
1893    /// No special hints for the IME (default).
1894    #[default]
1895    Normal,
1896    /// The IME is used for password input.
1897    Password,
1898    /// The IME is used to input into a terminal.
1899    ///
1900    /// For example, that could alter OSK on Wayland to show extra buttons.
1901    Terminal,
1902}
1903
1904/// An opaque token used to activate the [`Window`].
1905///
1906/// [`Window`]: crate::window::Window
1907#[derive(Debug, PartialEq, Eq, Clone)]
1908pub struct ActivationToken {
1909    pub(crate) _token: String,
1910}
1911
1912impl ActivationToken {
1913    pub(crate) fn _new(_token: String) -> Self {
1914        Self { _token }
1915    }
1916}