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}