winit_win32/lib.rs
1//! # Winit Win32 / Windows backend
2//!
3//! The supported OS version is Windows 7 or higher, though Windows 10 is
4//! tested regularly.
5#![cfg(target_os = "windows")] // FIXME(madsmtm): Allow compiling on all platforms.
6
7#[macro_use]
8mod util;
9mod dark_mode;
10mod definitions;
11mod dpi;
12mod drop_handler;
13mod event_loop;
14mod icon;
15mod ime;
16mod keyboard;
17mod keyboard_layout;
18mod monitor;
19mod raw_input;
20mod window;
21mod window_state;
22
23use std::borrow::Borrow;
24use std::ffi::c_void;
25use std::ops::Deref;
26use std::path::Path;
27use std::sync::Arc;
28
29use ::dpi::PhysicalSize;
30#[cfg(feature = "serde")]
31use serde::{Deserialize, Serialize};
32use windows_sys::Win32::Foundation::HANDLE;
33use winit_core::event::DeviceId;
34use winit_core::icon::{BadIcon, Icon};
35use winit_core::window::{PlatformWindowAttributes, Window as CoreWindow};
36
37pub use self::event_loop::{EventLoop, PlatformSpecificEventLoopAttributes};
38use self::icon::{RaiiIcon, SelectedCursor};
39pub use self::keyboard::{physicalkey_to_scancode, scancode_to_physicalkey};
40pub use self::monitor::{MonitorHandle, VideoModeHandle};
41pub use self::window::Window;
42
43/// Window Handle type used by Win32 API
44pub type HWND = *mut c_void;
45/// Menu Handle type used by Win32 API
46pub type HMENU = *mut c_void;
47/// Monitor Handle type used by Win32 API
48pub type HMONITOR = *mut c_void;
49
50/// Describes a system-drawn backdrop material of a window.
51///
52/// For a detailed explanation, see [`DWM_SYSTEMBACKDROP_TYPE docs`].
53///
54/// [`DWM_SYSTEMBACKDROP_TYPE docs`]: https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/ne-dwmapi-dwm_systembackdrop_type
55#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
56#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
57pub enum BackdropType {
58 /// Corresponds to `DWMSBT_AUTO`.
59 ///
60 /// Usually draws a default backdrop effect on the title bar.
61 #[default]
62 Auto = 0,
63
64 /// Corresponds to `DWMSBT_NONE`.
65 None = 1,
66
67 /// Corresponds to `DWMSBT_MAINWINDOW`.
68 ///
69 /// Draws the Mica backdrop material.
70 MainWindow = 2,
71
72 /// Corresponds to `DWMSBT_TRANSIENTWINDOW`.
73 ///
74 /// Draws the Background Acrylic backdrop material.
75 TransientWindow = 3,
76
77 /// Corresponds to `DWMSBT_TABBEDWINDOW`.
78 ///
79 /// Draws the Alt Mica backdrop material.
80 TabbedWindow = 4,
81}
82
83/// Describes a color used by Windows
84#[repr(transparent)]
85#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
86#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
87pub struct Color(u32);
88
89impl Color {
90 // Special constant only valid for the window border and therefore modeled using Option<Color>
91 // for user facing code
92 const NONE: Color = Color(0xfffffffe);
93 /// Use the system's default color
94 pub const SYSTEM_DEFAULT: Color = Color(0xffffffff);
95
96 /// Create a new color from the given RGB values
97 pub const fn from_rgb(r: u8, g: u8, b: u8) -> Self {
98 Self((r as u32) | ((g as u32) << 8) | ((b as u32) << 16))
99 }
100}
101
102impl Default for Color {
103 fn default() -> Self {
104 Self::SYSTEM_DEFAULT
105 }
106}
107
108/// Describes how the corners of a window should look like.
109///
110/// For a detailed explanation, see [`DWM_WINDOW_CORNER_PREFERENCE docs`].
111///
112/// [`DWM_WINDOW_CORNER_PREFERENCE docs`]: https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/ne-dwmapi-dwm_window_corner_preference
113#[repr(i32)]
114#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
115#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
116pub enum CornerPreference {
117 /// Corresponds to `DWMWCP_DEFAULT`.
118 ///
119 /// Let the system decide when to round window corners.
120 #[default]
121 Default = 0,
122
123 /// Corresponds to `DWMWCP_DONOTROUND`.
124 ///
125 /// Never round window corners.
126 DoNotRound = 1,
127
128 /// Corresponds to `DWMWCP_ROUND`.
129 ///
130 /// Round the corners, if appropriate.
131 Round = 2,
132
133 /// Corresponds to `DWMWCP_ROUNDSMALL`.
134 ///
135 /// Round the corners if appropriate, with a small radius.
136 RoundSmall = 3,
137}
138
139/// A wrapper around a [`Window`] that ignores thread-specific window handle limitations.
140///
141/// See [`WindowBorrowExtWindows::any_thread`] for more information.
142#[derive(Clone, Debug)]
143pub struct AnyThread<W: CoreWindow>(W);
144
145impl<W: CoreWindow> AnyThread<W> {
146 /// Get a reference to the inner window.
147 #[inline]
148 pub fn get_ref(&self) -> &dyn CoreWindow {
149 &self.0
150 }
151}
152
153impl<W: CoreWindow> Deref for AnyThread<W> {
154 type Target = W;
155 fn deref(&self) -> &Self::Target {
156 &self.0
157 }
158}
159
160impl<W: CoreWindow> rwh_06::HasWindowHandle for AnyThread<W> {
161 fn window_handle(&self) -> Result<rwh_06::WindowHandle<'_>, rwh_06::HandleError> {
162 // SAFETY: The top level user has asserted this is only used safely.
163 unsafe { self.get_ref().window_handle_any_thread() }
164 }
165}
166
167/// Additional methods on `EventLoop` that are specific to Windows.
168pub trait EventLoopBuilderExtWindows {
169 /// Whether to allow the event loop to be created off of the main thread.
170 ///
171 /// By default, the window is only allowed to be created on the main
172 /// thread, to make platform compatibility easier.
173 ///
174 /// # `Window` caveats
175 ///
176 /// Note that any `Window` created on the new thread will be destroyed when the thread
177 /// terminates. Attempting to use a `Window` after its parent thread terminates has
178 /// unspecified, although explicitly not undefined, behavior.
179 fn with_any_thread(&mut self, any_thread: bool) -> &mut Self;
180
181 /// Whether to enable process-wide DPI awareness.
182 ///
183 /// By default, `winit` will attempt to enable process-wide DPI awareness. If
184 /// that's undesirable, you can disable it with this function.
185 ///
186 /// # Example
187 ///
188 /// Disable process-wide DPI awareness.
189 ///
190 /// ```
191 /// use winit::event_loop::EventLoop;
192 /// #[cfg(target_os = "windows")]
193 /// use winit::platform::windows::EventLoopBuilderExtWindows;
194 ///
195 /// let mut builder = EventLoop::builder();
196 /// #[cfg(target_os = "windows")]
197 /// builder.with_dpi_aware(false);
198 /// # if false { // We can't test this part
199 /// let event_loop = builder.build();
200 /// # }
201 /// ```
202 fn with_dpi_aware(&mut self, dpi_aware: bool) -> &mut Self;
203
204 /// A callback to be executed before dispatching a win32 message to the window procedure.
205 /// Return true to disable winit's internal message dispatching.
206 ///
207 /// # Example
208 ///
209 /// ```
210 /// # use windows_sys::Win32::UI::WindowsAndMessaging::{ACCEL, CreateAcceleratorTableW, TranslateAcceleratorW, DispatchMessageW, TranslateMessage, MSG};
211 /// use winit::event_loop::EventLoop;
212 /// #[cfg(target_os = "windows")]
213 /// use winit::platform::windows::EventLoopBuilderExtWindows;
214 ///
215 /// let mut builder = EventLoop::builder();
216 /// #[cfg(target_os = "windows")]
217 /// builder.with_msg_hook(|msg|{
218 /// let msg = msg as *const MSG;
219 /// # let accels: Vec<ACCEL> = Vec::new();
220 /// let translated = unsafe {
221 /// TranslateAcceleratorW(
222 /// (*msg).hwnd,
223 /// CreateAcceleratorTableW(accels.as_ptr() as _, 1),
224 /// msg,
225 /// ) == 1
226 /// };
227 /// translated
228 /// });
229 /// ```
230 fn with_msg_hook<F>(&mut self, callback: F) -> &mut Self
231 where
232 F: FnMut(*const c_void) -> bool + 'static;
233}
234
235/// Additional methods on `Window` that are specific to Windows.
236pub trait WindowExtWindows {
237 /// Enables or disables mouse and keyboard input to the specified window.
238 ///
239 /// A window must be enabled before it can be activated.
240 /// If an application has create a modal dialog box by disabling its owner window
241 /// (as described in [`WindowAttributesWindows::with_owner_window`]), the application must
242 /// enable the owner window before destroying the dialog box.
243 /// Otherwise, another window will receive the keyboard focus and be activated.
244 ///
245 /// If a child window is disabled, it is ignored when the system tries to determine which
246 /// window should receive mouse messages.
247 ///
248 /// For more information, see <https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-enablewindow#remarks>
249 /// and <https://docs.microsoft.com/en-us/windows/win32/winmsg/window-features#disabled-windows>
250 fn set_enable(&self, enabled: bool);
251
252 /// This sets `ICON_BIG`. A good ceiling here is 256x256.
253 fn set_taskbar_icon(&self, taskbar_icon: Option<Icon>);
254
255 /// Whether to show or hide the window icon in the taskbar.
256 fn set_skip_taskbar(&self, skip: bool);
257
258 /// Shows or hides the background drop shadow for undecorated windows.
259 ///
260 /// Enabling the shadow causes a thin 1px line to appear on the top of the window.
261 fn set_undecorated_shadow(&self, shadow: bool);
262
263 /// Sets system-drawn backdrop type.
264 ///
265 /// Requires Windows 11 build 22523+.
266 fn set_system_backdrop(&self, backdrop_type: BackdropType);
267
268 /// Sets the color of the window border.
269 ///
270 /// Supported starting with Windows 11 Build 22000.
271 fn set_border_color(&self, color: Option<Color>);
272
273 /// Sets the background color of the title bar.
274 ///
275 /// Supported starting with Windows 11 Build 22000.
276 fn set_title_background_color(&self, color: Option<Color>);
277
278 /// Sets the color of the window title.
279 ///
280 /// Supported starting with Windows 11 Build 22000.
281 fn set_title_text_color(&self, color: Color);
282
283 /// Sets the preferred style of the window corners.
284 ///
285 /// Supported starting with Windows 11 Build 22000.
286 fn set_corner_preference(&self, preference: CornerPreference);
287
288 /// Sets if the reported [`winit_core::event::WindowEvent::MouseWheel`] event
289 /// should account for scroll speed system settings.
290 ///
291 /// The default scroll speed on Windows is 3 lines/characters per scroll,
292 /// this will be 1 if you set it to false.
293 ///
294 /// The default is `true`.
295 fn set_use_system_scroll_speed(&self, should_use: bool);
296
297 /// Get the raw window handle for this [`Window`] without checking for thread affinity.
298 ///
299 /// Window handles in Win32 have a property called "thread affinity" that ties them to their
300 /// origin thread. Some operations can only happen on the window's origin thread, while others
301 /// can be called from any thread. For example, [`SetWindowSubclass`] is not thread safe while
302 /// [`GetDC`] is thread safe.
303 ///
304 /// In Rust terms, the window handle is `Send` sometimes but `!Send` other times.
305 ///
306 /// Therefore, in order to avoid confusing threading errors, [`Window`] only returns the
307 /// window handle when the [`window_handle`] function is called from the thread that created
308 /// the window. In other cases, it returns an [`Unavailable`] error.
309 ///
310 /// However in some cases you may already know that you are using the window handle for
311 /// operations that are guaranteed to be thread-safe. In which case this function aims
312 /// to provide an escape hatch so these functions are still accessible from other threads.
313 ///
314 /// # Safety
315 ///
316 /// It is the responsibility of the user to only pass the window handle into thread-safe
317 /// Win32 APIs.
318 ///
319 /// [`SetWindowSubclass`]: https://learn.microsoft.com/en-us/windows/win32/api/commctrl/nf-commctrl-setwindowsubclass
320 /// [`GetDC`]: https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getdc
321 /// [`Window`]: crate::window::Window
322 /// [`window_handle`]: https://docs.rs/raw-window-handle/latest/raw_window_handle/trait.HasWindowHandle.html#tymethod.window_handle
323 /// [`Unavailable`]: https://docs.rs/raw-window-handle/latest/raw_window_handle/enum.HandleError.html#variant.Unavailable
324 ///
325 /// ## Example
326 ///
327 /// ```no_run
328 /// # use winit::window::Window;
329 /// # fn scope(window: Box<dyn Window>) {
330 /// use std::thread;
331 ///
332 /// use winit::platform::windows::WindowExtWindows;
333 /// use winit::raw_window_handle::HasWindowHandle;
334 ///
335 /// // We can get the window handle on the current thread.
336 /// let handle = window.window_handle().unwrap();
337 ///
338 /// // However, on another thread, we can't!
339 /// thread::spawn(move || {
340 /// assert!(window.window_handle().is_err());
341 ///
342 /// // We can use this function as an escape hatch.
343 /// let handle = unsafe { window.window_handle_any_thread().unwrap() };
344 /// });
345 /// # }
346 /// ```
347 unsafe fn window_handle_any_thread(
348 &self,
349 ) -> Result<rwh_06::WindowHandle<'_>, rwh_06::HandleError>;
350}
351
352impl WindowExtWindows for dyn CoreWindow + '_ {
353 #[inline]
354 fn set_enable(&self, enabled: bool) {
355 let window = self.cast_ref::<Window>().unwrap();
356 window.set_enable(enabled)
357 }
358
359 #[inline]
360 fn set_taskbar_icon(&self, taskbar_icon: Option<Icon>) {
361 let window = self.cast_ref::<Window>().unwrap();
362 window.set_taskbar_icon(taskbar_icon)
363 }
364
365 #[inline]
366 fn set_skip_taskbar(&self, skip: bool) {
367 let window = self.cast_ref::<Window>().unwrap();
368 window.set_skip_taskbar(skip)
369 }
370
371 #[inline]
372 fn set_undecorated_shadow(&self, shadow: bool) {
373 let window = self.cast_ref::<Window>().unwrap();
374 window.set_undecorated_shadow(shadow)
375 }
376
377 #[inline]
378 fn set_system_backdrop(&self, backdrop_type: BackdropType) {
379 let window = self.cast_ref::<Window>().unwrap();
380 window.set_system_backdrop(backdrop_type)
381 }
382
383 #[inline]
384 fn set_border_color(&self, color: Option<Color>) {
385 let window = self.cast_ref::<Window>().unwrap();
386 window.set_border_color(color.unwrap_or(Color::NONE))
387 }
388
389 #[inline]
390 fn set_title_background_color(&self, color: Option<Color>) {
391 // The windows docs don't mention NONE as a valid options but it works in practice and is
392 // useful to circumvent the Windows option "Show accent color on title bars and
393 // window borders"
394 let window = self.cast_ref::<Window>().unwrap();
395 window.set_title_background_color(color.unwrap_or(Color::NONE))
396 }
397
398 #[inline]
399 fn set_title_text_color(&self, color: Color) {
400 let window = self.cast_ref::<Window>().unwrap();
401 window.set_title_text_color(color)
402 }
403
404 #[inline]
405 fn set_corner_preference(&self, preference: CornerPreference) {
406 let window = self.cast_ref::<Window>().unwrap();
407 window.set_corner_preference(preference)
408 }
409
410 fn set_use_system_scroll_speed(&self, should_use: bool) {
411 let window = self.cast_ref::<Window>().unwrap();
412 window.set_use_system_scroll_speed(should_use)
413 }
414
415 unsafe fn window_handle_any_thread(
416 &self,
417 ) -> Result<rwh_06::WindowHandle<'_>, rwh_06::HandleError> {
418 let window = self.cast_ref::<Window>().unwrap();
419 unsafe {
420 let handle = window.rwh_06_no_thread_check()?;
421
422 // SAFETY: The handle is valid in this context.
423 Ok(rwh_06::WindowHandle::borrow_raw(handle))
424 }
425 }
426}
427
428/// Additional methods for anything that dereference to [`Window`].
429///
430/// [`Window`]: crate::window::Window
431pub trait WindowBorrowExtWindows: Borrow<dyn CoreWindow> + Sized {
432 /// Create an object that allows accessing the inner window handle in a thread-unsafe way.
433 ///
434 /// It is possible to call [`window_handle_any_thread`] to get around Windows's thread
435 /// affinity limitations. However, it may be desired to pass the [`Window`] into something
436 /// that requires the [`HasWindowHandle`] trait, while ignoring thread affinity limitations.
437 ///
438 /// This function wraps anything that implements `Borrow<Window>` into a structure that
439 /// uses the inner window handle as a mean of implementing [`HasWindowHandle`]. It wraps
440 /// `Window`, `&Window`, `Arc<Window>`, and other reference types.
441 ///
442 /// # Safety
443 ///
444 /// It is the responsibility of the user to only pass the window handle into thread-safe
445 /// Win32 APIs.
446 ///
447 /// [`Window`]: crate::window::Window
448 /// [`HasWindowHandle`]: rwh_06::HasWindowHandle
449 /// [`window_handle_any_thread`]: WindowExtWindows::window_handle_any_thread
450 unsafe fn any_thread(self) -> AnyThread<Self>
451 where
452 Self: CoreWindow,
453 {
454 AnyThread(self)
455 }
456}
457
458impl<W: Borrow<dyn CoreWindow> + Sized> WindowBorrowExtWindows for W {}
459
460#[derive(Clone, Debug)]
461pub struct WindowAttributesWindows {
462 pub(crate) owner: Option<HWND>,
463 pub(crate) menu: Option<HMENU>,
464 pub(crate) taskbar_icon: Option<Icon>,
465 pub(crate) no_redirection_bitmap: bool,
466 pub(crate) drag_and_drop: bool,
467 pub(crate) skip_taskbar: bool,
468 pub(crate) class_name: String,
469 pub(crate) decoration_shadow: bool,
470 pub(crate) backdrop_type: BackdropType,
471 pub(crate) clip_children: bool,
472 pub(crate) border_color: Option<Color>,
473 pub(crate) title_background_color: Option<Color>,
474 pub(crate) title_text_color: Option<Color>,
475 pub(crate) corner_preference: Option<CornerPreference>,
476 pub(crate) use_system_wheel_speed: bool,
477}
478
479impl Default for WindowAttributesWindows {
480 fn default() -> Self {
481 Self {
482 owner: None,
483 menu: None,
484 taskbar_icon: None,
485 no_redirection_bitmap: false,
486 drag_and_drop: true,
487 skip_taskbar: false,
488 class_name: "Window Class".to_string(),
489 decoration_shadow: false,
490 backdrop_type: BackdropType::default(),
491 clip_children: true,
492 border_color: None,
493 title_background_color: None,
494 title_text_color: None,
495 corner_preference: None,
496 use_system_wheel_speed: true,
497 }
498 }
499}
500
501unsafe impl Send for WindowAttributesWindows {}
502unsafe impl Sync for WindowAttributesWindows {}
503
504impl WindowAttributesWindows {
505 /// Set an owner to the window to be created. Can be used to create a dialog box, for example.
506 /// This only works when [`WindowAttributes::with_parent_window`] isn't called or set to `None`.
507 /// Can be used in combination with
508 /// [`WindowExtWindows::set_enable(false)`][WindowExtWindows::set_enable] on the owner
509 /// window to create a modal dialog box.
510 ///
511 /// From MSDN:
512 /// - An owned window is always above its owner in the z-order.
513 /// - The system automatically destroys an owned window when its owner is destroyed.
514 /// - An owned window is hidden when its owner is minimized.
515 ///
516 /// For more information, see <https://docs.microsoft.com/en-us/windows/win32/winmsg/window-features#owned-windows>
517 ///
518 /// [`WindowAttributes::with_parent_window`]: winit_core::window::WindowAttributes::with_parent_window
519 pub fn with_owner_window(mut self, parent: HWND) -> Self {
520 self.owner = Some(parent);
521 self
522 }
523
524 /// Sets a menu on the window to be created.
525 ///
526 /// Parent and menu are mutually exclusive; a child window cannot have a menu!
527 ///
528 /// The menu must have been manually created beforehand with [`CreateMenu`] or similar.
529 ///
530 /// Note: Dark mode cannot be supported for win32 menus, it's simply not possible to change how
531 /// the menus look. If you use this, it is recommended that you combine it with
532 /// `with_theme(Some(Theme::Light))` to avoid a jarring effect.
533 ///
534 /// [`CreateMenu`]: windows_sys::Win32::UI::WindowsAndMessaging::CreateMenu"
535 pub fn with_menu(mut self, menu: HMENU) -> Self {
536 self.menu = Some(menu);
537 self
538 }
539
540 /// This sets `ICON_BIG`. A good ceiling here is 256x256.
541 pub fn with_taskbar_icon(mut self, taskbar_icon: Option<Icon>) -> Self {
542 self.taskbar_icon = taskbar_icon;
543 self
544 }
545
546 /// This sets `WS_EX_NOREDIRECTIONBITMAP`.
547 pub fn with_no_redirection_bitmap(mut self, flag: bool) -> Self {
548 self.no_redirection_bitmap = flag;
549 self
550 }
551
552 /// Enables or disables drag and drop support (enabled by default). Will interfere with other
553 /// crates that use multi-threaded COM API (`CoInitializeEx` with `COINIT_MULTITHREADED`
554 /// instead of `COINIT_APARTMENTTHREADED`) on the same thread. Note that winit may still
555 /// attempt to initialize COM API regardless of this option. Currently only fullscreen mode
556 /// does that, but there may be more in the future. If you need COM API with
557 /// `COINIT_MULTITHREADED` you must initialize it before calling any winit functions. See <https://docs.microsoft.com/en-us/windows/win32/api/objbase/nf-objbase-coinitialize#remarks> for more information.
558 pub fn with_drag_and_drop(mut self, flag: bool) -> Self {
559 self.drag_and_drop = flag;
560 self
561 }
562
563 /// Whether show or hide the window icon in the taskbar.
564 pub fn with_skip_taskbar(mut self, skip: bool) -> Self {
565 self.skip_taskbar = skip;
566 self
567 }
568
569 /// Customize the window class name.
570 pub fn with_class_name<S: Into<String>>(mut self, class_name: S) -> Self {
571 self.class_name = class_name.into();
572 self
573 }
574
575 /// Shows or hides the background drop shadow for undecorated windows.
576 ///
577 /// The shadow is hidden by default.
578 /// Enabling the shadow causes a thin 1px line to appear on the top of the window.
579 pub fn with_undecorated_shadow(mut self, shadow: bool) -> Self {
580 self.decoration_shadow = shadow;
581 self
582 }
583
584 /// Sets system-drawn backdrop type.
585 ///
586 /// Requires Windows 11 build 22523+.
587 pub fn with_system_backdrop(mut self, backdrop_type: BackdropType) -> Self {
588 self.backdrop_type = backdrop_type;
589 self
590 }
591
592 /// This sets or removes `WS_CLIPCHILDREN` style.
593 pub fn with_clip_children(mut self, flag: bool) -> Self {
594 self.clip_children = flag;
595 self
596 }
597
598 /// Sets the color of the window border.
599 ///
600 /// Supported starting with Windows 11 Build 22000.
601 pub fn with_border_color(mut self, color: Option<Color>) -> Self {
602 self.border_color = Some(color.unwrap_or(Color::NONE));
603 self
604 }
605
606 /// Sets the background color of the title bar.
607 ///
608 /// Supported starting with Windows 11 Build 22000.
609 pub fn with_title_background_color(mut self, color: Option<Color>) -> Self {
610 self.title_background_color = Some(color.unwrap_or(Color::NONE));
611 self
612 }
613
614 /// Sets the color of the window title.
615 ///
616 /// Supported starting with Windows 11 Build 22000.
617 pub fn with_title_text_color(mut self, color: Color) -> Self {
618 self.title_text_color = Some(color);
619 self
620 }
621
622 /// Sets the preferred style of the window corners.
623 ///
624 /// Supported starting with Windows 11 Build 22000.
625 pub fn with_corner_preference(mut self, corners: CornerPreference) -> Self {
626 self.corner_preference = Some(corners);
627 self
628 }
629
630 /// Sets if the reported [`winit_core::event::WindowEvent::MouseWheel`] event
631 /// should account for scroll speed system settings.
632 ///
633 /// The default scroll speed on Windows is 3 lines/characters per scroll,
634 /// this will be 1 if you set it to false.
635 ///
636 /// The default is `true`.
637 pub fn with_use_system_scroll_speed(mut self, should_use: bool) -> Self {
638 self.use_system_wheel_speed = should_use;
639 self
640 }
641}
642
643impl PlatformWindowAttributes for WindowAttributesWindows {
644 fn box_clone(&self) -> Box<dyn PlatformWindowAttributes> {
645 Box::from(self.clone())
646 }
647}
648
649/// Additional methods on `DeviceId` that are specific to Windows.
650pub trait DeviceIdExtWindows {
651 /// Returns an identifier that persistently refers to this specific device.
652 ///
653 /// Will return `None` if the device is no longer available.
654 fn persistent_identifier(&self) -> Option<String>;
655}
656
657impl DeviceIdExtWindows for DeviceId {
658 fn persistent_identifier(&self) -> Option<String> {
659 let raw_id = self.into_raw();
660 if raw_id != 0 { raw_input::get_raw_input_device_name(raw_id as HANDLE) } else { None }
661 }
662}
663
664/// Windows specific `Icon`.
665///
666/// Windows icons can be created from files, or from the [`embedded resources`](https://learn.microsoft.com/en-us/windows/win32/menurc/about-resource-files).
667///
668/// The `ICON` resource definition statement use the following syntax:
669/// ```rc
670/// nameID ICON filename
671/// ```
672/// `nameID` is a unique name or a 16-bit unsigned integer value identifying the resource,
673/// `filename` is the name of the file that contains the resource.
674///
675/// More information about the `ICON` resource can be found at [`Microsoft Learn`](https://learn.microsoft.com/en-us/windows/win32/menurc/icon-resource) portal.
676#[derive(Clone, PartialEq, Eq, Hash)]
677pub struct WinIcon {
678 pub(crate) inner: Arc<RaiiIcon>,
679}
680
681impl WinIcon {
682 /// Create an icon from a file path.
683 ///
684 /// Specify `size` to load a specific icon size from the file, or `None` to load the default
685 /// icon size from the file.
686 ///
687 /// In cases where the specified size does not exist in the file, Windows may perform scaling
688 /// to get an icon of the desired size.
689 pub fn from_path<P: AsRef<Path>>(
690 path: P,
691 size: Option<PhysicalSize<u32>>,
692 ) -> Result<Self, BadIcon> {
693 Self::from_path_impl(path, size)
694 }
695
696 /// Create an icon from a resource embedded in this executable or library by its ordinal id.
697 ///
698 /// The valid `ordinal` values range from 1 to [`u16::MAX`] (inclusive). The value `0` is an
699 /// invalid ordinal id, but it can be used with [`from_resource_name`] as `"0"`.
700 ///
701 /// [`from_resource_name`]: Self::from_resource_name
702 ///
703 /// Specify `size` to load a specific icon size from the file, or `None` to load the default
704 /// icon size from the file.
705 ///
706 /// In cases where the specified size does not exist in the file, Windows may perform scaling
707 /// to get an icon of the desired size.
708 pub fn from_resource(
709 resource_id: u16,
710 size: Option<PhysicalSize<u32>>,
711 ) -> Result<Self, BadIcon> {
712 Self::from_resource_impl(resource_id, size)
713 }
714
715 /// Create an icon from a resource embedded in this executable or library by its name.
716 ///
717 /// Specify `size` to load a specific icon size from the file, or `None` to load the default
718 /// icon size from the file.
719 ///
720 /// In cases where the specified size does not exist in the file, Windows may perform scaling
721 /// to get an icon of the desired size.
722 ///
723 /// # Notes
724 ///
725 /// Consider the following resource definition statements:
726 /// ```rc
727 /// app ICON "app.ico"
728 /// 1 ICON "a.ico"
729 /// 0027 ICON "custom.ico"
730 /// 0 ICON "alt.ico"
731 /// ```
732 ///
733 /// Due to some internal implementation details of the resource embedding/loading process on
734 /// Windows platform, strings that can be interpreted as 16-bit unsigned integers (`"1"`,
735 /// `"002"`, etc.) cannot be used as valid resource names, and instead should be passed into
736 /// [`from_resource`]:
737 ///
738 /// [`from_resource`]: Self::from_resource
739 ///
740 /// ```rust,no_run
741 /// use winit::platform::windows::WinIcon;
742 ///
743 /// assert!(WinIcon::from_resource_name("app", None).is_ok());
744 /// assert!(WinIcon::from_resource(1, None).is_ok());
745 /// assert!(WinIcon::from_resource(27, None).is_ok());
746 /// assert!(WinIcon::from_resource_name("27", None).is_err());
747 /// assert!(WinIcon::from_resource_name("0027", None).is_err());
748 /// ```
749 ///
750 /// While `0` cannot be used as an ordinal id (see [`from_resource`]), it can be used as a
751 /// name:
752 ///
753 /// [`from_resource`]: IconExtWindows::from_resource
754 ///
755 /// ```rust,no_run
756 /// # use winit::platform::windows::WinIcon;
757 /// # use winit::icon::Icon;
758 /// assert!(WinIcon::from_resource_name("0", None).is_ok());
759 /// assert!(WinIcon::from_resource(0, None).is_err());
760 /// ```
761 pub fn from_resource_name(
762 resource_name: &str,
763 size: Option<PhysicalSize<u32>>,
764 ) -> Result<Self, BadIcon> {
765 Self::from_resource_name_impl(resource_name, size)
766 }
767}
768
769impl From<WinIcon> for Icon {
770 fn from(value: WinIcon) -> Self {
771 Self(Arc::new(value))
772 }
773}