async_winit/platform/
windows.rs

1/*
2
3`async-winit` is free software: you can redistribute it and/or modify it under the terms of one of
4the following licenses:
5
6* GNU Lesser General Public License as published by the Free Software Foundation, either
7  version 3 of the License, or (at your option) any later version.
8* Mozilla Public License as published by the Mozilla Foundation, version 2.
9
10`async-winit` is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
11the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General
12Public License and the Patron License for more details.
13
14You should have received a copy of the GNU Lesser General Public License and the Mozilla
15Public License along with `async-winit`. If not, see <https://www.gnu.org/licenses/>.
16
17*/
18
19// This file is partially derived from `winit`, which was originally created by Pierre Krieger and
20// contributers. It was originally released under the MIT license.
21
22//! Windows-specific functionality.
23
24#[doc(inline)]
25pub use winit::platform::windows::{
26    IconExtWindows, MonitorHandleExtWindows, HINSTANCE, HMENU, HMONITOR, HWND,
27};
28
29use super::__private as sealed;
30use crate::event_loop::EventLoopBuilder;
31use crate::window::{Icon, Window, WindowBuilder};
32use crate::ThreadSafety;
33
34use std::os::raw::c_void;
35
36use winit::platform::windows::{
37    EventLoopBuilderExtWindows as _, WindowBuilderExtWindows as _, WindowExtWindows as _,
38};
39
40/// Additional methods on `EventLoop` that are specific to Windows.
41pub trait EventLoopBuilderExtWindows: sealed::EventLoopBuilderPrivate {
42    /// Whether to allow the event loop to be created off of the main thread.
43    ///
44    /// By default, the window is only allowed to be created on the main
45    /// thread, to make platform compatibility easier.
46    ///
47    /// # `Window` caveats
48    ///
49    /// Note that any `Window` created on the new thread will be destroyed when the thread
50    /// terminates. Attempting to use a `Window` after its parent thread terminates has
51    /// unspecified, although explicitly not undefined, behavior.
52    fn with_any_thread(&mut self, any_thread: bool) -> &mut Self;
53
54    /// Whether to enable process-wide DPI awareness.
55    ///
56    /// By default, `winit` will attempt to enable process-wide DPI awareness. If
57    /// that's undesirable, you can disable it with this function.
58    ///
59    /// # Example
60    ///
61    /// Disable process-wide DPI awareness.
62    ///
63    /// ```
64    /// use winit::event_loop::EventLoopBuilder;
65    /// #[cfg(target_os = "windows")]
66    /// use winit::platform::windows::EventLoopBuilderExtWindows;
67    ///
68    /// let mut builder = EventLoopBuilder::new();
69    /// #[cfg(target_os = "windows")]
70    /// builder.with_dpi_aware(false);
71    /// # if false { // We can't test this part
72    /// let event_loop = builder.build();
73    /// # }
74    /// ```
75    fn with_dpi_aware(&mut self, dpi_aware: bool) -> &mut Self;
76
77    /// A callback to be executed before dispatching a win32 message to the window procedure.
78    /// Return true to disable winit's internal message dispatching.
79    fn with_msg_hook<F>(&mut self, callback: F) -> &mut Self
80    where
81        F: FnMut(*const c_void) -> bool + 'static;
82}
83
84impl EventLoopBuilderExtWindows for EventLoopBuilder {
85    fn with_any_thread(&mut self, any_thread: bool) -> &mut Self {
86        self.inner.with_any_thread(any_thread);
87        self
88    }
89
90    fn with_dpi_aware(&mut self, dpi_aware: bool) -> &mut Self {
91        self.inner.with_dpi_aware(dpi_aware);
92        self
93    }
94
95    fn with_msg_hook<F>(&mut self, callback: F) -> &mut Self
96    where
97        F: FnMut(*const c_void) -> bool + 'static,
98    {
99        self.inner.with_msg_hook(callback);
100        self
101    }
102}
103
104/// Additional methods on `Window` that are specific to Windows.
105pub trait WindowExtWindows: sealed::WindowPrivate {
106    /// Returns the HINSTANCE of the window
107    fn hinstance(&self) -> HINSTANCE;
108    /// Returns the native handle that is used by this window.
109    ///
110    /// The pointer will become invalid when the native window was destroyed.
111    fn hwnd(&self) -> HWND;
112
113    /// Enables or disables mouse and keyboard input to the specified window.
114    ///
115    /// A window must be enabled before it can be activated.
116    /// If an application has create a modal dialog box by disabling its owner window
117    /// (as described in [`WindowBuilderExtWindows::with_owner_window`]), the application must enable
118    /// the owner window before destroying the dialog box.
119    /// Otherwise, another window will receive the keyboard focus and be activated.
120    ///
121    /// If a child window is disabled, it is ignored when the system tries to determine which
122    /// window should receive mouse messages.
123    ///
124    /// For more information, see <https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-enablewindow#remarks>
125    /// and <https://docs.microsoft.com/en-us/windows/win32/winmsg/window-features#disabled-windows>
126    fn set_enable(&self, enabled: bool);
127
128    /// This sets `ICON_BIG`. A good ceiling here is 256x256.
129    fn set_taskbar_icon(&self, taskbar_icon: Option<Icon>);
130
131    /// Whether to show or hide the window icon in the taskbar.
132    fn set_skip_taskbar(&self, skip: bool);
133
134    /// Shows or hides the background drop shadow for undecorated windows.
135    ///
136    /// Enabling the shadow causes a thin 1px line to appear on the top of the window.
137    fn set_undecorated_shadow(&self, shadow: bool);
138}
139
140impl<TS: ThreadSafety> WindowExtWindows for Window<TS> {
141    fn hwnd(&self) -> HWND {
142        self.window().hwnd()
143    }
144
145    fn hinstance(&self) -> HINSTANCE {
146        self.window().hinstance()
147    }
148
149    fn set_enable(&self, enabled: bool) {
150        self.window().set_enable(enabled);
151    }
152
153    fn set_taskbar_icon(&self, taskbar_icon: Option<Icon>) {
154        self.window().set_taskbar_icon(taskbar_icon);
155    }
156
157    fn set_skip_taskbar(&self, skip: bool) {
158        self.window().set_skip_taskbar(skip);
159    }
160
161    fn set_undecorated_shadow(&self, shadow: bool) {
162        self.window().set_undecorated_shadow(shadow);
163    }
164}
165
166/// Additional methods on `WindowBuilder` that are specific to Windows.
167pub trait WindowBuilderExtWindows: sealed::WindowBuilderPrivate {
168    /// Set an owner to the window to be created. Can be used to create a dialog box, for example.
169    /// This only works when `WindowBuilder::with_parent_window` isn't called or set to `None`.
170    /// Can be used in combination with [`WindowExtWindows::set_enable(false)`](WindowExtWindows::set_enable)
171    /// on the owner window to create a modal dialog box.
172    ///
173    /// From MSDN:
174    /// - An owned window is always above its owner in the z-order.
175    /// - The system automatically destroys an owned window when its owner is destroyed.
176    /// - An owned window is hidden when its owner is minimized.
177    ///
178    /// For more information, see <https://docs.microsoft.com/en-us/windows/win32/winmsg/window-features#owned-windows>
179    fn with_owner_window(self, parent: HWND) -> WindowBuilder;
180
181    /// Sets a menu on the window to be created.
182    ///
183    /// Parent and menu are mutually exclusive; a child window cannot have a menu!
184    ///
185    /// The menu must have been manually created beforehand with `CreateMenu` or similar.
186    ///
187    /// Note: Dark mode cannot be supported for win32 menus, it's simply not possible to change how the menus look.
188    /// If you use this, it is recommended that you combine it with `with_theme(Some(Theme::Light))` to avoid a jarring effect.
189    fn with_menu(self, menu: HMENU) -> WindowBuilder;
190
191    /// This sets `ICON_BIG`. A good ceiling here is 256x256.
192    fn with_taskbar_icon(self, taskbar_icon: Option<Icon>) -> WindowBuilder;
193
194    /// This sets `WS_EX_NOREDIRECTIONBITMAP`.
195    fn with_no_redirection_bitmap(self, flag: bool) -> WindowBuilder;
196
197    /// Enables or disables drag and drop support (enabled by default). Will interfere with other crates
198    /// that use multi-threaded COM API (`CoInitializeEx` with `COINIT_MULTITHREADED` instead of
199    /// `COINIT_APARTMENTTHREADED`) on the same thread. Note that winit may still attempt to initialize
200    /// COM API regardless of this option. Currently only fullscreen mode does that, but there may be more in the future.
201    /// If you need COM API with `COINIT_MULTITHREADED` you must initialize it before calling any winit functions.
202    /// See <https://docs.microsoft.com/en-us/windows/win32/api/objbase/nf-objbase-coinitialize#remarks> for more information.
203    fn with_drag_and_drop(self, flag: bool) -> WindowBuilder;
204
205    /// Whether show or hide the window icon in the taskbar.
206    fn with_skip_taskbar(self, skip: bool) -> WindowBuilder;
207
208    /// Shows or hides the background drop shadow for undecorated windows.
209    ///
210    /// The shadow is hidden by default.
211    /// Enabling the shadow causes a thin 1px line to appear on the top of the window.
212    fn with_undecorated_shadow(self, shadow: bool) -> WindowBuilder;
213}
214
215#[derive(Default)]
216pub(crate) struct PlatformSpecific {
217    owner_window: Option<HWND>,
218    menu: Option<HMENU>,
219    taskbar_icon: Option<Icon>,
220    no_redirection_bitmap: Option<bool>,
221    drag_and_drop: Option<bool>,
222    skip_taskbar: Option<bool>,
223    undecorated_shadow: Option<bool>,
224}
225
226impl PlatformSpecific {
227    pub(crate) fn apply_to(
228        self,
229        mut wb: winit::window::WindowBuilder,
230    ) -> winit::window::WindowBuilder {
231        if let Some(owner_window) = self.owner_window {
232            wb = wb.with_owner_window(owner_window);
233        }
234
235        if let Some(menu) = self.menu {
236            wb = wb.with_menu(menu);
237        }
238
239        if let Some(taskbar_icon) = self.taskbar_icon {
240            wb = wb.with_taskbar_icon(Some(taskbar_icon));
241        }
242
243        if let Some(no_redirection_bitmap) = self.no_redirection_bitmap {
244            wb = wb.with_no_redirection_bitmap(no_redirection_bitmap);
245        }
246
247        if let Some(drag_and_drop) = self.drag_and_drop {
248            wb = wb.with_drag_and_drop(drag_and_drop);
249        }
250
251        if let Some(skip_taskbar) = self.skip_taskbar {
252            wb = wb.with_skip_taskbar(skip_taskbar);
253        }
254
255        if let Some(undecorated_shadow) = self.undecorated_shadow {
256            wb = wb.with_undecorated_shadow(undecorated_shadow);
257        }
258
259        wb
260    }
261}