Skip to main content

winit_core/
window.rs

1//! The [`Window`] trait and associated types.
2mod positioner;
3
4use std::any::Any;
5use std::fmt;
6
7use bitflags::bitflags;
8use cursor_icon::CursorIcon;
9use dpi::{
10    LogicalPosition, LogicalSize, PhysicalInsets, PhysicalPosition, PhysicalSize, Position, Size,
11};
12pub use positioner::{WindowAnchor, WindowConstraintAdjustment, WindowGravity};
13#[cfg(feature = "serde")]
14use serde::{Deserialize, Serialize};
15
16use crate::cursor::Cursor;
17use crate::error::RequestError;
18use crate::icon::Icon;
19use crate::monitor::{Fullscreen, MonitorHandle};
20
21/// Identifier of a window. Unique for each window.
22///
23/// Can be obtained with [`window.id()`][`Window::id`].
24///
25/// Whenever you receive an event specific to a window, this event contains a `WindowId` which you
26/// can then compare to the ids of your windows.
27#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
28pub struct WindowId(usize);
29
30impl WindowId {
31    /// Convert the `WindowId` into the underlying integer.
32    ///
33    /// This is useful if you need to pass the ID across an FFI boundary, or store it in an atomic.
34    pub const fn into_raw(self) -> usize {
35        self.0
36    }
37
38    /// Construct a `WindowId` from the underlying integer.
39    ///
40    /// This should only be called with integers returned from [`WindowId::into_raw`].
41    pub const fn from_raw(id: usize) -> Self {
42        Self(id)
43    }
44}
45
46impl fmt::Debug for WindowId {
47    fn fmt(&self, fmtr: &mut fmt::Formatter<'_>) -> fmt::Result {
48        self.0.fmt(fmtr)
49    }
50}
51
52/// The role of a window, used to request platform-specific window behavior.
53#[non_exhaustive]
54#[derive(Debug, Clone, Copy, Default, PartialEq)]
55pub enum WindowType {
56    /// A normal, top-level window.
57    #[default]
58    Window,
59    /// A short-lived window anchored to a parent, such as a menu, combo-box dropdown, or
60    /// tooltip. Requires a parent set via [`WindowAttributes::with_parent_window`], and its
61    /// position is interpreted relative to that parent.
62    ///
63    /// The anchor/gravity/positioning system described on [`WindowAttributes::with_positioner`]
64    /// can be used to position the popup or window in a more advanced way
65    ///
66    /// ## Platform-specific
67    ///
68    /// - **macOS:** A borderless, non-activating child window. The system does *not* draw rounded
69    ///   corners for it. To get a rounded, native-looking popup, create it transparent (via
70    ///   [`WindowAttributes::with_transparent`]) and render the round border yourself.
71    /// - **X11, Web, Android, iOS, Orbital:** An error is returned because it is not implemented.
72    Popup,
73}
74
75/// The positioner state backing a window's anchor-based placement.
76///
77/// Set at window creation via [`WindowAttributes::with_positioner`], and read/mutated at runtime
78/// through [`Window::positioner`]/[`Window::set_positioner`]. See those methods for
79/// platform-specific behavior, and [`WindowPositioner::default`] for the values used when
80/// [`WindowAttributes::with_positioner`] is never called.
81///
82/// The structure is based on the wayland structure. For more information see the wayland
83/// documentation [XDG Positioner](https://wayland.app/protocols/xdg-shell#xdg_positioner)
84#[non_exhaustive]
85#[derive(Debug, Clone, Copy, PartialEq)]
86pub struct WindowPositioner {
87    /// The edge or corner of the anchor rect used to position the window relative to it.
88    ///
89    /// Combined with [`gravity`](Self::gravity), this controls which corner/edge of the anchor
90    /// rectangle the window is pinned to. Defaults to [`WindowAnchor::Center`].
91    pub anchor: WindowAnchor,
92    /// The anchor rectangle the window is positioned relative to.
93    ///
94    /// The [`Position`] is the top-left corner of the rectangle relative to the parent window's
95    /// content area, and the [`Size`] its dimensions. Defaults to a `1x1` rectangle at the
96    /// content origin. Passing a [`WindowPositioner`] to [`WindowAttributes::with_positioner`]
97    /// overrides the position value set with [`WindowAttributes::with_position`].
98    pub anchor_rect: (Position, Size),
99    /// The window's position relative to the anchor rect. Defaults to no offset.
100    pub offset: Position,
101    /// The direction the window surface extends away from the anchor point.
102    ///
103    /// Combined with [`anchor`](Self::anchor), this determines the final position of the window
104    /// relative to its anchor rectangle. Defaults to [`WindowGravity::Center`].
105    pub gravity: WindowGravity,
106    /// How the window should be repositioned when it would be constrained.
107    ///
108    /// The flags in [`WindowConstraintAdjustment`] can be combined to allow sliding, flipping,
109    /// and/or resizing the window independently on each axis. Defaults to no adjustment.
110    pub constraint_adjustment: WindowConstraintAdjustment,
111}
112
113impl WindowPositioner {
114    pub fn new(
115        anchor: WindowAnchor,
116        anchor_rect: (Position, Size),
117        offset: Position,
118        gravity: WindowGravity,
119        constraint_adjustment: WindowConstraintAdjustment,
120    ) -> Self {
121        WindowPositioner { anchor, anchor_rect, offset, gravity, constraint_adjustment }
122    }
123}
124
125impl Default for WindowPositioner {
126    fn default() -> Self {
127        Self {
128            anchor: WindowAnchor::default(),
129            anchor_rect: (
130                Position::Logical(LogicalPosition::new(0.0, 0.0)),
131                Size::Logical(LogicalSize::new(1.0, 1.0)),
132            ),
133            offset: Position::Logical(LogicalPosition::new(0.0, 0.0)),
134            gravity: WindowGravity::default(),
135            constraint_adjustment: WindowConstraintAdjustment::empty(),
136        }
137    }
138}
139
140/// Attributes used when creating a window.
141#[derive(Debug)]
142#[non_exhaustive]
143pub struct WindowAttributes {
144    pub surface_size: Option<Size>,
145    pub min_surface_size: Option<Size>,
146    pub max_surface_size: Option<Size>,
147    pub surface_resize_increments: Option<Size>,
148    /// The initial position of the window in screen coordinates.
149    ///
150    /// For popups, this position is relative to the parent window.
151    ///
152    /// **Wayland:** See `WindowAttributesWayland` for more options to position a popup.
153    pub position: Option<Position>,
154    pub resizable: bool,
155    pub enabled_buttons: WindowButtons,
156    pub title: String,
157    pub maximized: bool,
158    pub visible: bool,
159    pub transparent: bool,
160    pub blur: bool,
161    pub decorations: bool,
162    pub window_icon: Option<Icon>,
163    pub preferred_theme: Option<Theme>,
164    pub content_protected: bool,
165    pub window_level: WindowLevel,
166    /// Whether the window should be activated (focused) when shown.
167    ///
168    /// For [`WindowType::Popup`] windows this also controls keyboard grabbing:
169    /// - `true` — the popup captures keyboard input (Win32: omits `WS_EX_NOACTIVATE`, macOS: uses
170    ///   an activating `NSWindow`, Wayland: issues `xdg_popup.grab`).
171    /// - `false` — the popup is non-activating and the parent window keeps focus (Win32:
172    ///   `WS_EX_NOACTIVATE`, macOS: `NSWindowStyleMask::NonactivatingPanel`, Wayland: no grab).
173    pub active: bool,
174    pub cursor: Cursor,
175    pub(crate) parent_window: Option<SendSyncRawWindowHandle>,
176    pub fullscreen: Option<Fullscreen>,
177    pub platform: Option<Box<dyn PlatformWindowAttributes>>,
178    pub window_type: WindowType,
179    /// See [`WindowAttributes::with_positioner`].
180    pub positioner: Option<WindowPositioner>,
181}
182
183impl WindowAttributes {
184    /// Get the parent window stored on the attributes.
185    pub fn parent_window(&self) -> Option<&rwh_06::RawWindowHandle> {
186        self.parent_window.as_ref().map(|handle| &handle.0)
187    }
188
189    /// Requests the surface to be of specific dimensions.
190    ///
191    /// If this is not set, some platform-specific dimensions will be used.
192    ///
193    /// See [`Window::request_surface_size`] for details.
194    #[inline]
195    pub fn with_surface_size<S: Into<Size>>(mut self, size: S) -> Self {
196        self.surface_size = Some(size.into());
197        self
198    }
199
200    /// Sets the minimum dimensions the surface can have.
201    ///
202    /// If this is not set, the surface will have no minimum dimensions (aside from reserved).
203    ///
204    /// See [`Window::set_min_surface_size`] for details.
205    #[inline]
206    pub fn with_min_surface_size<S: Into<Size>>(mut self, min_size: S) -> Self {
207        self.min_surface_size = Some(min_size.into());
208        self
209    }
210
211    /// Sets the maximum dimensions the surface can have.
212    ///
213    /// If this is not set, the surface will have no maximum, or the maximum will be restricted to
214    /// the primary monitor's dimensions by the platform.
215    ///
216    /// See [`Window::set_max_surface_size`] for details.
217    #[inline]
218    pub fn with_max_surface_size<S: Into<Size>>(mut self, max_size: S) -> Self {
219        self.max_surface_size = Some(max_size.into());
220        self
221    }
222
223    /// Build window with resize increments hint.
224    ///
225    /// The default is `None`.
226    ///
227    /// See [`Window::set_surface_resize_increments`] for details.
228    #[inline]
229    pub fn with_surface_resize_increments<S: Into<Size>>(
230        mut self,
231        surface_resize_increments: S,
232    ) -> Self {
233        self.surface_resize_increments = Some(surface_resize_increments.into());
234        self
235    }
236
237    /// Sets a desired initial position for the window.
238    ///
239    /// If this is not set, some platform-specific position will be chosen.
240    ///
241    /// See [`Window::set_outer_position`] for details.
242    ///
243    /// ## Platform-specific
244    ///
245    /// - **macOS:** The top left corner position of the window content, the window's "inner"
246    ///   position. The window title bar will be placed above it. The window will be positioned such
247    ///   that it fits on screen, maintaining set `surface_size` if any. If you need to precisely
248    ///   position the top left corner of the whole window you have to use
249    ///   [`Window::set_outer_position`] after creating the window.
250    /// - **Windows:** The top left corner position of the window title bar, the window's "outer"
251    ///   position. There may be a small gap between this position and the window due to the
252    ///   specifics of the Window Manager.
253    /// - **X11:** The top left corner of the window, the window's "outer" position.
254    /// - **Wayland:** The top left corner of the window if the window type is `WindowType::Popup`
255    ///   otherwise ignored
256    /// - **Others:** Ignored.
257    #[inline]
258    pub fn with_position<P: Into<Position>>(mut self, position: P) -> Self {
259        self.position = Some(position.into());
260        self
261    }
262
263    /// Sets whether the window is resizable or not.
264    ///
265    /// The default is `true`.
266    ///
267    /// See [`Window::set_resizable`] for details.
268    #[inline]
269    pub fn with_resizable(mut self, resizable: bool) -> Self {
270        self.resizable = resizable;
271        self
272    }
273
274    /// Sets the enabled window buttons.
275    ///
276    /// The default is [`WindowButtons::all`]
277    ///
278    /// See [`Window::set_enabled_buttons`] for details.
279    #[inline]
280    pub fn with_enabled_buttons(mut self, buttons: WindowButtons) -> Self {
281        self.enabled_buttons = buttons;
282        self
283    }
284
285    /// Sets the initial title of the window in the title bar.
286    ///
287    /// The default is `"winit window"`.
288    ///
289    /// See [`Window::set_title`] for details.
290    #[inline]
291    pub fn with_title<T: Into<String>>(mut self, title: T) -> Self {
292        self.title = title.into();
293        self
294    }
295
296    /// Sets whether the window should be put into fullscreen upon creation.
297    ///
298    /// The default is `None`.
299    ///
300    /// See [`Window::set_fullscreen`] for details.
301    #[inline]
302    pub fn with_fullscreen(mut self, fullscreen: Option<Fullscreen>) -> Self {
303        self.fullscreen = fullscreen;
304        self
305    }
306
307    /// Request that the window is maximized upon creation.
308    ///
309    /// The default is `false`.
310    ///
311    /// See [`Window::set_maximized`] for details.
312    #[inline]
313    pub fn with_maximized(mut self, maximized: bool) -> Self {
314        self.maximized = maximized;
315        self
316    }
317
318    /// Sets whether the window will be initially visible or hidden.
319    ///
320    /// The default is to show the window.
321    ///
322    /// See [`Window::set_visible`] for details.
323    #[inline]
324    pub fn with_visible(mut self, visible: bool) -> Self {
325        self.visible = visible;
326        self
327    }
328
329    /// Sets whether the background of the window should be transparent.
330    ///
331    /// If this is `true`, writing colors with alpha values different than
332    /// `1.0` will produce a transparent window. On some platforms this
333    /// is more of a hint for the system and you'd still have the alpha
334    /// buffer. To control it see [`Window::set_transparent`].
335    ///
336    /// The default is `false`.
337    #[inline]
338    pub fn with_transparent(mut self, transparent: bool) -> Self {
339        self.transparent = transparent;
340        self
341    }
342
343    /// Sets whether the background of the window should be blurred by the system.
344    ///
345    /// The default is `false`.
346    ///
347    /// See [`Window::set_blur`] for details.
348    #[inline]
349    pub fn with_blur(mut self, blur: bool) -> Self {
350        self.blur = blur;
351        self
352    }
353
354    /// Get whether the window will support transparency.
355    #[inline]
356    pub fn transparent(&self) -> bool {
357        self.transparent
358    }
359
360    /// Sets whether the window should have a border, a title bar, etc.
361    ///
362    /// The default is `true`.
363    ///
364    /// See [`Window::set_decorations`] for details.
365    #[inline]
366    pub fn with_decorations(mut self, decorations: bool) -> Self {
367        self.decorations = decorations;
368        self
369    }
370
371    /// Sets the window level.
372    ///
373    /// This is just a hint to the OS, and the system could ignore it.
374    ///
375    /// The default is [`WindowLevel::Normal`].
376    ///
377    /// See [`WindowLevel`] for details.
378    #[inline]
379    pub fn with_window_level(mut self, level: WindowLevel) -> Self {
380        self.window_level = level;
381        self
382    }
383
384    /// Sets the window icon.
385    ///
386    /// The default is `None`.
387    ///
388    /// See [`Window::set_window_icon`] for details.
389    #[inline]
390    pub fn with_window_icon(mut self, window_icon: Option<Icon>) -> Self {
391        self.window_icon = window_icon;
392        self
393    }
394
395    /// Sets a specific theme for the window.
396    ///
397    /// If `None` is provided, the window will use the system theme.
398    ///
399    /// The default is `None`.
400    ///
401    /// ## Platform-specific
402    ///
403    /// - **Wayland:** This controls only CSD. When using `None` it'll try to use dbus to get the
404    ///   system preference. When explicit theme is used, this will avoid dbus all together.
405    /// - **x11:** Build window with `_GTK_THEME_VARIANT` hint set to `dark` or `light`.
406    /// - **iOS / Android / Web / x11 / Orbital:** Ignored.
407    #[inline]
408    pub fn with_theme(mut self, theme: Option<Theme>) -> Self {
409        self.preferred_theme = theme;
410        self
411    }
412
413    /// Prevents the window contents from being captured by other apps.
414    ///
415    /// The default is `false`.
416    ///
417    /// ## Platform-specific
418    ///
419    /// - **macOS**: if `false`, [`NSWindowSharingNone`] is used but doesn't completely prevent all
420    ///   apps from reading the window content, for instance, QuickTime.
421    /// - **iOS / Android / Web / x11 / Orbital:** Ignored.
422    ///
423    /// [`NSWindowSharingNone`]: https://developer.apple.com/documentation/appkit/nswindowsharingtype/nswindowsharingnone
424    #[inline]
425    pub fn with_content_protected(mut self, protected: bool) -> Self {
426        self.content_protected = protected;
427        self
428    }
429
430    /// Whether the window will be initially focused or not.
431    ///
432    /// The window should be assumed as not focused by default
433    /// following by the [`WindowEvent::Focused`].
434    ///
435    /// For [`WindowType::Popup`] windows, also controls keyboard grabbing — see
436    /// [`WindowAttributes::active`] for details.
437    ///
438    /// ## Platform-specific:
439    ///
440    /// **Android / iOS / X11 / Orbital:** Unsupported.
441    /// **Wayland:** Only supported for [`WindowType::Popup`].
442    ///
443    /// [`WindowEvent::Focused`]: crate::event::WindowEvent::Focused
444    #[inline]
445    pub fn with_active(mut self, active: bool) -> Self {
446        self.active = active;
447        self
448    }
449
450    /// Modifies the cursor icon of the window.
451    ///
452    /// The default is [`CursorIcon::Default`].
453    ///
454    /// See [`Window::set_cursor()`] for more details.
455    #[inline]
456    pub fn with_cursor(mut self, cursor: impl Into<Cursor>) -> Self {
457        self.cursor = cursor.into();
458        self
459    }
460
461    /// Build window with parent window.
462    ///
463    /// The default is `None`.
464    ///
465    /// ## Safety
466    ///
467    /// `parent_window` must be a valid window handle.
468    ///
469    /// ## Platform-specific
470    ///
471    /// - **Windows** : A child window has the WS_CHILD style and is confined
472    ///   to the client area of its parent window. For more information, see
473    ///   <https://docs.microsoft.com/en-us/windows/win32/winmsg/window-features#child-windows>
474    /// - **X11**: A child window is confined to the client area of its parent window.
475    /// - **Android / iOS / Wayland / Web:** Unsupported.
476    #[inline]
477    pub unsafe fn with_parent_window(
478        mut self,
479        parent_window: Option<rwh_06::RawWindowHandle>,
480    ) -> Self {
481        self.parent_window = parent_window.map(SendSyncRawWindowHandle);
482        self
483    }
484
485    /// Set the platform specific opaque attribute object.
486    ///
487    /// The interpretation will depend on the underlying backend that will be used.
488    #[inline]
489    pub fn with_platform_attributes(mut self, platform: Box<dyn PlatformWindowAttributes>) -> Self {
490        self.platform = Some(platform);
491        self
492    }
493
494    /// Sets the [`WindowType`] (window vs. popup).
495    ///
496    /// Used by the Windows, Wayland and macOS backends; on X11 [`WindowType::Popup`] is not
497    /// implemented and window creation returns an error.
498    /// If the type is [`WindowType::Popup`], the parent must also be set via
499    /// [`with_parent_window`](Self::with_parent_window), and the position is interpreted
500    /// relative to that parent.
501    ///
502    /// See [`WindowType::Popup`] for the per-platform behavior, including how to obtain a
503    /// rounded, native-looking popup on macOS.
504    pub fn with_window_type(mut self, window_type: WindowType) -> Self {
505        self.window_type = window_type;
506        self
507    }
508
509    /// Returns if the window type is a popup or a normal window
510    #[inline]
511    pub fn window_type(&self) -> WindowType {
512        self.window_type
513    }
514
515    /// Sets the positioner used to place the window relative to its anchor rect.
516    ///
517    /// See [`WindowPositioner`] and its fields for what each part of the positioner controls and
518    /// its default when left as `None`.
519    ///
520    /// ## Platform-specific
521    ///
522    /// - **Wayland:** Only takes effect when the window is a [`WindowType::Popup`], since the
523    ///   Wayland positioner is part of the `xdg_popup` protocol role.
524    /// - **macOS, Windows:** Works for both [`WindowType::Window`] and [`WindowType::Popup`]. A
525    ///   [`WindowType::Popup`] always requires a parent window to be set via
526    ///   [`with_parent_window`](Self::with_parent_window). A [`WindowType::Window`] without a
527    ///   parent is positioned relative to the screen's available space instead of the parent's
528    ///   content area.
529    /// - **X11, Web, Android, iOS, Orbital:** No effect.
530    #[inline]
531    pub fn with_positioner(mut self, positioner: WindowPositioner) -> Self {
532        self.positioner = Some(positioner);
533        self
534    }
535}
536
537impl Clone for WindowAttributes {
538    fn clone(&self) -> Self {
539        Self {
540            surface_size: self.surface_size,
541            min_surface_size: self.min_surface_size,
542            max_surface_size: self.max_surface_size,
543            surface_resize_increments: self.surface_resize_increments,
544            position: self.position,
545            resizable: self.resizable,
546            enabled_buttons: self.enabled_buttons,
547            title: self.title.clone(),
548            maximized: self.maximized,
549            visible: self.visible,
550            transparent: self.transparent,
551            blur: self.blur,
552            decorations: self.decorations,
553            window_icon: self.window_icon.clone(),
554            preferred_theme: self.preferred_theme,
555            content_protected: self.content_protected,
556            window_level: self.window_level,
557            active: self.active,
558            cursor: self.cursor.clone(),
559            parent_window: self.parent_window.clone(),
560            fullscreen: self.fullscreen.clone(),
561            platform: self.platform.as_ref().map(|platform| platform.box_clone()),
562            window_type: self.window_type,
563            positioner: self.positioner,
564        }
565    }
566}
567
568impl Default for WindowAttributes {
569    #[inline]
570    fn default() -> WindowAttributes {
571        WindowAttributes {
572            enabled_buttons: WindowButtons::all(),
573            title: String::from("winit window"),
574            decorations: true,
575            resizable: true,
576            visible: true,
577            active: true,
578            surface_resize_increments: Default::default(),
579            content_protected: Default::default(),
580            min_surface_size: Default::default(),
581            max_surface_size: Default::default(),
582            preferred_theme: Default::default(),
583            parent_window: Default::default(),
584            surface_size: Default::default(),
585            window_level: Default::default(),
586            window_icon: Default::default(),
587            transparent: Default::default(),
588            fullscreen: Default::default(),
589            maximized: Default::default(),
590            position: Default::default(),
591            platform: Default::default(),
592            cursor: Cursor::default(),
593            blur: Default::default(),
594            window_type: Default::default(),
595            positioner: Default::default(),
596        }
597    }
598}
599
600/// Wrapper for [`rwh_06::RawWindowHandle`] for [`WindowAttributes::parent_window`].
601///
602/// # Safety
603///
604/// The user has to account for that when using [`WindowAttributes::with_parent_window()`],
605/// which is `unsafe`.
606#[derive(Debug, Clone, PartialEq)]
607pub(crate) struct SendSyncRawWindowHandle(pub(crate) rwh_06::RawWindowHandle);
608
609unsafe impl Send for SendSyncRawWindowHandle {}
610unsafe impl Sync for SendSyncRawWindowHandle {}
611
612pub trait PlatformWindowAttributes: Any + std::fmt::Debug + Send + Sync {
613    fn box_clone(&self) -> Box<dyn PlatformWindowAttributes>;
614}
615
616impl_dyn_casting!(PlatformWindowAttributes);
617
618/// Represents a window.
619///
620/// The window is closed when dropped.
621///
622/// ## Threading
623///
624/// This is `Send + Sync`, meaning that it can be freely used from other
625/// threads.
626///
627/// However, some platforms (macOS, Web and iOS) only allow user interface
628/// interactions on the main thread, so on those platforms, if you use the
629/// window from a thread other than the main, the code is scheduled to run on
630/// the main thread, and your thread may be blocked until that completes.
631///
632/// ## Platform-specific
633///
634/// **Web:** The [`Window`], which is represented by a `HTMLElementCanvas`, can
635/// not be closed by dropping the [`Window`].
636pub trait Window: Any + Send + Sync + fmt::Debug {
637    /// Returns the window type of this window
638    fn window_type(&self) -> WindowType;
639
640    /// Returns the positioner used to place this window relative to its anchor rect.
641    ///
642    /// Returns [`WindowPositioner::default`] if this window doesn't use anchor positioning, see
643    /// [`WindowAttributes::with_positioner`].
644    ///
645    /// ## Platform-specific
646    ///
647    /// - **Wayland:** Always [`WindowPositioner::default`] unless the window is a
648    ///   [`WindowType::Popup`], since the Wayland positioner is part of the `xdg_popup` protocol
649    ///   role.
650    fn positioner(&self) -> WindowPositioner {
651        WindowPositioner::default()
652    }
653
654    /// Sets the positioner used to place this window relative to its anchor rect.
655    ///
656    /// No-op if this window doesn't use anchor positioning, see
657    /// [`WindowAttributes::with_positioner`].
658    ///
659    /// ## Platform-specific
660    ///
661    /// - **Wayland:** No-op unless the window is a [`WindowType::Popup`], since the Wayland
662    ///   positioner is part of the `xdg_popup` protocol role.
663    fn set_positioner(&self, _positioner: WindowPositioner) {}
664
665    /// Returns an identifier unique to the window.
666    fn id(&self) -> WindowId;
667
668    /// Returns the scale factor that can be used to map logical pixels to physical pixels, and
669    /// vice versa.
670    ///
671    /// Note that this value can change depending on user action (for example if the window is
672    /// moved to another screen); as such, tracking [`WindowEvent::ScaleFactorChanged`] events is
673    /// the most robust way to track the DPI you need to use to draw.
674    ///
675    /// This value may differ from [`MonitorHandleProvider::scale_factor`].
676    ///
677    /// See the [`dpi`] crate for more information.
678    ///
679    /// ## Platform-specific
680    ///
681    /// The scale factor is calculated differently on different platforms:
682    ///
683    /// - **Windows:** On Windows 8 and 10, per-monitor scaling is readily configured by users from
684    ///   the display settings. While users are free to select any option they want, they're only
685    ///   given a selection of "nice" scale factors, i.e. 1.0, 1.25, 1.5... on Windows 7. The scale
686    ///   factor is global and changing it requires logging out. See [this article][windows_1] for
687    ///   technical details.
688    /// - **macOS:** Recent macOS versions allow the user to change the scaling factor for specific
689    ///   displays. When available, the user may pick a per-monitor scaling factor from a set of
690    ///   pre-defined settings. All "retina displays" have a scaling factor above 1.0 by default,
691    ///   but the specific value varies across devices.
692    /// - **X11:** Many man-hours have been spent trying to figure out how to handle DPI in X11.
693    ///   Winit currently uses a three-pronged approach:
694    ///   + Use the value in the `WINIT_X11_SCALE_FACTOR` environment variable if present.
695    ///   + If not present, use the value set in `Xft.dpi` in Xresources.
696    ///   + Otherwise, calculate the scale factor based on the millimeter monitor dimensions
697    ///     provided by XRandR.
698    ///
699    ///   If `WINIT_X11_SCALE_FACTOR` is set to `randr`, it'll ignore the `Xft.dpi` field and use
700    ///   the   XRandR scaling method. Generally speaking, you should try to configure the
701    ///   standard system   variables to do what you want before resorting to
702    ///   `WINIT_X11_SCALE_FACTOR`.
703    /// - **Wayland:** The scale factor is suggested by the compositor for each window individually
704    ///   by using the wp-fractional-scale protocol if available. Falls back to integer-scale
705    ///   factors otherwise.
706    ///
707    ///   The monitor scale factor may differ from the window scale factor.
708    /// - **iOS:** Scale factors are set by Apple to the value that best suits the device, and range
709    ///   from `1.0` to `3.0`. See [this article][apple_1] and [this article][apple_2] for more
710    ///   information.
711    ///
712    ///   This uses the underlying `UIView`'s [`contentScaleFactor`].
713    /// - **Android:** Scale factors are set by the manufacturer to the value that best suits the
714    ///   device, and range from `1.0` to `4.0`. See [this article][android_1] for more information.
715    ///
716    ///   This is currently unimplemented, and this function always returns 1.0.
717    /// - **Web:** The scale factor is the ratio between CSS pixels and the physical device pixels.
718    ///   In other words, it is the value of [`window.devicePixelRatio`][web_1]. It is affected by
719    ///   both the screen scaling and the browser zoom level and can go below `1.0`.
720    /// - **Orbital:** This is currently unimplemented, and this function always returns 1.0.
721    ///
722    /// [`WindowEvent::ScaleFactorChanged`]: crate::event::WindowEvent::ScaleFactorChanged
723    /// [windows_1]: https://docs.microsoft.com/en-us/windows/win32/hidpi/high-dpi-desktop-application-development-on-windows
724    /// [apple_1]: https://developer.apple.com/library/archive/documentation/DeviceInformation/Reference/iOSDeviceCompatibility/Displays/Displays.html
725    /// [apple_2]: https://developer.apple.com/design/human-interface-guidelines/macos/icons-and-images/image-size-and-resolution/
726    /// [android_1]: https://developer.android.com/training/multiscreen/screendensities
727    /// [web_1]: https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio
728    /// [`contentScaleFactor`]: https://developer.apple.com/documentation/uikit/uiview/1622657-contentscalefactor?language=objc
729    /// [`MonitorHandleProvider::scale_factor`]: crate::monitor::MonitorHandleProvider::scale_factor.
730    fn scale_factor(&self) -> f64;
731
732    /// Queues a [`WindowEvent::RedrawRequested`] event to be emitted that aligns with the windowing
733    /// system drawing loop.
734    ///
735    /// This is the **strongly encouraged** method of redrawing windows, as it can integrate with
736    /// OS-requested redraws (e.g. when a window gets resized). To improve the event delivery
737    /// consider using [`Window::pre_present_notify`] as described in docs.
738    ///
739    /// Applications should always aim to redraw whenever they receive a `RedrawRequested` event.
740    ///
741    /// There are no strong guarantees about when exactly a `RedrawRequest` event will be emitted
742    /// with respect to other events, since the requirements can vary significantly between
743    /// windowing systems.
744    ///
745    /// However as the event aligns with the windowing system drawing loop, it may not arrive in
746    /// same or even next event loop iteration.
747    ///
748    /// ## Platform-specific
749    ///
750    /// - **Windows** This API uses `RedrawWindow` to request a `WM_PAINT` message and
751    ///   `RedrawRequested` is emitted in sync with any `WM_PAINT` messages.
752    /// - **Wayland:** The events are aligned with the frame callbacks when
753    ///   [`Window::pre_present_notify`] is used.
754    /// - **Web:** [`WindowEvent::RedrawRequested`] will be aligned with the
755    ///   `requestAnimationFrame`.
756    ///
757    /// [`WindowEvent::RedrawRequested`]: crate::event::WindowEvent::RedrawRequested
758    fn request_redraw(&self);
759
760    /// Notify the windowing system before presenting to the window.
761    ///
762    /// You should call this event after your drawing operations, but before you submit
763    /// the buffer to the display or commit your drawings. Doing so will help winit to properly
764    /// schedule and make assumptions about its internal state. For example, it could properly
765    /// throttle [`WindowEvent::RedrawRequested`].
766    ///
767    /// ## Example
768    ///
769    /// This example illustrates how it looks with OpenGL, but it applies to other graphics
770    /// APIs and software rendering.
771    ///
772    /// ```no_run
773    /// # use winit_core::window::Window;
774    /// # fn swap_buffers() {}
775    /// # fn scope(window: &dyn Window) {
776    /// // Do the actual drawing with OpenGL.
777    ///
778    /// // Notify winit that we're about to submit buffer to the windowing system.
779    /// window.pre_present_notify();
780    ///
781    /// // Submit buffer to the windowing system.
782    /// swap_buffers();
783    /// # }
784    /// ```
785    ///
786    /// ## Platform-specific
787    ///
788    /// - **Android / iOS / X11 / Web / Windows / macOS / Orbital:** Unsupported.
789    /// - **Wayland:** Schedules a frame callback to throttle [`WindowEvent::RedrawRequested`].
790    ///
791    /// [`WindowEvent::RedrawRequested`]: crate::event::WindowEvent::RedrawRequested
792    fn pre_present_notify(&self);
793
794    /// Reset the dead key state of the keyboard.
795    ///
796    /// This is useful when a dead key is bound to trigger an action. Then
797    /// this function can be called to reset the dead key state so that
798    /// follow-up text input won't be affected by the dead key.
799    ///
800    /// ## Platform-specific
801    /// - **Web, macOS:** Does nothing
802    // ---------------------------
803    // Developers' Note: If this cannot be implemented on every desktop platform
804    // at least, then this function should be provided through a platform specific
805    // extension trait
806    fn reset_dead_keys(&self);
807
808    /// The position of the top-left hand corner of the surface relative to the top-left hand corner
809    /// of the window.
810    ///
811    /// This, combined with [`outer_position`], can be useful for calculating the position of the
812    /// surface relative to the desktop.
813    ///
814    /// This may also be useful for figuring out the size of the window's decorations (such as
815    /// buttons, title, etc.), but may also not correspond to that (e.g. if the title bar is made
816    /// transparent on macOS, or your are drawing window
817    /// decorations yourself).
818    ///
819    /// This may be negative.
820    ///
821    /// If the window does not have any decorations, and the surface is in the exact same position
822    /// as the window itself, this simply returns `(0, 0)`.
823    ///
824    /// [`outer_position`]: Self::outer_position
825    fn surface_position(&self) -> PhysicalPosition<i32>;
826
827    /// The position of the top-left hand corner of the window relative to the top-left hand corner
828    /// of the desktop.
829    ///
830    /// Note that the top-left hand corner of the desktop is not necessarily the same as
831    /// the screen. If the user uses a desktop with multiple monitors, the top-left hand corner
832    /// of the desktop is the top-left hand corner of the primary monitor of the desktop.
833    ///
834    /// The coordinates can be negative if the top-left hand corner of the window is outside
835    /// of the visible screen region, or on another monitor than the primary.
836    ///
837    /// For a [`WindowType::Popup`] with a parent, the position is instead reported relative to the
838    /// top-left hand corner of the parent window's content area, mirroring the coordinate system
839    /// used by [`Window::set_outer_position`].
840    ///
841    /// ## Platform-specific
842    ///
843    /// - **Web:** Returns the top-left coordinates relative to the viewport.
844    /// - **Android:** Always returns [`RequestError::NotSupported`].
845    /// - **Wayland:** For a top-level window this always returns [`RequestError::NotSupported`],
846    ///   since the compositor does not report absolute positions. For a [`WindowType::Popup`] the
847    ///   compositor-decided position relative to the parent is returned once the popup has been
848    ///   configured (before that, [`RequestError::NotSupported`]).
849    fn outer_position(&self) -> Result<PhysicalPosition<i32>, RequestError>;
850
851    /// Sets the position of the window on the desktop.
852    ///
853    /// See [`Window::outer_position`] for more information about the coordinates.
854    /// This automatically un-maximizes the window if it's maximized.
855    ///
856    /// ```no_run
857    /// # use dpi::{LogicalPosition, PhysicalPosition};
858    /// # use winit_core::window::Window;
859    /// # fn scope(window: &dyn Window) {
860    /// // Specify the position in logical dimensions like this:
861    /// window.set_outer_position(LogicalPosition::new(400.0, 200.0).into());
862    ///
863    /// // Or specify the position in physical dimensions like this:
864    /// window.set_outer_position(PhysicalPosition::new(400, 200).into());
865    /// # }
866    /// ```
867    ///
868    /// ## Platform-specific
869    ///
870    /// - **iOS:** Sets the top left coordinates of the window in the screen space coordinate
871    ///   system.
872    /// - **Web:** Sets the top-left coordinates relative to the viewport. Doesn't account for CSS
873    ///   [`transform`].
874    /// - **Android / Wayland:** Unsupported.
875    ///
876    /// [`transform`]: https://developer.mozilla.org/en-US/docs/Web/CSS/transform
877    fn set_outer_position(&self, position: Position);
878
879    /// Returns the size of the window's render-able surface.
880    ///
881    /// This is the dimensions you should pass to things like Wgpu or Glutin when configuring the
882    /// surface for drawing. See [`WindowEvent::SurfaceResized`] for listening to changes to this
883    /// field.
884    ///
885    /// Note that to ensure that your content is not obscured by things such as notches or the title
886    /// bar, you will likely want to only draw important content inside a specific area of the
887    /// surface, see [`safe_area()`] for details.
888    ///
889    /// ## Platform-specific
890    ///
891    /// - **Web:** Returns the size of the canvas element. Doesn't account for CSS [`transform`].
892    ///
893    /// [`transform`]: https://developer.mozilla.org/en-US/docs/Web/CSS/transform
894    /// [`WindowEvent::SurfaceResized`]: crate::event::WindowEvent::SurfaceResized
895    /// [`safe_area()`]: Window::safe_area
896    fn surface_size(&self) -> PhysicalSize<u32>;
897
898    /// Request the new size for the surface.
899    ///
900    /// On platforms where the size is entirely controlled by the user the
901    /// applied size will be returned immediately, resize event in such case
902    /// may not be generated.
903    ///
904    /// On platforms where resizing is disallowed by the windowing system, the current surface size
905    /// is returned immediately, and the user one is ignored.
906    ///
907    /// When `None` is returned, it means that the request went to the display system,
908    /// and the actual size will be delivered later with the [`WindowEvent::SurfaceResized`].
909    ///
910    /// See [`Window::surface_size`] for more information about the values.
911    ///
912    /// The request could automatically un-maximize the window if it's maximized.
913    ///
914    /// ```no_run
915    /// # use dpi::{LogicalSize, PhysicalSize};
916    /// # use winit_core::window::Window;
917    /// # fn scope(window: &dyn Window) {
918    /// // Specify the size in logical dimensions like this:
919    /// let _ = window.request_surface_size(LogicalSize::new(400.0, 200.0).into());
920    ///
921    /// // Or specify the size in physical dimensions like this:
922    /// let _ = window.request_surface_size(PhysicalSize::new(400, 200).into());
923    /// # }
924    /// ```
925    ///
926    /// ## Platform-specific
927    ///
928    /// - **Web:** Sets the size of the canvas element. Doesn't account for CSS [`transform`].
929    ///
930    /// [`WindowEvent::SurfaceResized`]: crate::event::WindowEvent::SurfaceResized
931    /// [`transform`]: https://developer.mozilla.org/en-US/docs/Web/CSS/transform
932    #[must_use]
933    fn request_surface_size(&self, size: Size) -> Option<PhysicalSize<u32>>;
934
935    /// Returns the size of the entire window.
936    ///
937    /// These dimensions include window decorations like the title bar and borders. If you don't
938    /// want that (and you usually don't), use [`Window::surface_size`] instead.
939    ///
940    /// ## Platform-specific
941    ///
942    /// - **Web:** Returns the size of the canvas element. _Note: this returns the same value as
943    ///   [`Window::surface_size`]._
944    fn outer_size(&self) -> PhysicalSize<u32>;
945
946    /// The inset area of the surface that is unobstructed.
947    ///
948    /// On some devices, especially mobile devices, the screen is not a perfect rectangle, and may
949    /// have rounded corners, notches, bezels, and so on. When drawing your content, you usually
950    /// want to draw your background and other such unimportant content on the entire surface, while
951    /// you will want to restrict important content such as text, interactable or visual indicators
952    /// to the part of the screen that is actually visible; for this, you use the safe area.
953    ///
954    /// The safe area is a rectangle that is defined relative to the origin at the top-left corner
955    /// of the surface, and the size extending downwards to the right. The area will not extend
956    /// beyond [the bounds of the surface][Window::surface_size].
957    ///
958    /// Note that the safe area does not take occlusion from other windows into account; in a way,
959    /// it is only a "hardware"-level occlusion.
960    ///
961    /// If the entire content of the surface is visible, this returns `(0, 0, 0, 0)`.
962    ///
963    /// ## Platform-specific
964    ///
965    /// - **Android / Orbital / Wayland / Windows / X11:** Unimplemented, returns `(0, 0, 0, 0)`.
966    ///
967    /// ## Example
968    ///
969    /// Convert safe area insets to a size and a position.
970    ///
971    /// ```
972    /// use dpi::{PhysicalPosition, PhysicalSize};
973    ///
974    /// # let surface_size = dpi::PhysicalSize::new(0, 0);
975    /// # #[cfg(requires_window)]
976    /// let surface_size = window.surface_size();
977    /// # let insets = dpi::PhysicalInsets::new(0, 0, 0, 0);
978    /// # #[cfg(requires_window)]
979    /// let insets = window.safe_area();
980    ///
981    /// let origin = PhysicalPosition::new(insets.left, insets.top);
982    /// let size = PhysicalSize::new(
983    ///     surface_size.width - insets.left - insets.right,
984    ///     surface_size.height - insets.top - insets.bottom,
985    /// );
986    /// ```
987    fn safe_area(&self) -> PhysicalInsets<u32>;
988
989    /// Sets a minimum dimensions of the window's surface.
990    ///
991    /// ```no_run
992    /// # use dpi::{LogicalSize, PhysicalSize};
993    /// # use winit_core::window::Window;
994    /// # fn scope(window: &dyn Window) {
995    /// // Specify the size in logical dimensions like this:
996    /// window.set_min_surface_size(Some(LogicalSize::new(400.0, 200.0).into()));
997    ///
998    /// // Or specify the size in physical dimensions like this:
999    /// window.set_min_surface_size(Some(PhysicalSize::new(400, 200).into()));
1000    /// # }
1001    /// ```
1002    ///
1003    /// ## Platform-specific
1004    ///
1005    /// - **iOS / Android / Orbital:** Unsupported.
1006    fn set_min_surface_size(&self, min_size: Option<Size>);
1007
1008    /// Sets a maximum dimensions of the window's surface.
1009    ///
1010    /// ```no_run
1011    /// # use dpi::{LogicalSize, PhysicalSize};
1012    /// # use winit_core::window::Window;
1013    /// # fn scope(window: &dyn Window) {
1014    /// // Specify the size in logical dimensions like this:
1015    /// window.set_max_surface_size(Some(LogicalSize::new(400.0, 200.0).into()));
1016    ///
1017    /// // Or specify the size in physical dimensions like this:
1018    /// window.set_max_surface_size(Some(PhysicalSize::new(400, 200).into()));
1019    /// # }
1020    /// ```
1021    ///
1022    /// ## Platform-specific
1023    ///
1024    /// - **iOS / Android / Orbital:** Unsupported.
1025    fn set_max_surface_size(&self, max_size: Option<Size>);
1026
1027    /// Returns surface resize increments if any were set.
1028    ///
1029    /// ## Platform-specific
1030    ///
1031    /// - **iOS / Android / Web / Orbital:** Always returns [`None`].
1032    fn surface_resize_increments(&self) -> Option<PhysicalSize<u32>>;
1033
1034    /// Sets resize increments of the surface.
1035    ///
1036    /// This is a niche constraint hint usually employed by terminal emulators and other such apps
1037    /// that need "blocky" resizes.
1038    ///
1039    /// ## Platform-specific
1040    ///
1041    /// - **macOS:** Increments are converted to logical size and then macOS rounds them to whole
1042    ///   numbers.
1043    /// - **iOS / Android / Web / Orbital:** Unsupported.
1044    fn set_surface_resize_increments(&self, increments: Option<Size>);
1045
1046    /// Modifies the title of the window.
1047    ///
1048    /// ## Platform-specific
1049    ///
1050    /// - **iOS / Android:** Unsupported.
1051    fn set_title(&self, title: &str);
1052
1053    /// Change the window transparency state.
1054    ///
1055    /// This is just a hint that may not change anything about
1056    /// the window transparency, however doing a mismatch between
1057    /// the content of your window and this hint may result in
1058    /// visual artifacts.
1059    ///
1060    /// The default value follows the [`WindowAttributes::with_transparent`].
1061    ///
1062    /// ## Platform-specific
1063    ///
1064    /// - **macOS:** This will reset the window's background color.
1065    /// - **Web / iOS / Android:** Unsupported.
1066    /// - **X11:** Can only be set while building the window, with
1067    ///   [`WindowAttributes::with_transparent`].
1068    fn set_transparent(&self, transparent: bool);
1069
1070    /// Change the window blur state.
1071    ///
1072    /// If `true`, this will make the transparent window background blurry.
1073    ///
1074    /// ## Platform-specific
1075    ///
1076    /// - **macOS:** Renders a translucent system material behind the window's contents, which is
1077    ///   tinted and follows the window's appearance, rather than a blur of a specific radius. Which
1078    ///   material is used can be chosen with `WindowAttributesMacOS::with_blur_material` and
1079    ///   `WindowExtMacOS::set_blur_material`. The window's `contentView` is a container holding the
1080    ///   view returned by `raw-window-handle`, and the material is a sibling behind it. With the
1081    ///   `private-apple-apis` Cargo feature enabled, a private API is used instead to apply an
1082    ///   untinted backdrop blur of a fixed radius; this can cause App Store rejection. On macOS
1083    ///   10.12 and older, enabling blur makes the window's views layer-backed, which may break the
1084    ///   association with an attached `NSOpenGLContext`.
1085    /// - **Android / iOS / X11 / Web / Windows:** Unsupported.
1086    /// - **Wayland:** Only works with `org_kde_kwin_blur_manager` or
1087    ///   `ext_background_effect_manager_v1` protocol.
1088    fn set_blur(&self, blur: bool);
1089
1090    /// Modifies the window's visibility.
1091    ///
1092    /// If `false`, this will hide the window. If `true`, this will show the window.
1093    ///
1094    /// ## Platform-specific
1095    ///
1096    /// - **Android / Wayland / Web:** Unsupported.
1097    fn set_visible(&self, visible: bool);
1098
1099    /// Gets the window's current visibility state.
1100    ///
1101    /// `None` means it couldn't be determined, so it is not recommended to use this to drive your
1102    /// rendering backend.
1103    ///
1104    /// ## Platform-specific
1105    ///
1106    /// - **X11:** Not implemented.
1107    /// - **Wayland / iOS / Android / Web:** Unsupported.
1108    fn is_visible(&self) -> Option<bool>;
1109
1110    /// Sets whether the window is resizable or not.
1111    ///
1112    /// Note that making the window unresizable doesn't exempt you from handling
1113    /// [`WindowEvent::SurfaceResized`], as that event can still be triggered by DPI scaling,
1114    /// entering fullscreen mode, etc. Also, the window could still be resized by calling
1115    /// [`Window::request_surface_size`].
1116    ///
1117    /// ## Platform-specific
1118    ///
1119    /// This only has an effect on desktop platforms.
1120    ///
1121    /// - **X11:** Due to a bug in XFCE, this has no effect on Xfwm.
1122    /// - **iOS / Android / Web:** Unsupported.
1123    ///
1124    /// [`WindowEvent::SurfaceResized`]: crate::event::WindowEvent::SurfaceResized
1125    fn set_resizable(&self, resizable: bool);
1126
1127    /// Gets the window's current resizable state.
1128    ///
1129    /// ## Platform-specific
1130    ///
1131    /// - **X11:** Not implemented.
1132    /// - **iOS / Android / Web:** Unsupported.
1133    fn is_resizable(&self) -> bool;
1134
1135    /// Sets the enabled window buttons.
1136    ///
1137    /// ## Platform-specific
1138    ///
1139    /// - **Wayland / X11 / Orbital:** Not implemented.
1140    /// - **Web / iOS / Android:** Unsupported.
1141    fn set_enabled_buttons(&self, buttons: WindowButtons);
1142
1143    /// Gets the enabled window buttons.
1144    ///
1145    /// ## Platform-specific
1146    ///
1147    /// - **Wayland / X11 / Orbital:** Not implemented. Always returns [`WindowButtons::all`].
1148    /// - **Web / iOS / Android:** Unsupported. Always returns [`WindowButtons::all`].
1149    fn enabled_buttons(&self) -> WindowButtons;
1150
1151    /// Minimize the window, or put it back from the minimized state.
1152    ///
1153    /// ## Platform-specific
1154    ///
1155    /// - **iOS / Android / Web / Orbital:** Unsupported.
1156    /// - **Wayland:** Un-minimize is unsupported.
1157    fn set_minimized(&self, minimized: bool);
1158
1159    /// Gets the window's current minimized state.
1160    ///
1161    /// `None` will be returned, if the minimized state couldn't be determined.
1162    ///
1163    /// ## Note
1164    ///
1165    /// - You shouldn't stop rendering for minimized windows, however you could lower the fps.
1166    ///
1167    /// ## Platform-specific
1168    ///
1169    /// - **Wayland**: always `None`.
1170    /// - **iOS / Android / Web / Orbital:** Unsupported.
1171    fn is_minimized(&self) -> Option<bool>;
1172
1173    /// Sets the window to maximized or back.
1174    ///
1175    /// ## Platform-specific
1176    ///
1177    /// - **iOS / Android / Web:** Unsupported.
1178    fn set_maximized(&self, maximized: bool);
1179
1180    /// Gets the window's current maximized state.
1181    ///
1182    /// ## Platform-specific
1183    ///
1184    /// - **iOS / Android / Web:** Unsupported.
1185    fn is_maximized(&self) -> bool;
1186
1187    /// Set the window's fullscreen state.
1188    ///
1189    /// ## Platform-specific
1190    ///
1191    /// - **macOS:** [`Fullscreen::Exclusive`] provides true exclusive mode with a video mode
1192    ///   change. *Caveat!* macOS doesn't provide task switching (or spaces!) while in exclusive
1193    ///   fullscreen mode. This mode should be used when a video mode change is desired, but for a
1194    ///   better user experience, borderless fullscreen might be preferred.
1195    ///
1196    ///   [`Fullscreen::Borderless`] provides a borderless fullscreen window on a
1197    ///   separate space. This is the idiomatic way for fullscreen games to work
1198    ///   on macOS. See `WindowExtMacOs::set_simple_fullscreen` if
1199    ///   separate spaces are not preferred.
1200    ///
1201    ///   The dock and the menu bar are disabled in exclusive fullscreen mode.
1202    /// - **Orbital / Wayland:** Does not support exclusive fullscreen mode and will no-op a
1203    ///   request.
1204    /// - **Windows:** Screen saver is disabled in fullscreen mode.
1205    /// - **Web:** Passing a [`MonitorHandle`] or [`VideoMode`] that was not created with detailed
1206    ///   monitor permissions or calling without a [transient activation] does nothing.
1207    ///
1208    /// [transient activation]: https://developer.mozilla.org/en-US/docs/Glossary/Transient_activation
1209    /// [`VideoMode`]: crate::monitor::VideoMode
1210    fn set_fullscreen(&self, fullscreen: Option<Fullscreen>);
1211
1212    /// Gets the window's current fullscreen state.
1213    ///
1214    /// ## Platform-specific
1215    ///
1216    /// - **Android:** Will always return `None`.
1217    /// - **Orbital / Web:** Can only return `None` or `Borderless(None)`.
1218    /// - **Wayland:** Can return `Borderless(None)` when there are no monitors.
1219    fn fullscreen(&self) -> Option<Fullscreen>;
1220
1221    /// Turn window decorations on or off.
1222    ///
1223    /// Enable/disable window decorations provided by the server or Winit.
1224    /// By default this is enabled. Note that fullscreen windows and windows on
1225    /// mobile and Web platforms naturally do not have decorations.
1226    ///
1227    /// ## Platform-specific
1228    ///
1229    /// - **iOS / Android / Web:** No effect.
1230    fn set_decorations(&self, decorations: bool);
1231
1232    /// Gets the window's current decorations state.
1233    ///
1234    /// Returns `true` when windows are decorated (server-side or by Winit).
1235    /// Also returns `true` when no decorations are required (mobile, Web).
1236    ///
1237    /// ## Platform-specific
1238    ///
1239    /// - **iOS / Android / Web:** Always returns `true`.
1240    fn is_decorated(&self) -> bool;
1241
1242    /// Change the window level.
1243    ///
1244    /// This is just a hint to the OS, and the system could ignore it.
1245    ///
1246    /// See [`WindowLevel`] for details.
1247    fn set_window_level(&self, level: WindowLevel);
1248
1249    /// Sets the window icon.
1250    ///
1251    /// On Windows, Wayland and X11, this is typically the small icon in the top-left
1252    /// corner of the titlebar.
1253    ///
1254    /// ## Platform-specific
1255    ///
1256    /// - **iOS / Android / Web / / macOS / Orbital:** Unsupported.
1257    ///
1258    /// - **Windows:** Sets `ICON_SMALL`. The base size for a window icon is 16x16, but it's
1259    ///   recommended to account for screen scaling and pick a multiple of that, i.e. 32x32.
1260    ///
1261    /// - **X11:** Has no universal guidelines for icon sizes, so you're at the whims of the WM.
1262    ///   That said, it's usually in the same ballpark as on Windows.
1263    ///
1264    /// - **Wayland:** The compositor needs to implement `xdg_toplevel_icon`.
1265    fn set_window_icon(&self, window_icon: Option<Icon>);
1266
1267    /// Set the IME cursor editing area, where the `position` is the top left corner of that area
1268    /// in surface coordinates and `size` is the size of this area starting from the position. An
1269    /// example of such area could be a input field in the UI or line in the editor.
1270    ///
1271    /// The windowing system could place a candidate box close to that area, but try to not obscure
1272    /// the specified area, so the user input to it stays visible.
1273    ///
1274    /// The candidate box is the window / popup / overlay that allows you to select the desired
1275    /// characters. The look of this box may differ between input devices, even on the same
1276    /// platform.
1277    ///
1278    /// (Apple's official term is "candidate window", see their [chinese] and [japanese] guides).
1279    ///
1280    /// ## Example
1281    ///
1282    /// ```no_run
1283    /// # use dpi::{LogicalPosition, PhysicalPosition, LogicalSize, PhysicalSize};
1284    /// # use winit_core::window::Window;
1285    /// # fn scope(window: &dyn Window) {
1286    /// // Specify the position in logical dimensions like this:
1287    /// window.set_ime_cursor_area(
1288    ///     LogicalPosition::new(400.0, 200.0).into(),
1289    ///     LogicalSize::new(100, 100).into(),
1290    /// );
1291    ///
1292    /// // Or specify the position in physical dimensions like this:
1293    /// window.set_ime_cursor_area(
1294    ///     PhysicalPosition::new(400, 200).into(),
1295    ///     PhysicalSize::new(100, 100).into(),
1296    /// );
1297    /// # }
1298    /// ```
1299    ///
1300    /// ## Platform-specific
1301    ///
1302    /// - **iOS / Android / Web / Orbital:** Unsupported.
1303    ///
1304    /// [chinese]: https://support.apple.com/guide/chinese-input-method/use-the-candidate-window-cim12992/104/mac/12.0
1305    /// [japanese]: https://support.apple.com/guide/japanese-input-method/use-the-candidate-window-jpim10262/6.3/mac/12.0
1306    #[deprecated = "use Window::request_ime_update instead"]
1307    fn set_ime_cursor_area(&self, position: Position, size: Size) {
1308        if self.ime_capabilities().map(|caps| caps.cursor_area()).unwrap_or(false) {
1309            let _ = self.request_ime_update(ImeRequest::Update(
1310                ImeRequestData::default().with_cursor_area(position, size),
1311            ));
1312        }
1313    }
1314
1315    /// Sets whether the window should get IME events
1316    ///
1317    /// When IME is allowed, the window will receive [`Ime`] events, and during the
1318    /// preedit phase the window will NOT get [`KeyboardInput`] events. The window
1319    /// should allow IME when it is expecting text input.
1320    ///
1321    /// When IME is not allowed, the window won't receive [`Ime`] events, and will
1322    /// receive [`KeyboardInput`] events for every keypress instead. Not allowing
1323    /// IME is useful for games for example.
1324    ///
1325    /// IME is **not** allowed by default.
1326    ///
1327    /// ## Platform-specific
1328    ///
1329    /// - **macOS:** IME must be enabled to receive text-input where dead-key sequences are
1330    ///   combined.
1331    /// - **iOS / Android:** This will show / hide the soft keyboard.
1332    /// - **Web / Orbital:** Unsupported.
1333    /// - **X11**: Enabling IME will disable dead keys reporting during compose.
1334    ///
1335    /// [`Ime`]: crate::event::WindowEvent::Ime
1336    /// [`KeyboardInput`]: crate::event::WindowEvent::KeyboardInput
1337    #[deprecated = "use Window::request_ime_update instead"]
1338    fn set_ime_allowed(&self, allowed: bool) {
1339        let action = if allowed {
1340            let position = LogicalPosition::new(0, 0);
1341            let size = LogicalSize::new(0, 0);
1342            let ime_caps = ImeCapabilities::new().with_hint_and_purpose().with_cursor_area();
1343            let request_data = ImeRequestData {
1344                hint_and_purpose: Some((ImeHint::NONE, ImePurpose::Normal)),
1345                // WARNING: there's nothing sensible to use here by default.
1346                cursor_area: Some((position.into(), size.into())),
1347                ..ImeRequestData::default()
1348            };
1349
1350            // Enable all capabilities to reflect the old behavior.
1351            ImeRequest::Enable(ImeEnableRequest::new(ime_caps, request_data).unwrap())
1352        } else {
1353            ImeRequest::Disable
1354        };
1355
1356        let _ = self.request_ime_update(action);
1357    }
1358
1359    /// Sets the IME purpose for the window using [`ImePurpose`].
1360    ///
1361    /// ## Platform-specific
1362    ///
1363    /// - **iOS / Android / Web / Windows / X11 / macOS / Orbital:** Unsupported.
1364    #[deprecated = "use Window::request_ime_update instead"]
1365    fn set_ime_purpose(&self, purpose: ImePurpose) {
1366        if self.ime_capabilities().map(|caps| caps.hint_and_purpose()).unwrap_or(false) {
1367            let _ = self.request_ime_update(ImeRequest::Update(ImeRequestData {
1368                hint_and_purpose: Some((ImeHint::NONE, purpose)),
1369                ..ImeRequestData::default()
1370            }));
1371        }
1372    }
1373
1374    /// Atomically apply request to IME.
1375    ///
1376    /// For details consult [`ImeRequest`] and [`ImeCapabilities`].
1377    ///
1378    /// Input methods allows the user to compose text without using a keyboard. Requesting one may
1379    /// be beneficial for touch screen environments or ones where, for example, East Asian scripts
1380    /// may be entered.
1381    ///
1382    /// If the focus within the application changes from one logical text input area to another, the
1383    /// application should inform the IME of the switch by disabling the IME and enabling it again
1384    /// in the other area.
1385    ///
1386    /// IME is **not** enabled by default.
1387    ///
1388    /// ## Example
1389    ///
1390    /// ```no_run
1391    /// # use dpi::{Position, Size};
1392    /// # use winit_core::window::{Window, ImeHint, ImePurpose, ImeRequest, ImeCapabilities, ImeRequestData, ImeEnableRequest};
1393    /// # fn scope(window: &dyn Window, cursor_pos: Position, cursor_size: Size) {
1394    /// // Clear previous state by switching off IME
1395    /// window.request_ime_update(ImeRequest::Disable).expect("Disable cannot fail");
1396    ///
1397    /// let ime_caps = ImeCapabilities::new().with_cursor_area().with_hint_and_purpose();
1398    /// let request_data = ImeRequestData::default()
1399    ///                          .with_hint_and_purpose(ImeHint::NONE, ImePurpose::Normal)
1400    ///                          .with_cursor_area(cursor_pos, cursor_size);
1401    /// let enable_ime = ImeEnableRequest::new(ime_caps, request_data.clone()).unwrap();
1402    /// window.request_ime_update(ImeRequest::Enable(enable_ime)).expect("Enabling may fail if IME is not supported");
1403    ///
1404    /// // Update the current state
1405    /// window
1406    ///     .request_ime_update(ImeRequest::Update(request_data.clone()))
1407    ///     .expect("will fail if it's not enabled or ime is not supported");
1408    ///
1409    /// // Update the current state
1410    /// window
1411    ///     .request_ime_update(ImeRequest::Update(
1412    ///        request_data.with_cursor_area(cursor_pos, cursor_size),
1413    ///     ))
1414    ///     .expect("Can fail - we didn't submit a cursor position initially");
1415    ///
1416    /// // Switch off IME
1417    /// window.request_ime_update(ImeRequest::Disable).expect("Disable cannot fail");
1418    /// # }
1419    /// ```
1420    fn request_ime_update(&self, request: ImeRequest) -> Result<(), ImeRequestError>;
1421
1422    /// Return enabled by the client [`ImeCapabilities`] for this window.
1423    ///
1424    /// When the IME is not yet enabled it'll return `None`.
1425    ///
1426    /// By default IME is disabled, thus will return `None`.
1427    fn ime_capabilities(&self) -> Option<ImeCapabilities>;
1428
1429    /// Brings the window to the front and sets input focus. Has no effect if the window is
1430    /// already in focus, minimized, or not visible.
1431    ///
1432    /// This method steals input focus from other applications. Do not use this method unless
1433    /// you are certain that's what the user wants. Focus stealing can cause an extremely disruptive
1434    /// user experience.
1435    ///
1436    /// ## Platform-specific
1437    ///
1438    /// - **iOS / Android / Wayland / Orbital:** Unsupported.
1439    fn focus_window(&self);
1440
1441    /// Gets whether the window has keyboard focus.
1442    ///
1443    /// This queries the same state information as [`WindowEvent::Focused`].
1444    ///
1445    /// [`WindowEvent::Focused`]: crate::event::WindowEvent::Focused
1446    fn has_focus(&self) -> bool;
1447
1448    /// Requests user attention to the window, this has no effect if the application
1449    /// is already focused. How requesting for user attention manifests is platform dependent,
1450    /// see [`UserAttentionType`] for details.
1451    ///
1452    /// Providing `None` will unset the request for user attention. Unsetting the request for
1453    /// user attention might not be done automatically by the WM when the window receives input.
1454    ///
1455    /// ## Platform-specific
1456    ///
1457    /// - **iOS / Android / Web / Orbital:** Unsupported.
1458    /// - **macOS:** `None` has no effect.
1459    /// - **X11:** Requests for user attention must be manually cleared.
1460    /// - **Wayland:** Requires `xdg_activation_v1` protocol, `None` has no effect.
1461    fn request_user_attention(&self, request_type: Option<UserAttentionType>);
1462
1463    /// Set or override the window theme.
1464    ///
1465    /// Specify `None` to reset the theme to the system default.
1466    ///
1467    /// ## Platform-specific
1468    ///
1469    /// - **Wayland:** Sets the theme for the client side decorations. Using `None` will use dbus to
1470    ///   get the system preference.
1471    /// - **X11:** Sets `_GTK_THEME_VARIANT` hint to `dark` or `light` and if `None` is used, it
1472    ///   will default to  [`Theme::Dark`].
1473    /// - **iOS / Android / Web / Orbital:** Unsupported.
1474    fn set_theme(&self, theme: Option<Theme>);
1475
1476    /// Returns the current window theme.
1477    ///
1478    /// Returns `None` if it cannot be determined on the current platform.
1479    ///
1480    /// ## Platform-specific
1481    ///
1482    /// - **iOS / Android / x11 / Orbital:** Unsupported.
1483    /// - **Wayland:** Only returns theme overrides.
1484    fn theme(&self) -> Option<Theme>;
1485
1486    /// Prevents the window contents from being captured by other apps.
1487    ///
1488    /// ## Platform-specific
1489    ///
1490    /// - **macOS**: if `false`, [`NSWindowSharingNone`] is used but doesn't completely prevent all
1491    ///   apps from reading the window content, for instance, QuickTime.
1492    /// - **iOS / Android / x11 / Wayland / Web / Orbital:** Unsupported.
1493    ///
1494    /// [`NSWindowSharingNone`]: https://developer.apple.com/documentation/appkit/nswindowsharingtype/nswindowsharingnone
1495    fn set_content_protected(&self, protected: bool);
1496
1497    /// Gets the current title of the window.
1498    ///
1499    /// ## Platform-specific
1500    ///
1501    /// - **iOS / Android / x11 / Wayland / Web:** Unsupported. Always returns an empty string.
1502    fn title(&self) -> String;
1503
1504    /// Modifies the cursor icon of the window.
1505    ///
1506    /// ## Platform-specific
1507    ///
1508    /// - **iOS / Android / Orbital:** Unsupported.
1509    /// - **Web:** Custom cursors have to be loaded and decoded first, until then the previous
1510    ///   cursor is shown.
1511    fn set_cursor(&self, cursor: Cursor);
1512
1513    /// Changes the position of the cursor in window coordinates.
1514    ///
1515    /// ```no_run
1516    /// # use dpi::{LogicalPosition, PhysicalPosition};
1517    /// # use winit_core::window::Window;
1518    /// # fn scope(window: &dyn Window) {
1519    /// // Specify the position in logical dimensions like this:
1520    /// window.set_cursor_position(LogicalPosition::new(400.0, 200.0).into());
1521    ///
1522    /// // Or specify the position in physical dimensions like this:
1523    /// window.set_cursor_position(PhysicalPosition::new(400, 200).into());
1524    /// # }
1525    /// ```
1526    ///
1527    /// ## Platform-specific
1528    ///
1529    /// - **Wayland**: Cursor must be in [`CursorGrabMode::Locked`].
1530    /// - **iOS / Android / Web / Orbital:** Always returns an [`RequestError::NotSupported`].
1531    fn set_cursor_position(&self, position: Position) -> Result<(), RequestError>;
1532
1533    /// Set grabbing [mode][CursorGrabMode] on the cursor preventing it from leaving the window.
1534    ///
1535    /// ## Example
1536    ///
1537    /// First try confining the cursor, and if that fails, try locking it instead.
1538    ///
1539    /// ```no_run
1540    /// # use winit_core::window::{CursorGrabMode, Window};
1541    /// # fn scope(window: &dyn Window) {
1542    /// window
1543    ///     .set_cursor_grab(CursorGrabMode::Confined)
1544    ///     .or_else(|_e| window.set_cursor_grab(CursorGrabMode::Locked))
1545    ///     .unwrap();
1546    /// # }
1547    /// ```
1548    fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), RequestError>;
1549
1550    /// Modifies the cursor's visibility.
1551    ///
1552    /// If `false`, this will hide the cursor. If `true`, this will show the cursor.
1553    ///
1554    /// ## Platform-specific
1555    ///
1556    /// - **Windows:** The cursor is only hidden within the confines of the window.
1557    /// - **X11:** The cursor is only hidden within the confines of the window.
1558    /// - **Wayland:** The cursor is only hidden within the confines of the window.
1559    /// - **macOS:** The cursor is hidden as long as the window has input focus, even if the cursor
1560    ///   is outside of the window.
1561    /// - **iOS / Android:** Unsupported.
1562    fn set_cursor_visible(&self, visible: bool);
1563
1564    /// Moves the window with the left mouse button until the button is released.
1565    ///
1566    /// There's no guarantee that this will work unless the left mouse button was pressed
1567    /// immediately before this function is called.
1568    ///
1569    /// ## Platform-specific
1570    ///
1571    /// - **X11:** Un-grabs the cursor.
1572    /// - **Wayland:** Requires the cursor to be inside the window to be dragged.
1573    /// - **macOS:** May prevent the button release event to be triggered.
1574    /// - **iOS / Android / Web:** Always returns an [`RequestError::NotSupported`].
1575    fn drag_window(&self) -> Result<(), RequestError>;
1576
1577    /// Resizes the window with the left mouse button until the button is released.
1578    ///
1579    /// There's no guarantee that this will work unless the left mouse button was pressed
1580    /// immediately before this function is called.
1581    ///
1582    /// ## Platform-specific
1583    ///
1584    /// - **macOS:** Always returns an [`RequestError::NotSupported`]
1585    /// - **iOS / Android / Web:** Always returns an [`RequestError::NotSupported`].
1586    fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), RequestError>;
1587
1588    /// Show [window menu] at a specified position in surface coordinates.
1589    ///
1590    /// This is the context menu that is normally shown when interacting with
1591    /// the title bar. This is useful when implementing custom decorations.
1592    ///
1593    /// ## Platform-specific
1594    /// **Android / iOS / macOS / Orbital / Wayland / Web / X11:** Unsupported.
1595    ///
1596    /// [window menu]: https://en.wikipedia.org/wiki/Common_menus_in_Microsoft_Windows#System_menu
1597    fn show_window_menu(&self, position: Position);
1598
1599    /// Modifies whether the window catches cursor events.
1600    ///
1601    /// If `true`, the window will catch the cursor events. If `false`, events are passed through
1602    /// the window such that any other window behind it receives them. By default hittest is
1603    /// enabled.
1604    ///
1605    /// ## Platform-specific
1606    ///
1607    /// - **iOS / Android / Web / Orbital:** Always returns an [`RequestError::NotSupported`].
1608    fn set_cursor_hittest(&self, hittest: bool) -> Result<(), RequestError>;
1609
1610    /// Returns the monitor on which the window currently resides.
1611    ///
1612    /// Returns `None` if current monitor can't be detected.
1613    fn current_monitor(&self) -> Option<MonitorHandle>;
1614
1615    /// Returns the list of all the monitors available on the system.
1616    ///
1617    /// This is the same as [`ActiveEventLoop::available_monitors`], and is provided for
1618    /// convenience.
1619    ///
1620    /// [`ActiveEventLoop::available_monitors`]: crate::event_loop::ActiveEventLoop::available_monitors
1621    fn available_monitors(&self) -> Box<dyn Iterator<Item = MonitorHandle>>;
1622
1623    /// Returns the primary monitor of the system.
1624    ///
1625    /// Returns `None` if it can't identify any monitor as a primary one.
1626    ///
1627    /// This is the same as [`ActiveEventLoop::primary_monitor`], and is provided for convenience.
1628    ///
1629    /// ## Platform-specific
1630    ///
1631    /// - **Wayland:** Always returns `None`.
1632    ///
1633    /// [`ActiveEventLoop::primary_monitor`]: crate::event_loop::ActiveEventLoop::primary_monitor
1634    fn primary_monitor(&self) -> Option<MonitorHandle>;
1635
1636    /// Get the raw-window-handle v0.6 display handle.
1637    fn rwh_06_display_handle(&self) -> &dyn rwh_06::HasDisplayHandle;
1638
1639    /// Get the raw-window-handle v0.6 window handle.
1640    fn rwh_06_window_handle(&self) -> &dyn rwh_06::HasWindowHandle;
1641}
1642
1643impl_dyn_casting!(Window);
1644
1645impl PartialEq for dyn Window + '_ {
1646    fn eq(&self, other: &dyn Window) -> bool {
1647        self.id().eq(&other.id())
1648    }
1649}
1650
1651impl Eq for dyn Window + '_ {}
1652
1653impl std::hash::Hash for dyn Window + '_ {
1654    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1655        self.id().hash(state);
1656    }
1657}
1658
1659impl rwh_06::HasDisplayHandle for dyn Window + '_ {
1660    fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
1661        self.rwh_06_display_handle().display_handle()
1662    }
1663}
1664
1665impl rwh_06::HasWindowHandle for dyn Window + '_ {
1666    fn window_handle(&self) -> Result<rwh_06::WindowHandle<'_>, rwh_06::HandleError> {
1667        self.rwh_06_window_handle().window_handle()
1668    }
1669}
1670
1671/// The behavior of cursor grabbing.
1672///
1673/// Use this enum with [`Window::set_cursor_grab`] to grab the cursor.
1674#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1675#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1676#[allow(clippy::exhaustive_enums)]
1677pub enum CursorGrabMode {
1678    /// No grabbing of the cursor is performed.
1679    None,
1680
1681    /// The cursor is confined to the window area.
1682    ///
1683    /// There's no guarantee that the cursor will be hidden. You should hide it by yourself if you
1684    /// want to do so.
1685    ///
1686    /// ## Platform-specific
1687    ///
1688    /// - **macOS:** Not implemented. Always returns [`RequestError::NotSupported`] for now.
1689    /// - **iOS / Android / Web:** Always returns an [`RequestError::NotSupported`].
1690    Confined,
1691
1692    /// The cursor is locked inside the window area to the certain position.
1693    ///
1694    /// There's no guarantee that the cursor will be hidden. You should hide it by yourself if you
1695    /// want to do so.
1696    ///
1697    /// ## Platform-specific
1698    ///
1699    /// - **X11:** Not implemented. Always returns [`RequestError::NotSupported`] for now.
1700    /// - **iOS / Android:** Always returns an [`RequestError::NotSupported`].
1701    Locked,
1702}
1703
1704/// Defines the orientation that a window resize will be performed.
1705#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1706#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1707#[allow(clippy::exhaustive_enums)]
1708pub enum ResizeDirection {
1709    East,
1710    North,
1711    NorthEast,
1712    NorthWest,
1713    South,
1714    SouthEast,
1715    SouthWest,
1716    West,
1717}
1718
1719impl From<ResizeDirection> for CursorIcon {
1720    fn from(direction: ResizeDirection) -> Self {
1721        use ResizeDirection::*;
1722        match direction {
1723            East => CursorIcon::EResize,
1724            North => CursorIcon::NResize,
1725            NorthEast => CursorIcon::NeResize,
1726            NorthWest => CursorIcon::NwResize,
1727            South => CursorIcon::SResize,
1728            SouthEast => CursorIcon::SeResize,
1729            SouthWest => CursorIcon::SwResize,
1730            West => CursorIcon::WResize,
1731        }
1732    }
1733}
1734
1735/// The theme variant to use.
1736#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1737#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1738#[allow(clippy::exhaustive_enums)]
1739pub enum Theme {
1740    /// Use the light variant.
1741    Light,
1742
1743    /// Use the dark variant.
1744    Dark,
1745}
1746
1747/// ## Platform-specific
1748///
1749/// - **X11:** Sets the WM's `XUrgencyHint`. No distinction between [`Critical`] and
1750///   [`Informational`].
1751///
1752/// [`Critical`]: Self::Critical
1753/// [`Informational`]: Self::Informational
1754#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
1755#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1756#[allow(clippy::exhaustive_enums)]
1757pub enum UserAttentionType {
1758    /// ## Platform-specific
1759    ///
1760    /// - **macOS:** Bounces the dock icon until the application is in focus.
1761    /// - **Windows:** Flashes both the window and the taskbar button until the application is in
1762    ///   focus.
1763    Critical,
1764
1765    /// ## Platform-specific
1766    ///
1767    /// - **macOS:** Bounces the dock icon once.
1768    /// - **Windows:** Flashes the taskbar button until the application is in focus.
1769    #[default]
1770    Informational,
1771}
1772
1773bitflags::bitflags! {
1774    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1775    pub struct WindowButtons: u32 {
1776        const CLOSE  = 1 << 0;
1777        const MINIMIZE  = 1 << 1;
1778        const MAXIMIZE  = 1 << 2;
1779    }
1780}
1781
1782/// A window level groups windows with respect to their z-position.
1783///
1784/// The relative ordering between windows in different window levels is fixed.
1785/// The z-order of a window within the same window level may change dynamically on user interaction.
1786///
1787/// ## Platform-specific
1788///
1789/// - **iOS / Android / Web / Wayland:** Unsupported.
1790#[derive(Debug, Default, PartialEq, Eq, Clone, Copy, Hash)]
1791#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1792#[allow(clippy::exhaustive_enums)]
1793pub enum WindowLevel {
1794    /// The window will always be below normal windows.
1795    ///
1796    /// This is useful for a widget-based app.
1797    AlwaysOnBottom,
1798
1799    /// The default.
1800    #[default]
1801    Normal,
1802
1803    /// The window will always be on top of normal windows.
1804    AlwaysOnTop,
1805}
1806
1807/// Generic IME purposes for use in [`Window::set_ime_purpose`].
1808///
1809/// The purpose should reflect the kind of data to be entered.
1810/// The purpose may improve UX by optimizing the IME for the specific use case,
1811/// for example showing relevant characters and hiding unneeded ones,
1812/// or changing the icon of the confirmation button,
1813/// if winit can express the purpose to the platform and the platform reacts accordingly.
1814///
1815/// ## Platform-specific
1816///
1817/// - **iOS / Android / Web / Windows / X11 / macOS / Orbital:** Unsupported.
1818#[non_exhaustive]
1819#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Default)]
1820#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1821pub enum ImePurpose {
1822    /// No special purpose for the IME (default).
1823    #[default]
1824    Normal,
1825    /// The IME is used for password input.
1826    /// The IME will treat the contents as sensitive.
1827    Password,
1828    /// The IME is used to input into a terminal.
1829    ///
1830    /// For example, that could alter OSK on Wayland to show extra buttons.
1831    Terminal,
1832    /// Number (including decimal separator and sign)
1833    Number,
1834    /// Phone number
1835    Phone,
1836    /// URL
1837    Url,
1838    /// Email address
1839    Email,
1840    /// Password composed only of digits (treated as sensitive data)
1841    Pin,
1842    /// Date
1843    Date,
1844    /// Time
1845    Time,
1846    /// Date and time
1847    DateTime,
1848}
1849
1850bitflags! {
1851    /// IME hints
1852    ///
1853    /// The hint should reflect the desired behaviour of the IME
1854    /// while entering text.
1855    /// The purpose may improve UX by optimizing the IME for the specific use case,
1856    /// beyond just the general data type specified in `ImePurpose`.
1857    ///
1858    /// ## Platform-specific
1859    ///
1860    /// - **iOS / Android / Web / Windows / X11 / macOS / Orbital:** Unsupported.
1861    #[non_exhaustive]
1862    #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1863    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
1864    pub struct ImeHint: u32 {
1865        /// No special behaviour.
1866        const NONE = 0;
1867        /// Suggest word completions.
1868        const COMPLETION = 0x1;
1869        /// Suggest word corrections.
1870        const SPELLCHECK = 0x2;
1871        /// Switch to uppercase letters at the start of a sentence.
1872        const AUTO_CAPITALIZATION = 0x4;
1873        /// Prefer lowercase letters.
1874        const LOWERCASE = 0x8;
1875        /// Prefer uppercase letters.
1876        const UPPERCASE = 0x10;
1877        /// Prefer casing for titles and headings (can be language dependent).
1878        const TITLECASE = 0x20;
1879        /// Characters should be hidden.
1880        ///
1881        /// This may prevent e.g. layout switching with some IMEs, unless hint is disabled.
1882        const HIDDEN_TEXT = 0x40;
1883        /// Typed text should not be stored.
1884        const SENSITIVE_DATA = 0x80;
1885        /// Just Latin characters should be entered.
1886        const LATIN = 0x100;
1887        /// The text input is multiline.
1888        const MULTILINE = 0x200;
1889    }
1890}
1891
1892#[derive(Debug, PartialEq, Eq, Clone, Hash)]
1893#[non_exhaustive]
1894pub enum ImeSurroundingTextError {
1895    /// Text exceeds 4000 bytes
1896    TextTooLong,
1897    /// Cursor not on a code point boundary, or past the end of text.
1898    CursorBadPosition,
1899    /// Anchor not on a code point boundary, or past the end of text.
1900    AnchorBadPosition,
1901}
1902
1903impl fmt::Display for ImeSurroundingTextError {
1904    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1905        match self {
1906            ImeSurroundingTextError::TextTooLong => write!(f, "text exceeds maximum length"),
1907            ImeSurroundingTextError::CursorBadPosition => {
1908                write!(f, "cursor is not at a valid text index")
1909            },
1910            ImeSurroundingTextError::AnchorBadPosition => {
1911                write!(f, "anchor is not at a valid text index")
1912            },
1913        }
1914    }
1915}
1916
1917impl std::error::Error for ImeSurroundingTextError {}
1918
1919/// Defines the text surrounding the caret
1920#[derive(Debug, PartialEq, Eq, Clone, Hash)]
1921#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1922pub struct ImeSurroundingText {
1923    /// An excerpt of the text present in the text input field, excluding preedit.
1924    text: String,
1925    /// The position of the caret, in bytes from the beginning of the string
1926    cursor: usize,
1927    /// The position of the other end of selection, in bytes.
1928    /// With no selection, it should be the same as the cursor.
1929    anchor: usize,
1930}
1931
1932impl ImeSurroundingText {
1933    /// The maximum size of the text excerpt.
1934    pub const MAX_TEXT_BYTES: usize = 4000;
1935    /// Defines the text surrounding the cursor and the selection within it.
1936    ///
1937    /// `text`: An excerpt of the text present in the text input field, excluding preedit.
1938    /// It must be limited to 4000 bytes due to backend constraints.
1939    /// `cursor`: The position of the caret, in bytes from the beginning of the string.
1940    /// `anchor: The position of the other end of selection, in bytes.
1941    /// With no selection, it should be the same as the cursor.
1942    ///
1943    /// This may fail if the byte indices don't fall on code point boundaries,
1944    /// or if the text is too long.
1945    ///
1946    /// ## Examples:
1947    ///
1948    /// A text field containing `foo|bar` where `|` denotes the caret would correspond to a value
1949    /// obtained by:
1950    ///
1951    /// ```
1952    /// # use winit_core::window::ImeSurroundingText;
1953    /// let s = ImeSurroundingText::new("foobar".into(), 3, 3).unwrap();
1954    /// ```
1955    ///
1956    /// Because preedit is excluded from the text string, a text field containing `foo[baz|]bar`
1957    /// where `|` denotes the caret and [baz|] is the preedit would be created in exactly the same
1958    /// way.
1959    pub fn new(
1960        text: String,
1961        cursor: usize,
1962        anchor: usize,
1963    ) -> Result<Self, ImeSurroundingTextError> {
1964        let text = if text.len() < 4000 {
1965            text
1966        } else {
1967            return Err(ImeSurroundingTextError::TextTooLong);
1968        };
1969
1970        let cursor = if text.is_char_boundary(cursor) && cursor <= text.len() {
1971            cursor
1972        } else {
1973            return Err(ImeSurroundingTextError::CursorBadPosition);
1974        };
1975
1976        let anchor = if text.is_char_boundary(anchor) && anchor <= text.len() {
1977            anchor
1978        } else {
1979            return Err(ImeSurroundingTextError::AnchorBadPosition);
1980        };
1981
1982        Ok(Self { text, cursor, anchor })
1983    }
1984
1985    /// Consumes the object, releasing the text string only.
1986    /// Use this call in the backend to avoid an extra clone when submitting the surrounding text.
1987    pub fn into_text(self) -> String {
1988        self.text
1989    }
1990
1991    pub fn text(&self) -> &str {
1992        &self.text
1993    }
1994
1995    pub fn cursor(&self) -> usize {
1996        self.cursor
1997    }
1998
1999    pub fn anchor(&self) -> usize {
2000        self.anchor
2001    }
2002}
2003
2004/// Request to send to IME.
2005#[derive(Debug, PartialEq, Clone)]
2006#[non_exhaustive]
2007pub enum ImeRequest {
2008    /// Enable the IME with the [`ImeCapabilities`] and [`ImeRequestData`] as initial state. When
2009    /// the [`ImeRequestData`] is **not** matching capabilities fully, the default values will be
2010    /// used instead.
2011    ///
2012    /// **Requesting to update data matching not enabled capabilities will result in update
2013    /// being ignored.** The winit backend in such cases is recommended to log a warning. This
2014    /// applies to both [`ImeRequest::Enable`] and [`ImeRequest::Update`]. For details on
2015    /// capabilities refer to [`ImeCapabilities`].
2016    ///
2017    /// To update the [`ImeCapabilities`], the IME must be disabled and then re-enabled.
2018    Enable(ImeEnableRequest),
2019    /// Update the state of already enabled IME. Issuing this request before [`ImeRequest::Enable`]
2020    /// will result in error.
2021    Update(ImeRequestData),
2022    /// Disable the IME.
2023    ///
2024    /// **The disable request can not fail**.
2025    Disable,
2026}
2027
2028/// Initial IME request.
2029#[derive(Debug, Clone, PartialEq)]
2030pub struct ImeEnableRequest {
2031    capabilities: ImeCapabilities,
2032    request_data: ImeRequestData,
2033}
2034
2035impl ImeEnableRequest {
2036    /// Create request for the [`ImeRequest::Enable`]
2037    ///
2038    /// This will return [`None`] if some capability was requested but its initial value was not
2039    /// set by the user or value was set by the user, but capability not requested.
2040    pub fn new(capabilities: ImeCapabilities, request_data: ImeRequestData) -> Option<Self> {
2041        if capabilities.cursor_area() ^ request_data.cursor_area.is_some() {
2042            return None;
2043        }
2044
2045        if capabilities.hint_and_purpose() ^ request_data.hint_and_purpose.is_some() {
2046            return None;
2047        }
2048
2049        if capabilities.surrounding_text() ^ request_data.surrounding_text.is_some() {
2050            return None;
2051        }
2052        Some(Self { capabilities, request_data })
2053    }
2054
2055    /// [`ImeCapabilities`] to enable.
2056    pub const fn capabilities(&self) -> &ImeCapabilities {
2057        &self.capabilities
2058    }
2059
2060    /// Request data attached to request.
2061    pub const fn request_data(&self) -> &ImeRequestData {
2062        &self.request_data
2063    }
2064
2065    /// Destruct [`ImeEnableRequest`]  into its raw parts.
2066    pub fn into_raw(self) -> (ImeCapabilities, ImeRequestData) {
2067        (self.capabilities, self.request_data)
2068    }
2069}
2070
2071/// IME capabilities supported by client.
2072///
2073/// For example, if the client doesn't support [`ImeCapabilities::cursor_area()`], then not enabling
2074/// it will make IME hide the popup window instead of placing it arbitrary over the
2075/// client's window surface.
2076///
2077/// When the capability is not enabled or not supported by the IME, trying to update its'
2078/// corresponding data with [`ImeRequest`] will be ignored.
2079///
2080/// New capabilities may be added to this struct in the future.
2081#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
2082pub struct ImeCapabilities(ImeCapabilitiesFlags);
2083
2084impl ImeCapabilities {
2085    /// Returns a new empty set of capabilities.
2086    pub fn new() -> Self {
2087        Self::default()
2088    }
2089
2090    /// Marks `hint and purpose` as supported.
2091    ///
2092    /// For more details see [`ImeRequestData::with_hint_and_purpose`].
2093    pub const fn with_hint_and_purpose(self) -> Self {
2094        Self(self.0.union(ImeCapabilitiesFlags::HINT_AND_PURPOSE))
2095    }
2096
2097    /// Marks `hint and purpose` as unsupported.
2098    ///
2099    /// For more details see [`ImeRequestData::with_hint_and_purpose`].
2100    pub const fn without_hint_and_purpose(self) -> Self {
2101        Self(self.0.difference(ImeCapabilitiesFlags::HINT_AND_PURPOSE))
2102    }
2103
2104    /// Returns `true` if `hint and purpose` is supported.
2105    pub const fn hint_and_purpose(&self) -> bool {
2106        self.0.contains(ImeCapabilitiesFlags::HINT_AND_PURPOSE)
2107    }
2108
2109    /// Marks `cursor_area` as supported.
2110    ///
2111    /// For more details see [`ImeRequestData::with_cursor_area`].
2112    pub const fn with_cursor_area(self) -> Self {
2113        Self(self.0.union(ImeCapabilitiesFlags::CURSOR_AREA))
2114    }
2115
2116    /// Marks `cursor_area` as unsupported.
2117    ///
2118    /// For more details see [`ImeRequestData::with_cursor_area`].
2119    pub const fn without_cursor_area(self) -> Self {
2120        Self(self.0.difference(ImeCapabilitiesFlags::CURSOR_AREA))
2121    }
2122
2123    /// Returns `true` if `cursor_area` is supported.
2124    pub const fn cursor_area(&self) -> bool {
2125        self.0.contains(ImeCapabilitiesFlags::CURSOR_AREA)
2126    }
2127
2128    /// Marks `surrounding_text` as supported.
2129    ///
2130    /// For more details see [`ImeRequestData::with_surrounding_text`].
2131    pub const fn with_surrounding_text(self) -> Self {
2132        Self(self.0.union(ImeCapabilitiesFlags::SURROUNDING_TEXT))
2133    }
2134
2135    /// Marks `surrounding_text` as unsupported.
2136    ///
2137    /// For more details see [`ImeRequestData::with_surrounding_text`].
2138    pub const fn without_surrounding_text(self) -> Self {
2139        Self(self.0.difference(ImeCapabilitiesFlags::SURROUNDING_TEXT))
2140    }
2141
2142    /// Returns `true` if `surrounding_text` is supported.
2143    pub const fn surrounding_text(&self) -> bool {
2144        self.0.contains(ImeCapabilitiesFlags::SURROUNDING_TEXT)
2145    }
2146}
2147
2148bitflags! {
2149    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
2150    pub(crate) struct ImeCapabilitiesFlags : u8 {
2151        /// Client supports setting IME hint and purpose.
2152        const HINT_AND_PURPOSE = 1 << 0;
2153        /// Client supports reporting cursor area for IME popup to
2154        /// appear.
2155        const CURSOR_AREA = 1 << 1;
2156        /// Client supports reporting the text around the caret
2157        const SURROUNDING_TEXT = 1 << 2;
2158    }
2159}
2160
2161/// The [`ImeRequest`] data to communicate to system's IME.
2162///
2163/// This applies multiple IME state properties at once.
2164/// Fields set to `None` are not updated and the previously sent
2165/// value is reused.
2166#[non_exhaustive]
2167#[derive(Debug, PartialEq, Clone, Default)]
2168#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2169pub struct ImeRequestData {
2170    /// Text input hint and purpose.
2171    ///
2172    /// To support updating it, enable [`ImeCapabilities::hint_and_purpose()`].
2173    pub hint_and_purpose: Option<(ImeHint, ImePurpose)>,
2174    /// The IME cursor area which should not be covered by the input method popup.
2175    ///
2176    /// To support updating it, enable [`ImeCapabilities::cursor_area()`].
2177    pub cursor_area: Option<(Position, Size)>,
2178    /// The text surrounding the caret
2179    ///
2180    /// To support updating it, enable [`ImeCapabilities::surrounding_text()`].
2181    pub surrounding_text: Option<ImeSurroundingText>,
2182}
2183
2184impl ImeRequestData {
2185    /// Sets the hint and purpose of the current text input content.
2186    pub fn with_hint_and_purpose(self, hint: ImeHint, purpose: ImePurpose) -> Self {
2187        Self { hint_and_purpose: Some((hint, purpose)), ..self }
2188    }
2189
2190    /// Sets the IME cursor editing area.
2191    ///
2192    /// The `position` is the top left corner of that area
2193    /// in surface coordinates and `size` is the size of this area starting from the position. An
2194    /// example of such area could be a input field in the UI or line in the editor.
2195    ///
2196    /// The windowing system could place a candidate box close to that area, but try to not obscure
2197    /// the specified area, so the user input to it stays visible.
2198    ///
2199    /// The candidate box is the window / popup / overlay that allows you to select the desired
2200    /// characters. The look of this box may differ between input devices, even on the same
2201    /// platform.
2202    ///
2203    /// (Apple's official term is "candidate window", see their [chinese] and [japanese] guides).
2204    ///
2205    /// ## Example
2206    ///
2207    /// ```no_run
2208    /// # use dpi::{LogicalPosition, PhysicalPosition, LogicalSize, PhysicalSize};
2209    /// # use winit_core::window::ImeRequestData;
2210    /// # fn scope(ime_request_data: ImeRequestData) {
2211    /// // Specify the position in logical dimensions like this:
2212    /// let ime_request_data = ime_request_data.with_cursor_area(
2213    ///     LogicalPosition::new(400.0, 200.0).into(),
2214    ///     LogicalSize::new(100, 100).into(),
2215    /// );
2216    ///
2217    /// // Or specify the position in physical dimensions like this:
2218    /// let ime_request_data = ime_request_data.with_cursor_area(
2219    ///     PhysicalPosition::new(400, 200).into(),
2220    ///     PhysicalSize::new(100, 100).into(),
2221    /// );
2222    /// # }
2223    /// ```
2224    ///
2225    /// ## Platform-specific
2226    ///
2227    /// - **iOS / Android / Web / Orbital:** Unsupported.
2228    ///
2229    /// [chinese]: https://support.apple.com/guide/chinese-input-method/use-the-candidate-window-cim12992/104/mac/12.0
2230    /// [japanese]: https://support.apple.com/guide/japanese-input-method/use-the-candidate-window-jpim10262/6.3/mac/12.0
2231    pub fn with_cursor_area(self, position: Position, size: Size) -> Self {
2232        Self { cursor_area: Some((position, size)), ..self }
2233    }
2234
2235    /// Describes the text surrounding the caret.
2236    ///
2237    /// The IME can then continue providing suggestions for the continuation of the existing text,
2238    /// as well as can erase text more accurately, for example glyphs composed of multiple code
2239    /// points.
2240    pub fn with_surrounding_text(self, surrounding_text: ImeSurroundingText) -> Self {
2241        Self { surrounding_text: Some(surrounding_text), ..self }
2242    }
2243}
2244
2245/// Error from sending request to IME with
2246/// [`Window::request_ime_update`].
2247#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2248#[non_exhaustive]
2249pub enum ImeRequestError {
2250    /// IME is not yet enabled.
2251    NotEnabled,
2252    /// IME is already enabled.
2253    AlreadyEnabled,
2254    /// Not supported.
2255    NotSupported,
2256}
2257
2258impl fmt::Display for ImeRequestError {
2259    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2260        match self {
2261            ImeRequestError::NotEnabled => write!(f, "ime is not enabled."),
2262            ImeRequestError::AlreadyEnabled => write!(f, "ime is already enabled."),
2263            ImeRequestError::NotSupported => write!(f, "ime is not supported."),
2264        }
2265    }
2266}
2267
2268impl std::error::Error for ImeRequestError {}
2269
2270/// An opaque token used to activate the [`Window`].
2271///
2272/// [`Window`]: crate::window::Window
2273#[derive(Debug, PartialEq, Eq, Clone, Hash)]
2274pub struct ActivationToken {
2275    pub(crate) token: String,
2276}
2277
2278impl ActivationToken {
2279    /// Make an [`ActivationToken`] from a string.
2280    ///
2281    /// This method should be used to wrap tokens passed by side channels to your application, like
2282    /// dbus.
2283    ///
2284    /// The validity of the token is ensured by the windowing system. Using the invalid token will
2285    /// only result in the side effect of the operation involving it being ignored (e.g. window
2286    /// won't get focused automatically), but won't yield any errors.
2287    ///
2288    /// To obtain a valid token consult the backend implementation.
2289    pub fn from_raw(token: String) -> Self {
2290        Self { token }
2291    }
2292
2293    /// Convert the token to its string representation to later pass via IPC.
2294    pub fn into_raw(self) -> String {
2295        self.token
2296    }
2297
2298    /// Get a reference to a raw token.
2299    pub fn as_raw(&self) -> &str {
2300        &self.token
2301    }
2302}
2303
2304#[cfg(test)]
2305mod tests {
2306
2307    use dpi::{LogicalPosition, LogicalSize, Position, Size};
2308
2309    use super::{
2310        ImeCapabilities, ImeEnableRequest, ImeRequestData, ImeSurroundingText,
2311        ImeSurroundingTextError,
2312    };
2313    use crate::window::{ImeHint, ImePurpose};
2314
2315    #[test]
2316    fn ime_initial_request_caps_match() {
2317        let position: Position = LogicalPosition::new(0, 0).into();
2318        let size: Size = LogicalSize::new(0, 0).into();
2319
2320        assert!(
2321            ImeEnableRequest::new(
2322                ImeCapabilities::new().with_cursor_area(),
2323                ImeRequestData::default()
2324            )
2325            .is_none()
2326        );
2327        assert!(
2328            ImeEnableRequest::new(
2329                ImeCapabilities::new().with_hint_and_purpose(),
2330                ImeRequestData::default()
2331            )
2332            .is_none()
2333        );
2334
2335        assert!(
2336            ImeEnableRequest::new(
2337                ImeCapabilities::new().with_cursor_area(),
2338                ImeRequestData::default().with_hint_and_purpose(ImeHint::NONE, ImePurpose::Normal)
2339            )
2340            .is_none()
2341        );
2342
2343        assert!(
2344            ImeEnableRequest::new(
2345                ImeCapabilities::new(),
2346                ImeRequestData::default()
2347                    .with_hint_and_purpose(ImeHint::NONE, ImePurpose::Normal)
2348                    .with_cursor_area(position, size)
2349            )
2350            .is_none()
2351        );
2352
2353        assert!(
2354            ImeEnableRequest::new(
2355                ImeCapabilities::new().with_cursor_area(),
2356                ImeRequestData::default()
2357                    .with_hint_and_purpose(ImeHint::NONE, ImePurpose::Normal)
2358                    .with_cursor_area(position, size)
2359            )
2360            .is_none()
2361        );
2362
2363        assert!(
2364            ImeEnableRequest::new(
2365                ImeCapabilities::new().with_cursor_area(),
2366                ImeRequestData::default().with_cursor_area(position, size)
2367            )
2368            .is_some()
2369        );
2370
2371        assert!(
2372            ImeEnableRequest::new(
2373                ImeCapabilities::new().with_hint_and_purpose().with_cursor_area(),
2374                ImeRequestData::default()
2375                    .with_hint_and_purpose(ImeHint::NONE, ImePurpose::Normal)
2376                    .with_cursor_area(position, size)
2377            )
2378            .is_some()
2379        );
2380
2381        let text: &[u8] = ['a' as u8; 8000].as_slice();
2382        let text = std::str::from_utf8(text).unwrap();
2383        assert_eq!(
2384            ImeSurroundingText::new(text.into(), 0, 0),
2385            Err(ImeSurroundingTextError::TextTooLong),
2386        );
2387
2388        assert_eq!(
2389            ImeSurroundingText::new("short".into(), 110, 0),
2390            Err(ImeSurroundingTextError::CursorBadPosition),
2391        );
2392
2393        assert_eq!(
2394            ImeSurroundingText::new("граница".into(), 1, 0),
2395            Err(ImeSurroundingTextError::CursorBadPosition),
2396        );
2397    }
2398}