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}