tao/window.rs
1// Copyright 2014-2021 The winit contributors
2// Copyright 2021-2023 Tauri Programme within The Commons Conservancy
3// SPDX-License-Identifier: Apache-2.0
4
5//! The `Window` struct and associated types.
6use std::fmt;
7
8use crate::{
9 dpi::{LogicalSize, PhysicalPosition, PhysicalSize, Pixel, PixelUnit, Position, Size},
10 error::{ExternalError, NotSupportedError, OsError},
11 event_loop::EventLoopWindowTarget,
12 monitor::{MonitorHandle, VideoMode},
13 platform_impl,
14};
15
16pub use crate::icon::{BadIcon, Icon};
17
18/// Progress State
19#[derive(Debug, Clone, Copy)]
20pub enum ProgressState {
21 None,
22 Normal,
23 /// **Treated as Normal in linux and macOS**
24 Indeterminate,
25 /// **Treated as Normal in linux**
26 Paused,
27 /// **Treated as Normal in linux**
28 Error,
29}
30
31pub struct ProgressBarState {
32 /// The progress bar state.
33 pub state: Option<ProgressState>,
34 /// The progress bar progress. This can be a value ranging from `0` to `100`
35 pub progress: Option<u64>,
36 /// The `.desktop` filename with the Unity desktop window manager, for example `myapp.desktop` **Linux Only**
37 pub desktop_filename: Option<String>,
38}
39
40/// Represents a window.
41///
42/// # Example
43///
44/// ```no_run
45/// use tao::{
46/// event::{Event, WindowEvent},
47/// event_loop::{ControlFlow, EventLoop},
48/// window::Window,
49/// };
50///
51/// let mut event_loop = EventLoop::new();
52/// let window = Window::new(&event_loop).unwrap();
53///
54/// event_loop.run(move |event, _, control_flow| {
55/// *control_flow = ControlFlow::Wait;
56///
57/// match event {
58/// Event::WindowEvent {
59/// event: WindowEvent::CloseRequested,
60/// ..
61/// } => *control_flow = ControlFlow::Exit,
62/// _ => (),
63/// }
64/// });
65/// ```
66pub struct Window {
67 pub(crate) window: platform_impl::Window,
68}
69
70impl fmt::Debug for Window {
71 fn fmt(&self, fmtr: &mut fmt::Formatter<'_>) -> fmt::Result {
72 fmtr.pad("Window { .. }")
73 }
74}
75
76impl Drop for Window {
77 fn drop(&mut self) {
78 // If the window is in exclusive fullscreen, we must restore the desktop
79 // video mode (generally this would be done on application exit, but
80 // closing the window doesn't necessarily always mean application exit,
81 // such as when there are multiple windows)
82 if let Some(Fullscreen::Exclusive(_)) = self.fullscreen() {
83 self.set_fullscreen(None);
84 }
85 }
86}
87
88/// Type alias for a color in the RGBA format.
89///
90/// Each value can be 0..255 inclusive.
91pub type RGBA = (u8, u8, u8, u8);
92
93/// Identifier of a window. Unique for each window.
94///
95/// Can be obtained with `window.id()`.
96///
97/// Whenever you receive an event specific to a window, this event contains a `WindowId` which you
98/// can then compare to the ids of your windows.
99#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
100pub struct WindowId(pub(crate) platform_impl::WindowId);
101
102impl WindowId {
103 /// # Safety
104 /// Returns a dummy `WindowId`, useful for unit testing. The only guarantee made about the return
105 /// value of this function is that it will always be equal to itself and to future values returned
106 /// by this function. No other guarantees are made. This may be equal to a real `WindowId`.
107 ///
108 /// **Passing this into a tao function will result in undefined behavior.**
109 pub unsafe fn dummy() -> Self {
110 WindowId(platform_impl::WindowId::dummy())
111 }
112}
113
114/// Object that allows you to build windows.
115#[derive(Clone, Default)]
116pub struct WindowBuilder {
117 /// The attributes to use to create the window.
118 pub window: WindowAttributes,
119
120 // Platform-specific configuration.
121 pub(crate) platform_specific: platform_impl::PlatformSpecificWindowBuilderAttributes,
122}
123
124impl fmt::Debug for WindowBuilder {
125 fn fmt(&self, fmtr: &mut fmt::Formatter<'_>) -> fmt::Result {
126 fmtr
127 .debug_struct("WindowBuilder")
128 .field("window", &self.window)
129 .finish()
130 }
131}
132
133/// Attributes to use when creating a window.
134#[derive(Debug, Clone)]
135pub struct WindowAttributes {
136 /// The dimensions of the window. If this is `None`, some platform-specific dimensions will be
137 /// used.
138 ///
139 /// The default is `None`.
140 pub inner_size: Option<Size>,
141
142 /// The window size constraints
143 pub inner_size_constraints: WindowSizeConstraints,
144
145 /// The desired position of the window. If this is `None`, some platform-specific position
146 /// will be chosen.
147 ///
148 /// The default is `None`.
149 ///
150 /// ## Platform-specific
151 ///
152 /// - **macOS**: The top left corner position of the window content, the window's "inner"
153 /// position. The window title bar will be placed above it.
154 /// The window will be positioned such that it fits on screen, maintaining
155 /// set `inner_size` if any.
156 /// If you need to precisely position the top left corner of the whole window you have to
157 /// use [`Window::set_outer_position`] after creating the window.
158 /// - **Windows**: The top left corner position of the window title bar, the window's "outer"
159 /// position.
160 /// There may be a small gap between this position and the window due to the specifics of the
161 /// Window Manager.
162 /// - **Linux**: The top left corner of the window, the window's "outer" position.
163 /// - **Linux(Wayland)**: Unsupported.
164 /// - **Others**: Ignored.
165 ///
166 /// See [`Window::set_outer_position`].
167 ///
168 /// [`Window::set_outer_position`]: crate::window::Window::set_outer_position
169 pub position: Option<Position>,
170
171 /// Whether the window is resizable or not.
172 ///
173 /// The default is `true`.
174 pub resizable: bool,
175
176 /// Whether the window is minimizable or not.
177 ///
178 /// The default is `true`.
179 ///
180 /// See [`Window::set_minimizable`] for details.
181 pub minimizable: bool,
182
183 /// Whether the window is maximizable or not.
184 ///
185 /// The default is `true`.
186 ///
187 /// See [`Window::set_maximizable`] for details.
188 pub maximizable: bool,
189
190 /// Whether the window is closable or not.
191 ///
192 /// The default is `true`.
193 ///
194 /// See [`Window::set_closable`] for details.
195 pub closable: bool,
196
197 /// Whether the window should be set as fullscreen upon creation.
198 ///
199 /// The default is `None`.
200 pub fullscreen: Option<Fullscreen>,
201
202 /// The title of the window in the title bar.
203 ///
204 /// The default is `"tao window"`.
205 pub title: String,
206
207 /// Whether the window should be maximized upon creation.
208 ///
209 /// The default is `false`.
210 pub maximized: bool,
211
212 /// Whether the window should be immediately visible upon creation.
213 ///
214 /// The default is `true`.
215 pub visible: bool,
216
217 /// Whether the the window should be transparent. If this is true, writing colors
218 /// with alpha values different than `1.0` will produce a transparent window.
219 ///
220 /// The default is `false`.
221 pub transparent: bool,
222
223 /// Whether the window should have borders and bars.
224 ///
225 /// The default is `true`.
226 pub decorations: bool,
227
228 /// Whether the window should always be on top of other windows.
229 ///
230 /// The default is `false`.
231 ///
232 /// ## Platform-specific:
233 ///
234 /// - **Linux(x11):** Result depends on the system's window manager. Consider this setting a suggestion.
235 /// - **Linux(Wayland):** Unsupported.
236 // TODO: Unsupported in gtk4
237 pub always_on_top: bool,
238
239 /// Whether the window should always be on bottom of other windows.
240 ///
241 /// The default is `false`.
242 ///
243 /// ## Platform-specific:
244 ///
245 /// - **Linux(x11):** Result depends on the system's window manager. Consider this setting a suggestion.
246 /// - **Linux(Wayland):** Unsupported.
247 // TODO: Unsupported in gtk4
248 pub always_on_bottom: bool,
249
250 /// The window icon.
251 ///
252 /// The default is `None`.
253 pub window_icon: Option<Icon>,
254
255 pub preferred_theme: Option<Theme>,
256
257 /// Whether the window should be initially focused or not.
258 ///
259 /// ## Platform-specific:
260 ///
261 /// **Android / iOS:** Unsupported.
262 pub focused: bool,
263
264 /// Whether the window should be focusable or not.
265 ///
266 /// ## Platform-specific:
267 ///
268 /// **Android / iOS:** Unsupported.
269 pub focusable: bool,
270
271 /// Prevents the window contents from being captured by other apps.
272 ///
273 /// ## Platform-specific
274 ///
275 /// - **iOS / Android / Linux:** Unsupported.
276 pub content_protection: bool,
277
278 /// Sets whether the window should be visible on all workspaces.
279 ///
280 /// ## Platform-specific
281 ///
282 /// - **iOS / Android / Windows:** Unsupported.
283 pub visible_on_all_workspaces: bool,
284
285 /// Sets the window background color.
286 ///
287 /// ## Platform-specific:
288 ///
289 /// - **Windows:** alpha channel is ignored. Instead manually draw the window, for example using `softbuffer` crate, see <https://github.com/tauri-apps/tao/blob/dev/examples/transparent.rs>
290 /// - **iOS / Android:** Unsupported.
291 pub background_color: Option<RGBA>,
292}
293
294impl Default for WindowAttributes {
295 #[inline]
296 fn default() -> WindowAttributes {
297 WindowAttributes {
298 inner_size: None,
299 inner_size_constraints: Default::default(),
300 position: None,
301 resizable: true,
302 minimizable: true,
303 maximizable: true,
304 closable: true,
305 title: "tao window".to_owned(),
306 maximized: false,
307 fullscreen: None,
308 visible: true,
309 transparent: false,
310 decorations: true,
311 always_on_top: false,
312 always_on_bottom: false,
313 window_icon: None,
314 preferred_theme: None,
315 focused: true,
316 focusable: true,
317 content_protection: false,
318 visible_on_all_workspaces: false,
319 background_color: None,
320 }
321 }
322}
323
324impl WindowBuilder {
325 /// Initializes a new `WindowBuilder` with default values.
326 #[inline]
327 pub fn new() -> Self {
328 Default::default()
329 }
330
331 /// Requests the window to be of specific dimensions.
332 ///
333 /// See [`Window::set_inner_size`] for details.
334 ///
335 /// [`Window::set_inner_size`]: crate::window::Window::set_inner_size
336 #[inline]
337 pub fn with_inner_size<S: Into<Size>>(mut self, size: S) -> Self {
338 self.window.inner_size = Some(size.into());
339 self
340 }
341
342 /// Sets a minimum dimension size for the window.
343 ///
344 /// See [`Window::set_min_inner_size`] for details.
345 ///
346 /// [`Window::set_min_inner_size`]: crate::window::Window::set_min_inner_size
347 #[inline]
348 pub fn with_min_inner_size<S: Into<Size>>(mut self, min_size: S) -> Self {
349 let size: Size = min_size.into();
350 let (width, height) = crate::extract_width_height(size);
351 self.window.inner_size_constraints.min_width = Some(width);
352 self.window.inner_size_constraints.min_height = Some(height);
353 self
354 }
355
356 /// Sets a maximum dimension size for the window.
357 ///
358 /// See [`Window::set_max_inner_size`] for details.
359 ///
360 /// [`Window::set_max_inner_size`]: crate::window::Window::set_max_inner_size
361 #[inline]
362 pub fn with_max_inner_size<S: Into<Size>>(mut self, max_size: S) -> Self {
363 let size: Size = max_size.into();
364 let (width, height) = crate::extract_width_height(size);
365 self.window.inner_size_constraints.max_width = Some(width);
366 self.window.inner_size_constraints.max_height = Some(height);
367 self
368 }
369
370 /// Sets inner size constraints for the window.
371 ///
372 /// See [`Window::set_inner_size_constraints`] for details.
373 ///
374 /// [`Window::set_inner_size_constraints`]: crate::window::Window::set_inner_size_constraints
375 #[inline]
376 pub fn with_inner_size_constraints(mut self, constraints: WindowSizeConstraints) -> Self {
377 self.window.inner_size_constraints = constraints;
378 self
379 }
380
381 /// Sets a desired initial position for the window.
382 ///
383 /// See [`WindowAttributes::position`] for details.
384 ///
385 /// [`WindowAttributes::position`]: crate::window::WindowAttributes::position
386 #[inline]
387 pub fn with_position<P: Into<Position>>(mut self, position: P) -> Self {
388 self.window.position = Some(position.into());
389 self
390 }
391
392 /// Sets whether the window is resizable or not.
393 ///
394 /// See [`Window::set_resizable`] for details.
395 ///
396 /// [`Window::set_resizable`]: crate::window::Window::set_resizable
397 #[inline]
398 pub fn with_resizable(mut self, resizable: bool) -> Self {
399 self.window.resizable = resizable;
400 self
401 }
402
403 /// Sets whether the window is minimizable or not.
404 ///
405 /// See [`Window::set_minimizable`] for details.
406 ///
407 /// [`Window::set_minimizable`]: crate::window::Window::set_minimizable
408 #[inline]
409 pub fn with_minimizable(mut self, minimizable: bool) -> Self {
410 self.window.minimizable = minimizable;
411 self
412 }
413
414 /// Sets whether the window is maximizable or not.
415 ///
416 /// See [`Window::set_maximizable`] for details.
417 ///
418 /// [`Window::set_maximizable`]: crate::window::Window::set_maximizable
419 #[inline]
420 pub fn with_maximizable(mut self, maximizable: bool) -> Self {
421 self.window.maximizable = maximizable;
422 self
423 }
424
425 /// Sets whether the window is closable or not.
426 ///
427 /// See [`Window::set_closable`] for details.
428 ///
429 /// [`Window::set_closable`]: crate::window::Window::set_closable
430 #[inline]
431 pub fn with_closable(mut self, closable: bool) -> Self {
432 self.window.closable = closable;
433 self
434 }
435
436 /// Requests a specific title for the window.
437 ///
438 /// See [`Window::set_title`] for details.
439 ///
440 /// [`Window::set_title`]: crate::window::Window::set_title
441 #[inline]
442 pub fn with_title<T: Into<String>>(mut self, title: T) -> Self {
443 self.window.title = title.into();
444 self
445 }
446
447 /// Sets the window fullscreen state.
448 ///
449 /// See [`Window::set_fullscreen`] for details.
450 ///
451 /// [`Window::set_fullscreen`]: crate::window::Window::set_fullscreen
452 #[inline]
453 pub fn with_fullscreen(mut self, fullscreen: Option<Fullscreen>) -> Self {
454 self.window.fullscreen = fullscreen;
455 self
456 }
457
458 /// Requests maximized mode.
459 ///
460 /// See [`Window::set_maximized`] for details.
461 ///
462 /// [`Window::set_maximized`]: crate::window::Window::set_maximized
463 #[inline]
464 pub fn with_maximized(mut self, maximized: bool) -> Self {
465 self.window.maximized = maximized;
466 self
467 }
468
469 /// Sets whether the window will be initially hidden or visible.
470 ///
471 /// See [`Window::set_visible`] for details.
472 ///
473 /// [`Window::set_visible`]: crate::window::Window::set_visible
474 #[inline]
475 pub fn with_visible(mut self, visible: bool) -> Self {
476 self.window.visible = visible;
477 self
478 }
479
480 /// Sets whether the background of the window should be transparent.
481 #[inline]
482 pub fn with_transparent(mut self, transparent: bool) -> Self {
483 self.window.transparent = transparent;
484 self
485 }
486
487 /// Sets whether the window should have a border, a title bar, etc.
488 ///
489 /// See [`Window::set_decorations`] for details.
490 ///
491 /// [`Window::set_decorations`]: crate::window::Window::set_decorations
492 #[inline]
493 pub fn with_decorations(mut self, decorations: bool) -> Self {
494 self.window.decorations = decorations;
495 self
496 }
497
498 /// Sets whether or not the window will always be below other windows.
499 ///
500 /// See [`Window::set_always_on_bottom`] for details.
501 ///
502 /// [`Window::set_always_on_bottom`]: crate::window::Window::set_always_on_bottom
503 #[inline]
504 pub fn with_always_on_bottom(mut self, always_on_bottom: bool) -> Self {
505 self.window.always_on_top = false;
506 self.window.always_on_bottom = always_on_bottom;
507 self
508 }
509
510 /// Sets whether or not the window will always be on top of other windows.
511 ///
512 /// See [`Window::set_always_on_top`] for details.
513 ///
514 /// [`Window::set_always_on_top`]: crate::window::Window::set_always_on_top
515 #[inline]
516 pub fn with_always_on_top(mut self, always_on_top: bool) -> Self {
517 self.window.always_on_bottom = false;
518 self.window.always_on_top = always_on_top;
519 self
520 }
521
522 /// Sets the window icon.
523 ///
524 /// See [`Window::set_window_icon`] for details.
525 ///
526 /// [`Window::set_window_icon`]: crate::window::Window::set_window_icon
527 #[inline]
528 pub fn with_window_icon(mut self, window_icon: Option<Icon>) -> Self {
529 self.window.window_icon = window_icon;
530 self
531 }
532
533 /// Forces a theme or uses the system settings if `None` was provided.
534 ///
535 /// ## Platform-specific:
536 ///
537 /// - **Windows**: It is recommended to always use the same theme used
538 /// in [`EventLoopBuilderExtWindows::with_theme`] for this method also
539 /// or use `None` so it automatically uses the theme used in [`EventLoopBuilderExtWindows::with_theme`]
540 /// or falls back to the system preference, because [`EventLoopBuilderExtWindows::with_theme`] changes
541 /// the theme for some controls like context menus which is app-wide and can't be changed by this method.
542 ///
543 /// [`EventLoopBuilderExtWindows::with_theme`]: crate::platform::windows::EventLoopBuilderExtWindows::with_theme
544 #[allow(rustdoc::broken_intra_doc_links)]
545 #[inline]
546 pub fn with_theme(mut self, theme: Option<Theme>) -> WindowBuilder {
547 self.window.preferred_theme = theme;
548 self
549 }
550
551 /// Whether the window will be initially focused or not.
552 ///
553 /// ## Platform-specific:
554 ///
555 /// **Android / iOS:** Unsupported.
556 #[inline]
557 pub fn with_focused(mut self, focused: bool) -> WindowBuilder {
558 self.window.focused = focused;
559 self
560 }
561
562 /// Whether the window will be focusable or not.
563 ///
564 /// ## Platform-specific:
565 /// **Android / iOS:** Unsupported.
566 #[inline]
567 pub fn with_focusable(mut self, focusable: bool) -> WindowBuilder {
568 self.window.focusable = focusable;
569 self
570 }
571
572 /// Prevents the window contents from being captured by other apps.
573 ///
574 /// ## Platform-specific
575 ///
576 /// - **iOS / Android / Linux:** Unsupported.
577 #[inline]
578 pub fn with_content_protection(mut self, protected: bool) -> WindowBuilder {
579 self.window.content_protection = protected;
580 self
581 }
582
583 /// Sets whether the window should be visible on all workspaces.
584 ///
585 /// ## Platform-specific
586 ///
587 /// - **iOS / Android / Windows:** Unsupported.
588 #[inline]
589 pub fn with_visible_on_all_workspaces(mut self, visible: bool) -> WindowBuilder {
590 self.window.visible_on_all_workspaces = visible;
591 self
592 }
593
594 /// Sets the window background color.
595 ///
596 /// ## Platform-specific:
597 ///
598 /// - **Windows:** alpha channel is ignored. Instead manually draw the window, for example using `softbuffer` crate, see <https://github.com/tauri-apps/tao/blob/dev/examples/transparent.rs>
599 /// - **iOS / Android:** Unsupported.
600 #[inline]
601 pub fn with_background_color(mut self, color: RGBA) -> WindowBuilder {
602 self.window.background_color = Some(color);
603 self
604 }
605
606 /// Builds the window.
607 ///
608 /// Possible causes of error include denied permission, incompatible system, and lack of memory.
609 #[inline]
610 pub fn build<T: 'static>(
611 self,
612 window_target: &EventLoopWindowTarget<T>,
613 ) -> Result<Window, OsError> {
614 platform_impl::Window::new(&window_target.p, self.window, self.platform_specific).map(
615 |window| {
616 window.request_redraw();
617 Window { window }
618 },
619 )
620 }
621}
622
623/// Base Window functions.
624impl Window {
625 /// Creates a new Window for platforms where this is appropriate.
626 ///
627 /// This function is equivalent to [`WindowBuilder::new().build(event_loop)`].
628 ///
629 /// Error should be very rare and only occur in case of permission denied, incompatible system,
630 /// out of memory, etc.
631 ///
632 /// [`WindowBuilder::new().build(event_loop)`]: crate::window::WindowBuilder::build
633 #[inline]
634 pub fn new<T: 'static>(event_loop: &EventLoopWindowTarget<T>) -> Result<Window, OsError> {
635 let builder = WindowBuilder::new();
636 builder.build(event_loop)
637 }
638
639 /// Returns an identifier unique to the window.
640 #[inline]
641 pub fn id(&self) -> WindowId {
642 WindowId(self.window.id())
643 }
644
645 /// Returns the scale factor that can be used to map logical pixels to physical pixels, and vice versa.
646 ///
647 /// See the [`dpi`](crate::dpi) module for more information.
648 ///
649 /// Note that this value can change depending on user action (for example if the window is
650 /// moved to another screen); as such, tracking `WindowEvent::ScaleFactorChanged` events is
651 /// the most robust way to track the DPI you need to use to draw.
652 ///
653 /// ## Platform-specific
654 ///
655 /// - **Android:** Always returns 1.0.
656 /// - **iOS:** Can only be called on the main thread. Returns the underlying `UIView`'s
657 /// [`contentScaleFactor`].
658 ///
659 /// [`contentScaleFactor`]: https://developer.apple.com/documentation/uikit/uiview/1622657-contentscalefactor?language=objc
660 #[inline]
661 pub fn scale_factor(&self) -> f64 {
662 self.window.scale_factor()
663 }
664
665 /// Emits a `WindowEvent::RedrawRequested` event in the associated event loop after all OS
666 /// events have been processed by the event loop.
667 ///
668 /// This is the **strongly encouraged** method of redrawing windows, as it can integrate with
669 /// OS-requested redraws (e.g. when a window gets resized).
670 ///
671 /// This function can cause `RedrawRequested` events to be emitted after `Event::MainEventsCleared`
672 /// but before `Event::NewEvents` if called in the following circumstances:
673 /// * While processing `MainEventsCleared`.
674 /// * While processing a `RedrawRequested` event that was sent during `MainEventsCleared` or any
675 /// directly subsequent `RedrawRequested` event.
676 ///
677 /// ## Platform-specific
678 ///
679 /// - **iOS:** Can only be called on the main thread.
680 /// - **Android:** Unsupported.
681 #[inline]
682 pub fn request_redraw(&self) {
683 self.window.request_redraw()
684 }
685}
686
687/// Position and size functions.
688impl Window {
689 /// Returns the position of the top-left hand corner of the window's client area relative to the
690 /// top-left hand corner of the desktop.
691 ///
692 /// The same conditions that apply to `outer_position` apply to this method.
693 ///
694 /// ## Platform-specific
695 ///
696 /// - **iOS:** Can only be called on the main thread. Returns the top left coordinates of the
697 /// window's [safe area] in the screen space coordinate system.
698 /// - **Android:** Always returns [`NotSupportedError`].
699 ///
700 /// [safe area]: https://developer.apple.com/documentation/uikit/uiview/2891103-safeareainsets?language=objc
701 #[inline]
702 pub fn inner_position(&self) -> Result<PhysicalPosition<i32>, NotSupportedError> {
703 self.window.inner_position()
704 }
705
706 /// Returns the position of the top-left hand corner of the window relative to the
707 /// top-left hand corner of the desktop.
708 ///
709 /// Note that the top-left hand corner of the desktop is not necessarily the same as
710 /// the screen. If the user uses a desktop with multiple monitors, the top-left hand corner
711 /// of the desktop is the top-left hand corner of the monitor at the top-left of the desktop.
712 ///
713 /// The coordinates can be negative if the top-left hand corner of the window is outside
714 /// of the visible screen region.
715 ///
716 /// ## Platform-specific
717 ///
718 /// - **iOS:** Can only be called on the main thread. Returns the top left coordinates of the
719 /// window in the screen space coordinate system.
720 /// - **Android:** Always returns [`NotSupportedError`].
721 /// - **Linux(Wayland)**: Has no effect, since Wayland doesn't support a global cordinate system
722 #[inline]
723 pub fn outer_position(&self) -> Result<PhysicalPosition<i32>, NotSupportedError> {
724 self.window.outer_position()
725 }
726
727 /// Modifies the position of the window.
728 ///
729 /// See `outer_position` for more information about the coordinates. This automatically un-maximizes the
730 /// window if it's maximized.
731 ///
732 /// ## Platform-specific
733 ///
734 /// - **iOS:** Can only be called on the main thread. Sets the top left coordinates of the
735 /// window in the screen space coordinate system.
736 /// - **Android / Linux(Wayland):** Unsupported.
737 #[inline]
738 pub fn set_outer_position<P: Into<Position>>(&self, position: P) {
739 self.window.set_outer_position(position.into())
740 }
741
742 /// Returns the physical size of the window's client area.
743 ///
744 /// The client area is the content of the window, excluding the title bar and borders.
745 ///
746 /// ## Platform-specific
747 ///
748 /// - **iOS:** Can only be called on the main thread. Returns the `PhysicalSize` of the window's
749 /// [safe area] in screen space coordinates.
750 ///
751 /// [safe area]: https://developer.apple.com/documentation/uikit/uiview/2891103-safeareainsets?language=objc
752 #[inline]
753 pub fn inner_size(&self) -> PhysicalSize<u32> {
754 self.window.inner_size()
755 }
756
757 /// Modifies the inner size of the window.
758 ///
759 /// See `inner_size` for more information about the values. This automatically un-maximizes the
760 /// window if it's maximized.
761 ///
762 /// ## Platform-specific
763 ///
764 /// - **iOS / Android:** Unsupported.
765 #[inline]
766 pub fn set_inner_size<S: Into<Size>>(&self, size: S) {
767 self.window.set_inner_size(size.into())
768 }
769
770 /// Returns the physical size of the entire window.
771 ///
772 /// These dimensions include the title bar and borders. If you don't want that (and you usually don't),
773 /// use `inner_size` instead.
774 ///
775 /// ## Platform-specific
776 ///
777 /// - **iOS:** Can only be called on the main thread. Returns the `PhysicalSize` of the window in
778 /// screen space coordinates.
779 #[inline]
780 pub fn outer_size(&self) -> PhysicalSize<u32> {
781 self.window.outer_size()
782 }
783
784 /// Sets a minimum dimension size for the window.
785 ///
786 /// ## Platform-specific
787 ///
788 /// - **iOS / Android:** Unsupported.
789 #[inline]
790 pub fn set_min_inner_size<S: Into<Size>>(&self, min_size: Option<S>) {
791 self.window.set_min_inner_size(min_size.map(|s| s.into()))
792 }
793
794 /// Sets a maximum dimension size for the window.
795 ///
796 /// ## Platform-specific
797 ///
798 /// - **iOS / Android:** Unsupported.
799 #[inline]
800 pub fn set_max_inner_size<S: Into<Size>>(&self, max_size: Option<S>) {
801 self.window.set_max_inner_size(max_size.map(|s| s.into()))
802 }
803
804 /// Sets inner size constraints for the window.
805 ///
806 /// ## Platform-specific
807 ///
808 /// - **iOS / Android:** Unsupported.
809 #[inline]
810 pub fn set_inner_size_constraints(&self, constraints: WindowSizeConstraints) {
811 self.window.set_inner_size_constraints(constraints)
812 }
813}
814
815/// Misc. attribute functions.
816impl Window {
817 /// Modifies the title of the window.
818 ///
819 /// ## Platform-specific
820 ///
821 /// - **iOS / Android:** Unsupported.
822 #[inline]
823 pub fn set_title(&self, title: &str) {
824 self.window.set_title(title)
825 }
826
827 /// Gets the current title of the window.
828 ///
829 /// ## Platform-specific
830 ///
831 /// - **iOS / Android:** Unsupported. Returns ane empty string.
832 #[inline]
833 pub fn title(&self) -> String {
834 self.window.title()
835 }
836
837 /// Modifies the window's visibility.
838 ///
839 /// If `false`, this will hide the window. If `true`, this will show the window.
840 /// ## Platform-specific
841 ///
842 /// - **Android:** Unsupported.
843 /// - **iOS:** Can only be called on the main thread.
844 #[inline]
845 pub fn set_visible(&self, visible: bool) {
846 self.window.set_visible(visible)
847 }
848
849 /// Bring the window to front and focus.
850 ///
851 /// ## Platform-specific
852 ///
853 /// - **iOS / Android:** Unsupported.
854 #[inline]
855 pub fn set_focus(&self) {
856 self.window.set_focus()
857 }
858
859 /// Sets whether the window is focusable or not.
860 ///
861 /// ## Platform-specific
862 ///
863 /// - **macOS**: If the window is already focused, it is not possible to unfocus it after calling `set_focusable(false)`.
864 /// In this case, you might consider calling [`Window::set_focus`] but it will move the window to the back i.e. at the bottom in terms of z-order.
865 /// - **iOS / Android:** Unsupported.
866 #[inline]
867 pub fn set_focusable(&self, focusable: bool) {
868 self.window.set_focusable(focusable)
869 }
870
871 /// Is window active and focused?
872 ///
873 /// ## Platform-specific
874 ///
875 /// - **iOS / Android:** Unsupported.
876 #[inline]
877 pub fn is_focused(&self) -> bool {
878 self.window.is_focused()
879 }
880
881 /// Indicates whether the window is always on top of other windows.
882 ///
883 /// ## Platform-specific
884 ///
885 /// - **iOS / Android:** Unsupported.
886 #[inline]
887 pub fn is_always_on_top(&self) -> bool {
888 self.window.is_always_on_top()
889 }
890
891 /// Sets whether the window is resizable or not.
892 ///
893 /// Note that making the window unresizable doesn't exempt you from handling `Resized`, as that event can still be
894 /// triggered by DPI scaling, entering fullscreen mode, etc.
895 ///
896 /// ## Platform-specific
897 ///
898 /// This only has an effect on desktop platforms.
899 ///
900 /// Due to a bug in XFCE, this has no effect on Xfwm.
901 ///
902 /// ## Platform-specific
903 ///
904 /// - **Linux:** Most size methods like maximized are async and do not work well with calling
905 /// sequentailly. For setting inner or outer size, you don't need to set resizable to true before
906 /// it. It can resize no matter what. But if you insist to do so, it has a `100, 100` minimum
907 /// limitation somehow. For maximizing, it requires resizable is true. If you really want to set
908 /// resizable to false after it. You might need a mechanism to check the window is really
909 /// maximized.
910 /// - **iOS / Android:** Unsupported.
911 #[inline]
912 pub fn set_resizable(&self, resizable: bool) {
913 self.window.set_resizable(resizable)
914 }
915
916 /// Sets whether the window is minimizable or not.
917 ///
918 /// ## Platform-specific
919 ///
920 /// - **Linux / iOS / Android:** Unsupported.
921 #[inline]
922 pub fn set_minimizable(&self, minimizable: bool) {
923 self.window.set_minimizable(minimizable)
924 }
925
926 /// Sets whether the window is maximizable or not.
927 ///
928 /// ## Platform-specific
929 ///
930 /// - **macOS:** Disables the "zoom" button in the window titlebar, which is also used to enter fullscreen mode.
931 /// - **Linux / iOS / Android:** Unsupported.
932 #[inline]
933 pub fn set_maximizable(&self, maximizable: bool) {
934 self.window.set_maximizable(maximizable)
935 }
936
937 /// Sets whether the window is closable or not.
938 ///
939 /// ## Platform-specific
940 ///
941 /// - **Linux:** "GTK+ will do its best to convince the window manager not to show a close button.
942 /// Depending on the system, this function may not have any effect when called on a window that is already visible"
943 /// - **iOS / Android:** Unsupported.
944 #[inline]
945 pub fn set_closable(&self, closable: bool) {
946 self.window.set_closable(closable)
947 }
948
949 /// Sets the window to minimized or back
950 ///
951 /// ## Platform-specific
952 ///
953 /// - **iOS / Android:** Unsupported.
954 #[inline]
955 pub fn set_minimized(&self, minimized: bool) {
956 self.window.set_minimized(minimized);
957 }
958
959 /// Sets the window to maximized or back.
960 ///
961 /// ## Platform-specific
962 ///
963 /// - **iOS / Android:** Unsupported.
964 #[inline]
965 pub fn set_maximized(&self, maximized: bool) {
966 self.window.set_maximized(maximized)
967 }
968
969 /// Gets the window's current maximized state.
970 ///
971 /// ## Platform-specific
972 ///
973 /// - **iOS / Android:** Unsupported.
974 #[inline]
975 pub fn is_maximized(&self) -> bool {
976 self.window.is_maximized()
977 }
978
979 /// Gets the window's current minimized state.
980 ///
981 /// ## Platform-specific
982 ///
983 /// - **iOS / Android:** Unsupported.
984 #[inline]
985 pub fn is_minimized(&self) -> bool {
986 self.window.is_minimized()
987 }
988
989 /// Gets the window's current visibility state.
990 ///
991 /// ## Platform-specific
992 ///
993 /// - **iOS / Android:** Unsupported.
994 #[inline]
995 pub fn is_visible(&self) -> bool {
996 self.window.is_visible()
997 }
998
999 /// Gets the window's current resizable state.
1000 ///
1001 /// ## Platform-specific
1002 ///
1003 /// - **iOS / Android:** Unsupported.
1004 #[inline]
1005 pub fn is_resizable(&self) -> bool {
1006 self.window.is_resizable()
1007 }
1008
1009 /// Gets the window's current minimizable state.
1010 ///
1011 /// ## Platform-specific
1012 ///
1013 /// - **Linux / iOS / Android:** Unsupported.
1014 #[inline]
1015 pub fn is_minimizable(&self) -> bool {
1016 self.window.is_minimizable()
1017 }
1018
1019 /// Gets the window's current maximizable state.
1020 ///
1021 /// ## Platform-specific
1022 ///
1023 /// - **Linux / iOS / Android:** Unsupported.
1024 #[inline]
1025 pub fn is_maximizable(&self) -> bool {
1026 self.window.is_maximizable()
1027 }
1028
1029 /// Gets the window's current closable state.
1030 ///
1031 /// ## Platform-specific
1032 ///
1033 /// - **iOS / Android:** Unsupported.
1034 #[inline]
1035 pub fn is_closable(&self) -> bool {
1036 self.window.is_closable()
1037 }
1038
1039 /// Gets the window's current decoration state.
1040 ///
1041 /// ## Platform-specific
1042 ///
1043 /// - **iOS / Android:** Unsupported.
1044 pub fn is_decorated(&self) -> bool {
1045 self.window.is_decorated()
1046 }
1047
1048 /// Sets the window to fullscreen or back.
1049 ///
1050 /// ## Platform-specific
1051 ///
1052 /// - **macOS:** `Fullscreen::Exclusive` provides true exclusive mode with a
1053 /// video mode change. *Caveat!* macOS doesn't provide task switching (or
1054 /// spaces!) while in exclusive fullscreen mode. This mode should be used
1055 /// when a video mode change is desired, but for a better user experience,
1056 /// borderless fullscreen might be preferred.
1057 ///
1058 /// `Fullscreen::Borderless` provides a borderless fullscreen window on a
1059 /// separate space. This is the idiomatic way for fullscreen games to work
1060 /// on macOS. See `WindowExtMacOs::set_simple_fullscreen` if
1061 /// separate spaces are not preferred.
1062 ///
1063 /// The dock and the menu bar are always disabled in fullscreen mode.
1064 /// - **iOS:** Can only be called on the main thread.
1065 /// - **Windows:** Screen saver is disabled in fullscreen mode.
1066 /// - **Linux:** The window will only fullscreen to current monitor no matter which enum variant.
1067 /// - **Android:** Unsupported.
1068 #[inline]
1069 pub fn set_fullscreen(&self, fullscreen: Option<Fullscreen>) {
1070 self.window.set_fullscreen(fullscreen)
1071 }
1072
1073 /// Gets the window's current fullscreen state.
1074 ///
1075 /// ## Platform-specific
1076 ///
1077 /// - **iOS:** Can only be called on the main thread.
1078 /// - **Android:** Will always return `None`.
1079 #[inline]
1080 pub fn fullscreen(&self) -> Option<Fullscreen> {
1081 self.window.fullscreen()
1082 }
1083
1084 /// Turn window decorations on or off.
1085 ///
1086 /// ## Platform-specific
1087 ///
1088 /// - **iOS / Android:** Unsupported.
1089 ///
1090 /// [`setPrefersStatusBarHidden`]: https://developer.apple.com/documentation/uikit/uiviewcontroller/1621440-prefersstatusbarhidden?language=objc
1091 #[inline]
1092 pub fn set_decorations(&self, decorations: bool) {
1093 self.window.set_decorations(decorations)
1094 }
1095
1096 /// Change whether or not the window will always be below other windows.
1097 ///
1098 /// ## Platform-specific
1099 ///
1100 /// - **Windows**: There is no guarantee that the window will be the bottom most but it will try to be.
1101 /// - **Linux(x11):** Result depends on the system's window manager. Consider this setting a suggestion.
1102 /// - **Linux(Wayland) / iOS / Android:** Unsupported.
1103 // TODO: Unsupported in gtk4
1104 #[inline]
1105 pub fn set_always_on_bottom(&self, always_on_bottom: bool) {
1106 self.window.set_always_on_bottom(always_on_bottom)
1107 }
1108
1109 /// Change whether or not the window will always be on top of other windows.
1110 ///
1111 /// ## Platform-specific
1112 ///
1113 /// - **Linux(x11):** Result depends on the system's window manager. Consider this setting a suggestion.
1114 /// - **Linux(Wayland) / iOS / Android:** Unsupported.
1115 // TODO: Unsupported in gtk4
1116 #[inline]
1117 pub fn set_always_on_top(&self, always_on_top: bool) {
1118 self.window.set_always_on_top(always_on_top)
1119 }
1120
1121 /// Sets the window icon. On Windows and Linux, this is typically the small icon in the top-left
1122 /// corner of the title bar.
1123 ///
1124 /// ## Platform-specific
1125 ///
1126 /// - **iOS / Android / macOS:** Unsupported.
1127 ///
1128 /// On Windows, this sets `ICON_SMALL`. The base size for a window icon is 16x16, but it's
1129 /// recommended to account for screen scaling and pick a multiple of that, i.e. 32x32.
1130 #[inline]
1131 pub fn set_window_icon(&self, window_icon: Option<Icon>) {
1132 self.window.set_window_icon(window_icon)
1133 }
1134
1135 /// Sets location of IME candidate box in client area coordinates relative to the top left.
1136 ///
1137 /// ## Platform-specific
1138 ///
1139 /// - **iOS / Android:** Unsupported.
1140 #[inline]
1141 pub fn set_ime_position<P: Into<Position>>(&self, position: P) {
1142 self.window.set_ime_position(position.into())
1143 }
1144
1145 /// Sets the taskbar progress state.
1146 ///
1147 /// ## Platform-specific
1148 ///
1149 /// - **Linux / macOS**: Unlike windows, progress bar is app-wide and not specific to this window. Only supported desktop environments with `libunity` (e.g. GNOME).
1150 /// - **iOS / Android:** Unsupported.
1151 #[inline]
1152 pub fn set_progress_bar(&self, _progress: ProgressBarState) {
1153 #[cfg(any(
1154 windows,
1155 target_os = "linux",
1156 target_os = "dragonfly",
1157 target_os = "freebsd",
1158 target_os = "netbsd",
1159 target_os = "openbsd",
1160 target_os = "macos",
1161 ))]
1162 self.window.set_progress_bar(_progress)
1163 }
1164
1165 /// Requests user attention to the window, this has no effect if the application
1166 /// is already focused. How requesting for user attention manifests is platform dependent,
1167 /// see `UserAttentionType` for details.
1168 ///
1169 /// Providing `None` will unset the request for user attention. Unsetting the request for
1170 /// user attention might not be done automatically by the WM when the window receives input.
1171 ///
1172 /// ## Platform-specific
1173 ///
1174 /// - **iOS / Android:** Unsupported.
1175 /// - **macOS:** `None` has no effect.
1176 /// - **Linux:** Urgency levels have the same effect.
1177 #[inline]
1178 pub fn request_user_attention(&self, request_type: Option<UserAttentionType>) {
1179 self.window.request_user_attention(request_type)
1180 }
1181
1182 /// Returns the current window theme.
1183 ///
1184 /// ## Platform-specific
1185 ///
1186 /// - **iOS / Android:** Unsupported.
1187 #[inline]
1188 pub fn theme(&self) -> Theme {
1189 self.window.theme()
1190 }
1191
1192 /// Sets the theme for this window.
1193 ///
1194 /// ## Platform-specific
1195 ///
1196 /// - **Linux / macOS**: Theme is app-wide and not specific to this window.
1197 /// - **iOS / Android:** Unsupported.
1198 #[inline]
1199 pub fn set_theme(&self, #[allow(unused)] theme: Option<Theme>) {
1200 #[cfg(any(
1201 windows,
1202 target_os = "linux",
1203 target_os = "dragonfly",
1204 target_os = "freebsd",
1205 target_os = "netbsd",
1206 target_os = "openbsd",
1207 target_os = "macos",
1208 ))]
1209 self.window.set_theme(theme)
1210 }
1211
1212 /// Prevents the window contents from being captured by other apps.
1213 ///
1214 /// ## Platform-specific
1215 ///
1216 /// - **iOS / Android / Linux:** Unsupported.
1217 pub fn set_content_protection(&self, #[allow(unused)] enabled: bool) {
1218 #[cfg(any(target_os = "macos", target_os = "windows"))]
1219 self.window.set_content_protection(enabled);
1220 }
1221
1222 /// Sets whether the window should be visible on all workspaces.
1223 ///
1224 /// ## Platform-specific
1225 ///
1226 /// - **iOS / Android / Windows:** Unsupported.
1227 pub fn set_visible_on_all_workspaces(&self, #[allow(unused)] visible: bool) {
1228 #[cfg(any(target_os = "macos", target_os = "linux"))]
1229 self.window.set_visible_on_all_workspaces(visible)
1230 }
1231
1232 /// Sets the window background color.
1233 ///
1234 /// ## Platform-specific:
1235 ///
1236 /// - **Windows:** alpha channel is ignored. Instead manually draw the window, for example using `softbuffer` crate, see <https://github.com/tauri-apps/tao/blob/dev/examples/transparent.rs>
1237 /// - **iOS / Android:** Unsupported.
1238 #[inline]
1239 pub fn set_background_color(&self, color: Option<RGBA>) {
1240 self.window.set_background_color(color)
1241 }
1242}
1243
1244/// Cursor functions.
1245impl Window {
1246 /// Modifies the cursor icon of the window.
1247 ///
1248 /// ## Platform-specific
1249 ///
1250 /// - **iOS / Android:** Unsupported.
1251 #[inline]
1252 pub fn set_cursor_icon(&self, cursor: CursorIcon) {
1253 self.window.set_cursor_icon(cursor);
1254 }
1255
1256 /// Changes the position of the cursor in window coordinates.
1257 ///
1258 /// ## Platform-specific
1259 ///
1260 /// - **iOS / Android:** Always returns an [`ExternalError::NotSupported`].
1261 #[inline]
1262 pub fn set_cursor_position<P: Into<Position>>(&self, position: P) -> Result<(), ExternalError> {
1263 self.window.set_cursor_position(position.into())
1264 }
1265
1266 /// Grabs the cursor, preventing it from leaving the window.
1267 ///
1268 /// There's no guarantee that the cursor will be hidden. You should
1269 /// hide it by yourself if you want so.
1270 ///
1271 /// ## Platform-specific
1272 ///
1273 /// - **macOS:** This locks the cursor in a fixed location, which looks visually awkward.
1274 /// - **iOS / Android:** Always returns an [`ExternalError::NotSupported`].
1275 #[inline]
1276 pub fn set_cursor_grab(&self, grab: bool) -> Result<(), ExternalError> {
1277 self.window.set_cursor_grab(grab)
1278 }
1279
1280 /// Modifies the cursor's visibility.
1281 ///
1282 /// If `false`, this will hide the cursor. If `true`, this will show the cursor.
1283 ///
1284 /// ## Platform-specific
1285 ///
1286 /// - **Windows:** The cursor is only hidden within the confines of the window.
1287 /// - **macOS:** The cursor is hidden as long as the window has input focus, even if the cursor is
1288 /// outside of the window.
1289 /// - **iOS / Android:** Unsupported.
1290 #[inline]
1291 pub fn set_cursor_visible(&self, visible: bool) {
1292 self.window.set_cursor_visible(visible)
1293 }
1294
1295 /// Moves the window with the left mouse button until the button is released.
1296 ///
1297 /// There's no guarantee that this will work unless the left mouse button was pressed
1298 /// immediately before this function is called.
1299 ///
1300 /// ## Platform-specific
1301 ///
1302 /// - **macOS:** May prevent the button release event to be triggered.
1303 /// - **iOS / Android:** Always returns an [`ExternalError::NotSupported`].
1304 #[inline]
1305 pub fn drag_window(&self) -> Result<(), ExternalError> {
1306 self.window.drag_window()
1307 }
1308
1309 /// Resizes the window with the left mouse button until the button is released.
1310 ///
1311 /// There's no guarantee that this will work unless the left mouse button was pressed
1312 /// immediately before this function is called.
1313 ///
1314 /// ## Platform-specific
1315 ///
1316 /// - **macOS / iOS / Android:** Always returns an [`ExternalError::NotSupported`].
1317 #[inline]
1318 pub fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), ExternalError> {
1319 self.window.drag_resize_window(direction)
1320 }
1321
1322 /// Modifies whether the window catches cursor events.
1323 ///
1324 /// If `true`, the events are passed through the window such that any other window behind it receives them.
1325 /// If `false` the window will catch the cursor events. By default cursor events are not ignored.
1326 ///
1327 /// ## Platform-specific
1328 ///
1329 /// - **iOS / Android:** Always returns an [`ExternalError::NotSupported`]
1330 #[inline]
1331 pub fn set_ignore_cursor_events(&self, ignore: bool) -> Result<(), ExternalError> {
1332 self.window.set_ignore_cursor_events(ignore)
1333 }
1334
1335 /// Returns the current cursor position
1336 ///
1337 /// ## Platform-specific
1338 ///
1339 /// - **iOS / Android / Linux(Wayland)**: Unsupported, returns `0,0`.
1340 #[inline]
1341 pub fn cursor_position(&self) -> Result<PhysicalPosition<f64>, ExternalError> {
1342 self.window.cursor_position()
1343 }
1344}
1345
1346/// Monitor info functions.
1347impl Window {
1348 /// Returns the monitor on which the window currently resides.
1349 ///
1350 /// Returns `None` if current monitor can't be detected.
1351 ///
1352 /// ## Platform-specific
1353 ///
1354 /// **iOS:** Can only be called on the main thread.
1355 #[inline]
1356 pub fn current_monitor(&self) -> Option<MonitorHandle> {
1357 self.window.current_monitor()
1358 }
1359
1360 #[inline]
1361 /// Returns the monitor that contains the given point.
1362 ///
1363 /// ## Platform-specific:
1364 ///
1365 /// - **Android / iOS:** Unsupported.
1366 pub fn monitor_from_point(&self, x: f64, y: f64) -> Option<MonitorHandle> {
1367 self.window.monitor_from_point(x, y)
1368 }
1369
1370 /// Returns the list of all the monitors available on the system.
1371 ///
1372 /// This is the same as `EventLoopWindowTarget::available_monitors`, and is provided for convenience.
1373 ///
1374 /// ## Platform-specific
1375 ///
1376 /// **iOS:** Can only be called on the main thread.
1377 #[inline]
1378 pub fn available_monitors(&self) -> impl Iterator<Item = MonitorHandle> {
1379 self
1380 .window
1381 .available_monitors()
1382 .into_iter()
1383 .map(|inner| MonitorHandle { inner })
1384 }
1385
1386 /// Returns the primary monitor of the system.
1387 ///
1388 /// Returns `None` if it can't identify any monitor as a primary one.
1389 ///
1390 /// This is the same as `EventLoopWindowTarget::primary_monitor`, and is provided for convenience.
1391 ///
1392 /// ## Platform-specific
1393 ///
1394 /// **iOS:** Can only be called on the main thread.
1395 #[inline]
1396 pub fn primary_monitor(&self) -> Option<MonitorHandle> {
1397 self.window.primary_monitor()
1398 }
1399}
1400
1401#[cfg(feature = "rwh_04")]
1402unsafe impl rwh_04::HasRawWindowHandle for Window {
1403 fn raw_window_handle(&self) -> rwh_04::RawWindowHandle {
1404 self.window.raw_window_handle_rwh_04()
1405 }
1406}
1407
1408#[cfg(feature = "rwh_05")]
1409unsafe impl rwh_05::HasRawWindowHandle for Window {
1410 fn raw_window_handle(&self) -> rwh_05::RawWindowHandle {
1411 self.window.raw_window_handle_rwh_05()
1412 }
1413}
1414
1415#[cfg(feature = "rwh_05")]
1416unsafe impl rwh_05::HasRawDisplayHandle for Window {
1417 fn raw_display_handle(&self) -> rwh_05::RawDisplayHandle {
1418 self.window.raw_display_handle_rwh_05()
1419 }
1420}
1421
1422#[cfg(feature = "rwh_06")]
1423impl rwh_06::HasWindowHandle for Window {
1424 fn window_handle(&self) -> Result<rwh_06::WindowHandle<'_>, rwh_06::HandleError> {
1425 let raw = self.window.raw_window_handle_rwh_06()?;
1426 // SAFETY: The window handle will never be deallocated while the window is alive.
1427 Ok(unsafe { rwh_06::WindowHandle::borrow_raw(raw) })
1428 }
1429}
1430
1431#[cfg(feature = "rwh_06")]
1432impl rwh_06::HasDisplayHandle for Window {
1433 fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
1434 let raw = self.window.raw_display_handle_rwh_06()?;
1435 // SAFETY: The window handle will never be deallocated while the window is alive.
1436 Ok(unsafe { rwh_06::DisplayHandle::borrow_raw(raw) })
1437 }
1438}
1439
1440/// Describes the appearance of the mouse cursor.
1441#[non_exhaustive]
1442#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1443#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1444#[derive(Default)]
1445pub enum CursorIcon {
1446 /// The platform-dependent default cursor.
1447 #[default]
1448 Default,
1449 /// A simple crosshair.
1450 Crosshair,
1451 /// A hand (often used to indicate links in web browsers).
1452 Hand,
1453 /// Self explanatory.
1454 Arrow,
1455 /// Indicates something is to be moved.
1456 Move,
1457 /// Indicates text that may be selected or edited.
1458 Text,
1459 /// Program busy indicator.
1460 Wait,
1461 /// Help indicator (often rendered as a "?")
1462 Help,
1463 /// Progress indicator. Shows that processing is being done. But in contrast
1464 /// with "Wait" the user may still interact with the program. Often rendered
1465 /// as a spinning beach ball, or an arrow with a watch or hourglass.
1466 Progress,
1467
1468 /// Cursor showing that something cannot be done.
1469 NotAllowed,
1470 ContextMenu,
1471 Cell,
1472 VerticalText,
1473 Alias,
1474 Copy,
1475 NoDrop,
1476 /// Indicates something can be grabbed.
1477 Grab,
1478 /// Indicates something is grabbed.
1479 Grabbing,
1480 AllScroll,
1481 ZoomIn,
1482 ZoomOut,
1483
1484 /// Indicate that some edge is to be moved. For example, the 'SeResize' cursor
1485 /// is used when the movement starts from the south-east corner of the box.
1486 EResize,
1487 NResize,
1488 NeResize,
1489 NwResize,
1490 SResize,
1491 SeResize,
1492 SwResize,
1493 WResize,
1494 EwResize,
1495 NsResize,
1496 NeswResize,
1497 NwseResize,
1498 ColResize,
1499 RowResize,
1500}
1501
1502/// Fullscreen modes.
1503#[non_exhaustive]
1504#[allow(clippy::large_enum_variant)]
1505#[derive(Clone, Debug, PartialEq)]
1506pub enum Fullscreen {
1507 Exclusive(VideoMode),
1508
1509 /// Providing `None` to `Borderless` will fullscreen on the current monitor.
1510 Borderless(Option<MonitorHandle>),
1511}
1512
1513#[non_exhaustive]
1514#[derive(Default, Clone, Copy, Debug, PartialEq)]
1515pub enum Theme {
1516 #[default]
1517 Light,
1518 Dark,
1519}
1520
1521#[non_exhaustive]
1522#[derive(Debug, Clone, Copy, PartialEq, Default)]
1523pub enum UserAttentionType {
1524 /// ## Platform-specific
1525 /// - **macOS:** Bounces the dock icon until the application is in focus.
1526 /// - **Windows:** Flashes both the window and the taskbar button until the application is in focus.
1527 Critical,
1528 /// ## Platform-specific
1529 /// - **macOS:** Bounces the dock icon once.
1530 /// - **Windows:** Flashes the taskbar button until the application is in focus.
1531 #[default]
1532 Informational,
1533}
1534
1535/// Window size constraints
1536#[derive(Clone, Copy, PartialEq, Debug, Default)]
1537pub struct WindowSizeConstraints {
1538 /// The minimum width a window can be, If this is `None`, the window will have no minimum width (aside from reserved).
1539 ///
1540 /// The default is `None`.
1541 pub min_width: Option<PixelUnit>,
1542 /// The minimum height a window can be, If this is `None`, the window will have no minimum height (aside from reserved).
1543 ///
1544 /// The default is `None`.
1545 pub min_height: Option<PixelUnit>,
1546 /// The maximum width a window can be, If this is `None`, the window will have no maximum width (aside from reserved).
1547 ///
1548 /// The default is `None`.
1549 pub max_width: Option<PixelUnit>,
1550 /// The maximum height a window can be, If this is `None`, the window will have no maximum height (aside from reserved).
1551 ///
1552 /// The default is `None`.
1553 pub max_height: Option<PixelUnit>,
1554}
1555
1556impl WindowSizeConstraints {
1557 pub fn new(
1558 min_width: Option<PixelUnit>,
1559 min_height: Option<PixelUnit>,
1560 max_width: Option<PixelUnit>,
1561 max_height: Option<PixelUnit>,
1562 ) -> Self {
1563 Self {
1564 min_width,
1565 min_height,
1566 max_width,
1567 max_height,
1568 }
1569 }
1570
1571 /// Returns true if `min_width` or `min_height` is set.
1572 pub fn has_min(&self) -> bool {
1573 self.min_width.is_some() || self.min_height.is_some()
1574 }
1575 /// Returns true if `max_width` or `max_height` is set.
1576 pub fn has_max(&self) -> bool {
1577 self.max_width.is_some() || self.max_height.is_some()
1578 }
1579
1580 /// Returns a physical size that represents the minimum constraints set and fallbacks to [`PixelUnit::MIN`] for unset values
1581 pub fn min_size_physical<T: Pixel>(&self, scale_factor: f64) -> PhysicalSize<T> {
1582 PhysicalSize::new(
1583 self
1584 .min_width
1585 .unwrap_or(PixelUnit::MIN)
1586 .to_physical(scale_factor)
1587 .0,
1588 self
1589 .min_height
1590 .unwrap_or(PixelUnit::MIN)
1591 .to_physical(scale_factor)
1592 .0,
1593 )
1594 }
1595
1596 /// Returns a logical size that represents the minimum constraints set and fallbacks to [`PixelUnit::MIN`] for unset values
1597 pub fn min_size_logical<T: Pixel>(&self, scale_factor: f64) -> LogicalSize<T> {
1598 LogicalSize::new(
1599 self
1600 .min_width
1601 .unwrap_or(PixelUnit::MIN)
1602 .to_logical(scale_factor)
1603 .0,
1604 self
1605 .min_height
1606 .unwrap_or(PixelUnit::MIN)
1607 .to_logical(scale_factor)
1608 .0,
1609 )
1610 }
1611
1612 /// Returns a physical size that represents the maximum constraints set and fallbacks to [`PixelUnit::MAX`] for unset values
1613 pub fn max_size_physical<T: Pixel>(&self, scale_factor: f64) -> PhysicalSize<T> {
1614 PhysicalSize::new(
1615 self
1616 .max_width
1617 .unwrap_or(PixelUnit::MAX)
1618 .to_physical(scale_factor)
1619 .0,
1620 self
1621 .max_height
1622 .unwrap_or(PixelUnit::MAX)
1623 .to_physical(scale_factor)
1624 .0,
1625 )
1626 }
1627
1628 /// Returns a logical size that represents the maximum constraints set and fallbacks to [`PixelUnit::MAX`] for unset values
1629 pub fn max_size_logical<T: Pixel>(&self, scale_factor: f64) -> LogicalSize<T> {
1630 LogicalSize::new(
1631 self
1632 .max_width
1633 .unwrap_or(PixelUnit::MAX)
1634 .to_logical(scale_factor)
1635 .0,
1636 self
1637 .max_height
1638 .unwrap_or(PixelUnit::MAX)
1639 .to_logical(scale_factor)
1640 .0,
1641 )
1642 }
1643
1644 /// Clamps the desired size based on the constraints set
1645 pub fn clamp(&self, desired_size: Size, scale_factor: f64) -> Size {
1646 let min_size: PhysicalSize<f64> = self.min_size_physical(scale_factor);
1647 let max_size: PhysicalSize<f64> = self.max_size_physical(scale_factor);
1648 Size::clamp(desired_size, min_size.into(), max_size.into(), scale_factor)
1649 }
1650}
1651
1652/// Defines the orientation that a window resize will be performed.
1653#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1654pub enum ResizeDirection {
1655 East,
1656 North,
1657 NorthEast,
1658 NorthWest,
1659 South,
1660 SouthEast,
1661 SouthWest,
1662 West,
1663}
1664
1665pub(crate) fn hit_test(
1666 (left, top, right, bottom): (i32, i32, i32, i32),
1667 cx: i32,
1668 cy: i32,
1669 border_x: i32,
1670 border_y: i32,
1671) -> Option<ResizeDirection> {
1672 const LEFT: isize = 0b0001;
1673 const RIGHT: isize = 0b0010;
1674 const TOP: isize = 0b0100;
1675 const BOTTOM: isize = 0b1000;
1676 const TOPLEFT: isize = TOP | LEFT;
1677 const TOPRIGHT: isize = TOP | RIGHT;
1678 const BOTTOMLEFT: isize = BOTTOM | LEFT;
1679 const BOTTOMRIGHT: isize = BOTTOM | RIGHT;
1680
1681 #[rustfmt::skip]
1682 let result = (LEFT * (cx < left + border_x) as isize)
1683 | (RIGHT * (cx >= right - border_x) as isize)
1684 | (TOP * (cy < top + border_y) as isize)
1685 | (BOTTOM * (cy >= bottom - border_y) as isize);
1686
1687 match result {
1688 LEFT => Some(ResizeDirection::West),
1689 RIGHT => Some(ResizeDirection::East),
1690 TOP => Some(ResizeDirection::North),
1691 BOTTOM => Some(ResizeDirection::South),
1692 TOPLEFT => Some(ResizeDirection::NorthWest),
1693 TOPRIGHT => Some(ResizeDirection::NorthEast),
1694 BOTTOMLEFT => Some(ResizeDirection::SouthWest),
1695 BOTTOMRIGHT => Some(ResizeDirection::SouthEast),
1696 _ => None,
1697 }
1698}