rio_window/
window.rs

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