winit_core/
window.rs

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