Skip to main content

winit/platform_impl/windows/
window.rs

1#![cfg(windows_platform)]
2
3use std::cell::Cell;
4use std::ffi::c_void;
5use std::mem::{self, MaybeUninit};
6use std::sync::mpsc::channel;
7use std::sync::{Arc, Mutex, MutexGuard};
8use std::{io, panic, ptr};
9
10use windows_sys::Win32::Foundation::{
11    HWND, LPARAM, OLE_E_WRONGCOMPOBJ, POINT, POINTS, RECT, RPC_E_CHANGED_MODE, S_OK, WPARAM,
12};
13use windows_sys::Win32::Graphics::Dwm::{
14    DwmEnableBlurBehindWindow, DwmSetWindowAttribute, DWMWA_BORDER_COLOR, DWMWA_CAPTION_COLOR,
15    DWMWA_SYSTEMBACKDROP_TYPE, DWMWA_TEXT_COLOR, DWMWA_WINDOW_CORNER_PREFERENCE, DWM_BB_BLURREGION,
16    DWM_BB_ENABLE, DWM_BLURBEHIND, DWM_SYSTEMBACKDROP_TYPE, DWM_WINDOW_CORNER_PREFERENCE,
17};
18use windows_sys::Win32::Graphics::Gdi::{
19    ChangeDisplaySettingsExW, ClientToScreen, CreateRectRgn, DeleteObject, InvalidateRgn,
20    RedrawWindow, CDS_FULLSCREEN, DISP_CHANGE_BADFLAGS, DISP_CHANGE_BADMODE, DISP_CHANGE_BADPARAM,
21    DISP_CHANGE_FAILED, DISP_CHANGE_SUCCESSFUL, RDW_INTERNALPAINT,
22};
23use windows_sys::Win32::System::Com::{
24    CoCreateInstance, CoInitializeEx, CoUninitialize, CLSCTX_ALL, COINIT_APARTMENTTHREADED,
25};
26use windows_sys::Win32::System::Ole::{OleInitialize, RegisterDragDrop};
27use windows_sys::Win32::UI::Input::KeyboardAndMouse::{
28    EnableWindow, GetActiveWindow, MapVirtualKeyW, ReleaseCapture, SendInput, ToUnicode, INPUT,
29    INPUT_0, INPUT_KEYBOARD, KEYBDINPUT, KEYEVENTF_EXTENDEDKEY, KEYEVENTF_KEYUP, MAPVK_VK_TO_VSC,
30    VIRTUAL_KEY, VK_LMENU, VK_MENU, VK_SPACE,
31};
32use windows_sys::Win32::UI::Input::Touch::{RegisterTouchWindow, TWF_WANTPALM};
33use windows_sys::Win32::UI::WindowsAndMessaging::{
34    CreateWindowExW, EnableMenuItem, FlashWindowEx, GetClientRect, GetCursorPos,
35    GetForegroundWindow, GetSystemMenu, GetSystemMetrics, GetWindowPlacement, GetWindowTextLengthW,
36    GetWindowTextW, IsWindowVisible, LoadCursorW, PeekMessageW, PostMessageW, RegisterClassExW,
37    SetCursor, SetCursorPos, SetForegroundWindow, SetMenuDefaultItem, SetWindowDisplayAffinity,
38    SetWindowPlacement, SetWindowPos, SetWindowTextW, TrackPopupMenu, CS_HREDRAW, CS_VREDRAW,
39    CW_USEDEFAULT, FLASHWINFO, FLASHW_ALL, FLASHW_STOP, FLASHW_TIMERNOFG, FLASHW_TRAY,
40    GWLP_HINSTANCE, HTBOTTOM, HTBOTTOMLEFT, HTBOTTOMRIGHT, HTCAPTION, HTLEFT, HTRIGHT, HTTOP,
41    HTTOPLEFT, HTTOPRIGHT, MENU_ITEM_STATE, MFS_DISABLED, MFS_ENABLED, MF_BYCOMMAND, NID_READY,
42    PM_NOREMOVE, SC_CLOSE, SC_MAXIMIZE, SC_MINIMIZE, SC_MOVE, SC_RESTORE, SC_SIZE, SM_DIGITIZER,
43    SWP_ASYNCWINDOWPOS, SWP_NOACTIVATE, SWP_NOSIZE, SWP_NOZORDER, TPM_LEFTALIGN, TPM_RETURNCMD,
44    WDA_EXCLUDEFROMCAPTURE, WDA_NONE, WM_NCLBUTTONDOWN, WM_SYSCOMMAND, WNDCLASSEXW,
45};
46
47use tracing::warn;
48
49use crate::cursor::Cursor;
50use crate::dpi::{PhysicalPosition, PhysicalSize, Position, Size};
51use crate::error::{ExternalError, NotSupportedError, OsError as RootOsError};
52use crate::icon::Icon;
53use crate::platform::windows::{BackdropType, Color, CornerPreference};
54use crate::platform_impl::platform::dark_mode::try_theme;
55use crate::platform_impl::platform::definitions::{
56    CLSID_TaskbarList, IID_ITaskbarList, IID_ITaskbarList2, ITaskbarList, ITaskbarList2,
57};
58use crate::platform_impl::platform::dpi::{
59    dpi_to_scale_factor, enable_non_client_dpi_scaling, hwnd_dpi,
60};
61use crate::platform_impl::platform::drop_handler::FileDropHandler;
62use crate::platform_impl::platform::event_loop::{self, ActiveEventLoop, DESTROY_MSG_ID};
63use crate::platform_impl::platform::icon::{self, IconType, WinCursor};
64use crate::platform_impl::platform::ime::ImeContext;
65use crate::platform_impl::platform::keyboard::KeyEventBuilder;
66use crate::platform_impl::platform::monitor::{self, MonitorHandle};
67use crate::platform_impl::platform::window_state::{
68    CursorFlags, SavedWindow, WindowFlags, WindowState,
69};
70use crate::platform_impl::platform::{util, Fullscreen, SelectedCursor, WindowId};
71use crate::window::{
72    CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType, WindowAttributes,
73    WindowButtons, WindowLevel,
74};
75
76/// The Win32 implementation of the main `Window` object.
77pub(crate) struct Window {
78    /// Main handle for the window.
79    window: HWND,
80
81    /// The current window state.
82    window_state: Arc<Mutex<WindowState>>,
83
84    // The events loop proxy.
85    thread_executor: event_loop::EventLoopThreadExecutor,
86}
87
88impl Window {
89    pub(crate) fn new(
90        event_loop: &ActiveEventLoop,
91        w_attr: WindowAttributes,
92    ) -> Result<Window, RootOsError> {
93        // We dispatch an `init` function because of code style.
94        // First person to remove the need for cloning here gets a cookie!
95        //
96        // done. you owe me -- ossi
97        unsafe { init(w_attr, event_loop) }
98    }
99
100    pub(crate) fn maybe_queue_on_main(&self, f: impl FnOnce(&Self) + Send + 'static) {
101        // TODO: Use `thread_executor` here
102        f(self)
103    }
104
105    pub(crate) fn maybe_wait_on_main<R: Send>(&self, f: impl FnOnce(&Self) -> R + Send) -> R {
106        // TODO: Use `thread_executor` here
107        f(self)
108    }
109
110    fn window_state_lock(&self) -> MutexGuard<'_, WindowState> {
111        self.window_state.lock().unwrap()
112    }
113
114    pub fn set_title(&self, text: &str) {
115        let wide_text = util::encode_wide(text);
116        unsafe {
117            SetWindowTextW(self.hwnd(), wide_text.as_ptr());
118        }
119    }
120
121    pub fn set_transparent(&self, transparent: bool) {
122        let window = self.window;
123        let window_state = Arc::clone(&self.window_state);
124        self.thread_executor.execute_in_thread(move || {
125            let _ = &window;
126            WindowState::set_window_flags(window_state.lock().unwrap(), window, |f| {
127                f.set(WindowFlags::TRANSPARENT, transparent)
128            });
129        });
130    }
131
132    pub fn set_blur(&self, _blur: bool) {}
133
134    #[inline]
135    pub fn set_visible(&self, visible: bool) {
136        let window = self.window;
137        let window_state = Arc::clone(&self.window_state);
138        self.thread_executor.execute_in_thread(move || {
139            let _ = &window;
140            WindowState::set_window_flags(window_state.lock().unwrap(), window, |f| {
141                f.set(WindowFlags::VISIBLE, visible)
142            });
143        });
144    }
145
146    #[inline]
147    pub fn is_visible(&self) -> Option<bool> {
148        Some(unsafe { IsWindowVisible(self.window) == 1 })
149    }
150
151    #[inline]
152    pub fn request_redraw(&self) {
153        // NOTE: mark that we requested a redraw to handle requests during `WM_PAINT` handling.
154        self.window_state.lock().unwrap().redraw_requested = true;
155        unsafe {
156            RedrawWindow(self.hwnd(), ptr::null(), 0, RDW_INTERNALPAINT);
157        }
158    }
159
160    #[inline]
161    pub fn pre_present_notify(&self) {}
162
163    #[inline]
164    pub fn outer_position(&self) -> Result<PhysicalPosition<i32>, NotSupportedError> {
165        util::WindowArea::Outer
166            .get_rect(self.hwnd())
167            .map(|rect| Ok(PhysicalPosition::new(rect.left, rect.top)))
168            .expect(
169                "Unexpected GetWindowRect failure; please report this error to \
170                 rust-windowing/winit",
171            )
172    }
173
174    #[inline]
175    pub fn inner_position(&self) -> Result<PhysicalPosition<i32>, NotSupportedError> {
176        let mut position: POINT = unsafe { mem::zeroed() };
177        if unsafe { ClientToScreen(self.hwnd(), &mut position) } == false.into() {
178            panic!(
179                "Unexpected ClientToScreen failure: please report this error to \
180                 rust-windowing/winit"
181            )
182        }
183        Ok(PhysicalPosition::new(position.x, position.y))
184    }
185
186    #[inline]
187    pub fn set_outer_position(&self, position: Position) {
188        let (x, y): (i32, i32) = position.to_physical::<i32>(self.scale_factor()).into();
189
190        let window_state = Arc::clone(&self.window_state);
191        let window = self.window;
192        self.thread_executor.execute_in_thread(move || {
193            let _ = &window;
194            WindowState::set_window_flags(window_state.lock().unwrap(), window, |f| {
195                f.set(WindowFlags::MAXIMIZED, false)
196            });
197        });
198
199        unsafe {
200            SetWindowPos(
201                self.hwnd(),
202                0,
203                x,
204                y,
205                0,
206                0,
207                SWP_ASYNCWINDOWPOS | SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE,
208            );
209            InvalidateRgn(self.hwnd(), 0, false.into());
210        }
211    }
212
213    #[inline]
214    pub fn inner_size(&self) -> PhysicalSize<u32> {
215        let mut rect: RECT = unsafe { mem::zeroed() };
216        if unsafe { GetClientRect(self.hwnd(), &mut rect) } == false.into() {
217            panic!(
218                "Unexpected GetClientRect failure: please report this error to \
219                 rust-windowing/winit"
220            )
221        }
222        PhysicalSize::new((rect.right - rect.left) as u32, (rect.bottom - rect.top) as u32)
223    }
224
225    #[inline]
226    pub fn outer_size(&self) -> PhysicalSize<u32> {
227        util::WindowArea::Outer
228            .get_rect(self.hwnd())
229            .map(|rect| {
230                PhysicalSize::new((rect.right - rect.left) as u32, (rect.bottom - rect.top) as u32)
231            })
232            .unwrap()
233    }
234
235    #[inline]
236    pub fn request_inner_size(&self, size: Size) -> Option<PhysicalSize<u32>> {
237        let scale_factor = self.scale_factor();
238        let physical_size = size.to_physical::<u32>(scale_factor);
239
240        let window_flags = self.window_state_lock().window_flags;
241        window_flags.set_size(self.hwnd(), physical_size);
242
243        if physical_size != self.inner_size() {
244            let window_state = Arc::clone(&self.window_state);
245            let window = self.window;
246            self.thread_executor.execute_in_thread(move || {
247                let _ = &window;
248                WindowState::set_window_flags(window_state.lock().unwrap(), window, |f| {
249                    f.set(WindowFlags::MAXIMIZED, false)
250                });
251            });
252        }
253
254        None
255    }
256
257    #[inline]
258    pub fn set_min_inner_size(&self, size: Option<Size>) {
259        self.window_state_lock().min_size = size;
260        // Make windows re-check the window size bounds.
261        let size = self.inner_size();
262        self.request_inner_size(size.into());
263    }
264
265    #[inline]
266    pub fn set_max_inner_size(&self, size: Option<Size>) {
267        self.window_state_lock().max_size = size;
268        // Make windows re-check the window size bounds.
269        let size = self.inner_size();
270        self.request_inner_size(size.into());
271    }
272
273    #[inline]
274    pub fn resize_increments(&self) -> Option<PhysicalSize<u32>> {
275        let w = self.window_state_lock();
276        let scale_factor = w.scale_factor;
277        w.resize_increments.map(|size| size.to_physical(scale_factor))
278    }
279
280    #[inline]
281    pub fn set_resize_increments(&self, increments: Option<Size>) {
282        self.window_state_lock().resize_increments = increments;
283    }
284
285    #[inline]
286    pub fn set_resizable(&self, resizable: bool) {
287        let window = self.window;
288        let window_state = Arc::clone(&self.window_state);
289
290        self.thread_executor.execute_in_thread(move || {
291            let _ = &window;
292            WindowState::set_window_flags(window_state.lock().unwrap(), window, |f| {
293                f.set(WindowFlags::RESIZABLE, resizable)
294            });
295        });
296    }
297
298    #[inline]
299    pub fn is_resizable(&self) -> bool {
300        let window_state = self.window_state_lock();
301        window_state.window_flags.contains(WindowFlags::RESIZABLE)
302    }
303
304    #[inline]
305    pub fn set_enabled_buttons(&self, buttons: WindowButtons) {
306        let window = self.window;
307        let window_state = Arc::clone(&self.window_state);
308
309        self.thread_executor.execute_in_thread(move || {
310            let _ = &window;
311            WindowState::set_window_flags(window_state.lock().unwrap(), window, |f| {
312                f.set(WindowFlags::MINIMIZABLE, buttons.contains(WindowButtons::MINIMIZE));
313                f.set(WindowFlags::MAXIMIZABLE, buttons.contains(WindowButtons::MAXIMIZE));
314                f.set(WindowFlags::CLOSABLE, buttons.contains(WindowButtons::CLOSE))
315            });
316        });
317    }
318
319    pub fn enabled_buttons(&self) -> WindowButtons {
320        let mut buttons = WindowButtons::empty();
321        let window_state = self.window_state_lock();
322        if window_state.window_flags.contains(WindowFlags::MINIMIZABLE) {
323            buttons |= WindowButtons::MINIMIZE;
324        }
325        if window_state.window_flags.contains(WindowFlags::MAXIMIZABLE) {
326            buttons |= WindowButtons::MAXIMIZE;
327        }
328        if window_state.window_flags.contains(WindowFlags::CLOSABLE) {
329            buttons |= WindowButtons::CLOSE;
330        }
331        buttons
332    }
333
334    /// Returns the `hwnd` of this window.
335    #[inline]
336    pub fn hwnd(&self) -> HWND {
337        self.window
338    }
339
340    #[cfg(feature = "rwh_04")]
341    #[inline]
342    pub fn raw_window_handle_rwh_04(&self) -> rwh_04::RawWindowHandle {
343        let mut window_handle = rwh_04::Win32Handle::empty();
344        window_handle.hwnd = self.window as *mut _;
345        let hinstance = unsafe { super::get_window_long(self.hwnd(), GWLP_HINSTANCE) };
346        window_handle.hinstance = hinstance as *mut _;
347        rwh_04::RawWindowHandle::Win32(window_handle)
348    }
349
350    #[cfg(feature = "rwh_05")]
351    #[inline]
352    pub fn raw_window_handle_rwh_05(&self) -> rwh_05::RawWindowHandle {
353        let mut window_handle = rwh_05::Win32WindowHandle::empty();
354        window_handle.hwnd = self.window as *mut _;
355        let hinstance = unsafe { super::get_window_long(self.hwnd(), GWLP_HINSTANCE) };
356        window_handle.hinstance = hinstance as *mut _;
357        rwh_05::RawWindowHandle::Win32(window_handle)
358    }
359
360    #[cfg(feature = "rwh_05")]
361    #[inline]
362    pub fn raw_display_handle_rwh_05(&self) -> rwh_05::RawDisplayHandle {
363        rwh_05::RawDisplayHandle::Windows(rwh_05::WindowsDisplayHandle::empty())
364    }
365
366    #[cfg(feature = "rwh_06")]
367    #[inline]
368    pub unsafe fn rwh_06_no_thread_check(
369        &self,
370    ) -> Result<rwh_06::RawWindowHandle, rwh_06::HandleError> {
371        let mut window_handle = rwh_06::Win32WindowHandle::new(unsafe {
372            // SAFETY: Handle will never be zero.
373            std::num::NonZeroIsize::new_unchecked(self.window)
374        });
375        let hinstance = unsafe { super::get_window_long(self.hwnd(), GWLP_HINSTANCE) };
376        window_handle.hinstance = std::num::NonZeroIsize::new(hinstance);
377        Ok(rwh_06::RawWindowHandle::Win32(window_handle))
378    }
379
380    #[cfg(feature = "rwh_06")]
381    #[inline]
382    pub fn raw_window_handle_rwh_06(&self) -> Result<rwh_06::RawWindowHandle, rwh_06::HandleError> {
383        // TODO: Write a test once integration framework is ready to ensure that it holds.
384        // If we aren't in the GUI thread, we can't return the window.
385        if !self.thread_executor.in_event_loop_thread() {
386            tracing::error!("tried to access window handle outside of the main thread");
387            return Err(rwh_06::HandleError::Unavailable);
388        }
389
390        // SAFETY: We are on the correct thread.
391        unsafe { self.rwh_06_no_thread_check() }
392    }
393
394    #[cfg(feature = "rwh_06")]
395    #[inline]
396    pub fn raw_display_handle_rwh_06(
397        &self,
398    ) -> Result<rwh_06::RawDisplayHandle, rwh_06::HandleError> {
399        Ok(rwh_06::RawDisplayHandle::Windows(rwh_06::WindowsDisplayHandle::new()))
400    }
401
402    #[inline]
403    pub fn set_cursor(&self, cursor: Cursor) {
404        match cursor {
405            Cursor::Icon(icon) => {
406                self.window_state_lock().mouse.selected_cursor = SelectedCursor::Named(icon);
407                self.thread_executor.execute_in_thread(move || unsafe {
408                    let cursor = LoadCursorW(0, util::to_windows_cursor(icon));
409                    SetCursor(cursor);
410                });
411            },
412            Cursor::Custom(cursor) => {
413                let new_cursor = match cursor.inner {
414                    WinCursor::Cursor(cursor) => cursor,
415                    WinCursor::Failed => {
416                        warn!("Requested to apply failed cursor");
417                        return;
418                    },
419                };
420                self.window_state_lock().mouse.selected_cursor =
421                    SelectedCursor::Custom(new_cursor.clone());
422                self.thread_executor.execute_in_thread(move || unsafe {
423                    SetCursor(new_cursor.as_raw_handle());
424                });
425            },
426        }
427    }
428
429    #[inline]
430    pub fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), ExternalError> {
431        let window = self.window;
432        let window_state = Arc::clone(&self.window_state);
433        let (tx, rx) = channel();
434
435        self.thread_executor.execute_in_thread(move || {
436            let _ = &window;
437            let result = window_state
438                .lock()
439                .unwrap()
440                .mouse
441                .set_cursor_flags(window, |f| {
442                    f.set(CursorFlags::GRABBED, mode != CursorGrabMode::None);
443                    f.set(CursorFlags::LOCKED, mode == CursorGrabMode::Locked);
444                })
445                .map_err(|e| ExternalError::Os(os_error!(e)));
446            let _ = tx.send(result);
447        });
448        rx.recv().unwrap()
449    }
450
451    #[inline]
452    pub fn set_cursor_visible(&self, visible: bool) {
453        let window = self.window;
454        let window_state = Arc::clone(&self.window_state);
455        let (tx, rx) = channel();
456
457        self.thread_executor.execute_in_thread(move || {
458            let _ = &window;
459            let result = window_state
460                .lock()
461                .unwrap()
462                .mouse
463                .set_cursor_flags(window, |f| f.set(CursorFlags::HIDDEN, !visible))
464                .map_err(|e| e.to_string());
465            let _ = tx.send(result);
466        });
467        rx.recv().unwrap().ok();
468    }
469
470    #[inline]
471    pub fn scale_factor(&self) -> f64 {
472        self.window_state_lock().scale_factor
473    }
474
475    #[inline]
476    pub fn set_cursor_position(&self, position: Position) -> Result<(), ExternalError> {
477        let scale_factor = self.scale_factor();
478        let (x, y) = position.to_physical::<i32>(scale_factor).into();
479
480        let mut point = POINT { x, y };
481        unsafe {
482            if ClientToScreen(self.hwnd(), &mut point) == false.into() {
483                return Err(ExternalError::Os(os_error!(io::Error::last_os_error())));
484            }
485            if SetCursorPos(point.x, point.y) == false.into() {
486                return Err(ExternalError::Os(os_error!(io::Error::last_os_error())));
487            }
488        }
489        Ok(())
490    }
491
492    unsafe fn handle_os_dragging(&self, wparam: WPARAM) {
493        let window = self.window;
494        let window_state = self.window_state.clone();
495
496        self.thread_executor.execute_in_thread(move || {
497            {
498                let mut guard = window_state.lock().unwrap();
499                if !guard.dragging {
500                    guard.dragging = true;
501                } else {
502                    return;
503                }
504            }
505
506            let points = {
507                let mut pos = unsafe { mem::zeroed() };
508                unsafe { GetCursorPos(&mut pos) };
509                pos
510            };
511            let points = POINTS { x: points.x as i16, y: points.y as i16 };
512
513            // ReleaseCapture needs to execute on the main thread
514            unsafe { ReleaseCapture() };
515
516            unsafe {
517                PostMessageW(window, WM_NCLBUTTONDOWN, wparam, &points as *const _ as LPARAM)
518            };
519        });
520    }
521
522    #[inline]
523    pub fn drag_window(&self) -> Result<(), ExternalError> {
524        unsafe {
525            self.handle_os_dragging(HTCAPTION as WPARAM);
526        }
527
528        Ok(())
529    }
530
531    #[inline]
532    pub fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), ExternalError> {
533        unsafe {
534            self.handle_os_dragging(match direction {
535                ResizeDirection::East => HTRIGHT,
536                ResizeDirection::North => HTTOP,
537                ResizeDirection::NorthEast => HTTOPRIGHT,
538                ResizeDirection::NorthWest => HTTOPLEFT,
539                ResizeDirection::South => HTBOTTOM,
540                ResizeDirection::SouthEast => HTBOTTOMRIGHT,
541                ResizeDirection::SouthWest => HTBOTTOMLEFT,
542                ResizeDirection::West => HTLEFT,
543            } as WPARAM);
544        }
545
546        Ok(())
547    }
548
549    unsafe fn handle_showing_window_menu(&self, position: Position) {
550        unsafe {
551            let point = {
552                let mut point = POINT { x: 0, y: 0 };
553                let scale_factor = self.scale_factor();
554                let (x, y) = position.to_physical::<i32>(scale_factor).into();
555                point.x = x;
556                point.y = y;
557                if ClientToScreen(self.hwnd(), &mut point) == false.into() {
558                    warn!(
559                        "Can't convert client-area coordinates to screen coordinates when showing \
560                         window menu."
561                    );
562                    return;
563                }
564                point
565            };
566
567            // get the current system menu
568            let h_menu = GetSystemMenu(self.hwnd(), 0);
569            if h_menu == 0 {
570                warn!("The corresponding window doesn't have a system menu");
571                // This situation should not be treated as an error so just return without showing
572                // menu.
573                return;
574            }
575
576            fn enable(b: bool) -> MENU_ITEM_STATE {
577                if b {
578                    MFS_ENABLED
579                } else {
580                    MFS_DISABLED
581                }
582            }
583
584            // Change the menu items according to the current window status.
585
586            let restore_btn = enable(self.is_maximized() && self.is_resizable());
587            let size_btn = enable(!self.is_maximized() && self.is_resizable());
588            let maximize_btn = enable(!self.is_maximized() && self.is_resizable());
589
590            EnableMenuItem(h_menu, SC_RESTORE, MF_BYCOMMAND | restore_btn);
591            EnableMenuItem(h_menu, SC_MOVE, MF_BYCOMMAND | enable(!self.is_maximized()));
592            EnableMenuItem(h_menu, SC_SIZE, MF_BYCOMMAND | size_btn);
593            EnableMenuItem(h_menu, SC_MINIMIZE, MF_BYCOMMAND | MFS_ENABLED);
594            EnableMenuItem(h_menu, SC_MAXIMIZE, MF_BYCOMMAND | maximize_btn);
595            EnableMenuItem(h_menu, SC_CLOSE, MF_BYCOMMAND | MFS_ENABLED);
596
597            // Set the default menu item.
598            SetMenuDefaultItem(h_menu, SC_CLOSE, 0);
599
600            // Popup the system menu at the position.
601            let result = TrackPopupMenu(
602                h_menu,
603                TPM_RETURNCMD | TPM_LEFTALIGN, /* for now im using LTR, but we have to use user
604                                                * layout direction */
605                point.x,
606                point.y,
607                0,
608                self.hwnd(),
609                std::ptr::null_mut(),
610            );
611
612            if result == 0 {
613                // User canceled the menu, no need to continue.
614                return;
615            }
616
617            // Send the command that the user select to the corresponding window.
618            if PostMessageW(self.hwnd(), WM_SYSCOMMAND, result as _, 0) == 0 {
619                warn!("Can't post the system menu message to the window.");
620            }
621        }
622    }
623
624    #[inline]
625    pub fn show_window_menu(&self, position: Position) {
626        unsafe {
627            self.handle_showing_window_menu(position);
628        }
629    }
630
631    #[inline]
632    pub fn set_cursor_hittest(&self, hittest: bool) -> Result<(), ExternalError> {
633        let window = self.window;
634        let window_state = Arc::clone(&self.window_state);
635        self.thread_executor.execute_in_thread(move || {
636            WindowState::set_window_flags(window_state.lock().unwrap(), window, |f| {
637                f.set(WindowFlags::IGNORE_CURSOR_EVENT, !hittest)
638            });
639        });
640
641        Ok(())
642    }
643
644    #[inline]
645    pub fn id(&self) -> WindowId {
646        WindowId(self.hwnd())
647    }
648
649    #[inline]
650    pub fn set_minimized(&self, minimized: bool) {
651        let window = self.window;
652        let window_state = Arc::clone(&self.window_state);
653
654        let is_minimized = util::is_minimized(self.hwnd());
655
656        self.thread_executor.execute_in_thread(move || {
657            let _ = &window;
658            WindowState::set_window_flags_in_place(&mut window_state.lock().unwrap(), |f| {
659                f.set(WindowFlags::MINIMIZED, is_minimized)
660            });
661            WindowState::set_window_flags(window_state.lock().unwrap(), window, |f| {
662                f.set(WindowFlags::MINIMIZED, minimized)
663            });
664        });
665    }
666
667    #[inline]
668    pub fn is_minimized(&self) -> Option<bool> {
669        Some(util::is_minimized(self.hwnd()))
670    }
671
672    #[inline]
673    pub fn set_maximized(&self, maximized: bool) {
674        let window = self.window;
675        let window_state = Arc::clone(&self.window_state);
676
677        self.thread_executor.execute_in_thread(move || {
678            let _ = &window;
679            WindowState::set_window_flags(window_state.lock().unwrap(), window, |f| {
680                f.set(WindowFlags::MAXIMIZED, maximized)
681            });
682        });
683    }
684
685    #[inline]
686    pub fn is_maximized(&self) -> bool {
687        let window_state = self.window_state_lock();
688        window_state.window_flags.contains(WindowFlags::MAXIMIZED)
689    }
690
691    #[inline]
692    pub fn fullscreen(&self) -> Option<Fullscreen> {
693        let window_state = self.window_state_lock();
694        window_state.fullscreen.clone()
695    }
696
697    #[inline]
698    pub fn set_fullscreen(&self, fullscreen: Option<Fullscreen>) {
699        let window = self.window;
700        let window_state = Arc::clone(&self.window_state);
701
702        let mut window_state_lock = window_state.lock().unwrap();
703        let old_fullscreen = window_state_lock.fullscreen.clone();
704
705        match (&old_fullscreen, &fullscreen) {
706            // Return if we already are in the same fullscreen mode
707            _ if old_fullscreen == fullscreen => return,
708            // Return if saved Borderless(monitor) is the same as current monitor when requested
709            // fullscreen is Borderless(None)
710            (Some(Fullscreen::Borderless(Some(monitor))), Some(Fullscreen::Borderless(None)))
711                if *monitor == monitor::current_monitor(window) =>
712            {
713                return
714            },
715            _ => {},
716        }
717
718        window_state_lock.fullscreen.clone_from(&fullscreen);
719        drop(window_state_lock);
720
721        self.thread_executor.execute_in_thread(move || {
722            let _ = &window;
723            // Change video mode if we're transitioning to or from exclusive
724            // fullscreen
725            match (&old_fullscreen, &fullscreen) {
726                (_, Some(Fullscreen::Exclusive(video_mode))) => {
727                    let monitor = video_mode.monitor();
728                    let monitor_info = monitor::get_monitor_info(monitor.hmonitor()).unwrap();
729
730                    let res = unsafe {
731                        ChangeDisplaySettingsExW(
732                            monitor_info.szDevice.as_ptr(),
733                            &*video_mode.native_video_mode,
734                            0,
735                            CDS_FULLSCREEN,
736                            ptr::null(),
737                        )
738                    };
739
740                    debug_assert!(res != DISP_CHANGE_BADFLAGS);
741                    debug_assert!(res != DISP_CHANGE_BADMODE);
742                    debug_assert!(res != DISP_CHANGE_BADPARAM);
743                    debug_assert!(res != DISP_CHANGE_FAILED);
744                    assert_eq!(res, DISP_CHANGE_SUCCESSFUL);
745                },
746                (Some(Fullscreen::Exclusive(_)), _) => {
747                    let res = unsafe {
748                        ChangeDisplaySettingsExW(
749                            ptr::null(),
750                            ptr::null(),
751                            0,
752                            CDS_FULLSCREEN,
753                            ptr::null(),
754                        )
755                    };
756
757                    debug_assert!(res != DISP_CHANGE_BADFLAGS);
758                    debug_assert!(res != DISP_CHANGE_BADMODE);
759                    debug_assert!(res != DISP_CHANGE_BADPARAM);
760                    debug_assert!(res != DISP_CHANGE_FAILED);
761                    assert_eq!(res, DISP_CHANGE_SUCCESSFUL);
762                },
763                _ => (),
764            }
765
766            unsafe {
767                // There are some scenarios where calling `ChangeDisplaySettingsExW` takes long
768                // enough to execute that the DWM thinks our program has frozen and takes over
769                // our program's window. When that happens, the `SetWindowPos` call below gets
770                // eaten and the window doesn't get set to the proper fullscreen position.
771                //
772                // Calling `PeekMessageW` here notifies Windows that our process is still running
773                // fine, taking control back from the DWM and ensuring that the `SetWindowPos` call
774                // below goes through.
775                let mut msg = mem::zeroed();
776                PeekMessageW(&mut msg, 0, 0, 0, PM_NOREMOVE);
777            }
778
779            // Update window style
780            WindowState::set_window_flags(window_state.lock().unwrap(), window, |f| {
781                f.set(
782                    WindowFlags::MARKER_EXCLUSIVE_FULLSCREEN,
783                    matches!(fullscreen, Some(Fullscreen::Exclusive(_))),
784                );
785                f.set(
786                    WindowFlags::MARKER_BORDERLESS_FULLSCREEN,
787                    matches!(fullscreen, Some(Fullscreen::Borderless(_))),
788                );
789            });
790
791            // Mark as fullscreen window wrt to z-order
792            //
793            // this needs to be called before the below fullscreen SetWindowPos as this itself
794            // will generate WM_SIZE messages of the old window size that can race with what we set
795            // below
796            unsafe {
797                taskbar_mark_fullscreen(window, fullscreen.is_some());
798            }
799
800            // Update window bounds
801            match &fullscreen {
802                Some(fullscreen) => {
803                    // Save window bounds before entering fullscreen
804                    let placement = unsafe {
805                        let mut placement = mem::zeroed();
806                        GetWindowPlacement(window, &mut placement);
807                        placement
808                    };
809
810                    window_state.lock().unwrap().saved_window = Some(SavedWindow { placement });
811
812                    let monitor = match &fullscreen {
813                        Fullscreen::Exclusive(video_mode) => video_mode.monitor(),
814                        Fullscreen::Borderless(Some(monitor)) => monitor.clone(),
815                        Fullscreen::Borderless(None) => monitor::current_monitor(window),
816                    };
817
818                    let position: (i32, i32) = monitor.position().into();
819                    let size: (u32, u32) = monitor.size().into();
820
821                    unsafe {
822                        SetWindowPos(
823                            window,
824                            0,
825                            position.0,
826                            position.1,
827                            size.0 as i32,
828                            size.1 as i32,
829                            SWP_ASYNCWINDOWPOS | SWP_NOZORDER,
830                        );
831                        InvalidateRgn(window, 0, false.into());
832                    }
833                },
834                None => {
835                    let mut window_state_lock = window_state.lock().unwrap();
836                    if let Some(SavedWindow { placement }) = window_state_lock.saved_window.take() {
837                        drop(window_state_lock);
838                        unsafe {
839                            SetWindowPlacement(window, &placement);
840                            InvalidateRgn(window, 0, false.into());
841                        }
842                    }
843                },
844            }
845        });
846    }
847
848    #[inline]
849    pub fn set_decorations(&self, decorations: bool) {
850        let window = self.window;
851        let window_state = Arc::clone(&self.window_state);
852
853        self.thread_executor.execute_in_thread(move || {
854            let _ = &window;
855            WindowState::set_window_flags(window_state.lock().unwrap(), window, |f| {
856                f.set(WindowFlags::MARKER_DECORATIONS, decorations)
857            });
858        });
859    }
860
861    #[inline]
862    pub fn is_decorated(&self) -> bool {
863        let window_state = self.window_state_lock();
864        window_state.window_flags.contains(WindowFlags::MARKER_DECORATIONS)
865    }
866
867    #[inline]
868    pub fn set_window_level(&self, level: WindowLevel) {
869        let window = self.window;
870        let window_state = Arc::clone(&self.window_state);
871
872        self.thread_executor.execute_in_thread(move || {
873            let _ = &window;
874            WindowState::set_window_flags(window_state.lock().unwrap(), window, |f| {
875                f.set(WindowFlags::ALWAYS_ON_TOP, level == WindowLevel::AlwaysOnTop);
876                f.set(WindowFlags::ALWAYS_ON_BOTTOM, level == WindowLevel::AlwaysOnBottom);
877            });
878        });
879    }
880
881    #[inline]
882    pub fn current_monitor(&self) -> Option<MonitorHandle> {
883        Some(monitor::current_monitor(self.hwnd()))
884    }
885
886    #[inline]
887    pub fn set_window_icon(&self, window_icon: Option<Icon>) {
888        if let Some(ref window_icon) = window_icon {
889            window_icon.inner.set_for_window(self.hwnd(), IconType::Small);
890        } else {
891            icon::unset_for_window(self.hwnd(), IconType::Small);
892        }
893        self.window_state_lock().window_icon = window_icon;
894    }
895
896    #[inline]
897    pub fn set_enable(&self, enabled: bool) {
898        unsafe { EnableWindow(self.hwnd(), enabled.into()) };
899    }
900
901    #[inline]
902    pub fn set_taskbar_icon(&self, taskbar_icon: Option<Icon>) {
903        if let Some(ref taskbar_icon) = taskbar_icon {
904            taskbar_icon.inner.set_for_window(self.hwnd(), IconType::Big);
905        } else {
906            icon::unset_for_window(self.hwnd(), IconType::Big);
907        }
908        self.window_state_lock().taskbar_icon = taskbar_icon;
909    }
910
911    #[inline]
912    pub fn set_ime_cursor_area(&self, spot: Position, size: Size) {
913        let window = self.window;
914        let state = self.window_state.clone();
915        self.thread_executor.execute_in_thread(move || unsafe {
916            let scale_factor = state.lock().unwrap().scale_factor;
917            ImeContext::current(window).set_ime_cursor_area(spot, size, scale_factor);
918        });
919    }
920
921    #[inline]
922    pub fn set_ime_allowed(&self, allowed: bool) {
923        let window = self.window;
924        let state = self.window_state.clone();
925        self.thread_executor.execute_in_thread(move || unsafe {
926            state.lock().unwrap().ime_allowed = allowed;
927            ImeContext::set_ime_allowed(window, allowed);
928        })
929    }
930
931    #[inline]
932    pub fn set_ime_purpose(&self, _purpose: ImePurpose) {}
933
934    #[inline]
935    pub fn request_user_attention(&self, request_type: Option<UserAttentionType>) {
936        let window = self.window;
937        let active_window_handle = unsafe { GetActiveWindow() };
938        if window == active_window_handle {
939            return;
940        }
941
942        self.thread_executor.execute_in_thread(move || unsafe {
943            let (flags, count) = request_type
944                .map(|ty| match ty {
945                    UserAttentionType::Critical => (FLASHW_ALL | FLASHW_TIMERNOFG, u32::MAX),
946                    UserAttentionType::Informational => (FLASHW_TRAY | FLASHW_TIMERNOFG, 0),
947                })
948                .unwrap_or((FLASHW_STOP, 0));
949
950            let flash_info = FLASHWINFO {
951                cbSize: mem::size_of::<FLASHWINFO>() as u32,
952                hwnd: window,
953                dwFlags: flags,
954                uCount: count,
955                dwTimeout: 0,
956            };
957            FlashWindowEx(&flash_info);
958        });
959    }
960
961    #[inline]
962    pub fn set_theme(&self, theme: Option<Theme>) {
963        try_theme(self.window, theme);
964    }
965
966    #[inline]
967    pub fn theme(&self) -> Option<Theme> {
968        Some(self.window_state_lock().current_theme)
969    }
970
971    #[inline]
972    pub fn has_focus(&self) -> bool {
973        let window_state = self.window_state.lock().unwrap();
974        window_state.has_active_focus()
975    }
976
977    pub fn title(&self) -> String {
978        let len = unsafe { GetWindowTextLengthW(self.window) } + 1;
979        let mut buf = vec![0; len as usize];
980        unsafe { GetWindowTextW(self.window, buf.as_mut_ptr(), len) };
981        util::decode_wide(&buf).to_string_lossy().to_string()
982    }
983
984    #[inline]
985    pub fn set_skip_taskbar(&self, skip: bool) {
986        self.window_state_lock().skip_taskbar = skip;
987        unsafe { set_skip_taskbar(self.hwnd(), skip) };
988    }
989
990    #[inline]
991    pub fn set_undecorated_shadow(&self, shadow: bool) {
992        let window = self.window;
993        let window_state = Arc::clone(&self.window_state);
994
995        self.thread_executor.execute_in_thread(move || {
996            let _ = &window;
997            WindowState::set_window_flags(window_state.lock().unwrap(), window, |f| {
998                f.set(WindowFlags::MARKER_UNDECORATED_SHADOW, shadow)
999            });
1000        });
1001    }
1002
1003    #[inline]
1004    pub fn set_system_backdrop(&self, backdrop_type: BackdropType) {
1005        unsafe {
1006            DwmSetWindowAttribute(
1007                self.hwnd(),
1008                DWMWA_SYSTEMBACKDROP_TYPE as u32,
1009                &(backdrop_type as i32) as *const _ as _,
1010                mem::size_of::<DWM_SYSTEMBACKDROP_TYPE>() as _,
1011            );
1012        }
1013    }
1014
1015    #[inline]
1016    pub fn focus_window(&self) {
1017        let window_flags = self.window_state_lock().window_flags();
1018
1019        let is_visible = window_flags.contains(WindowFlags::VISIBLE);
1020        let is_minimized = util::is_minimized(self.hwnd());
1021        let is_foreground = self.window == unsafe { GetForegroundWindow() };
1022
1023        if is_visible && !is_minimized && !is_foreground {
1024            unsafe { force_window_active(self.window) };
1025        }
1026    }
1027
1028    #[inline]
1029    pub fn set_content_protected(&self, protected: bool) {
1030        unsafe {
1031            SetWindowDisplayAffinity(
1032                self.hwnd(),
1033                if protected { WDA_EXCLUDEFROMCAPTURE } else { WDA_NONE },
1034            )
1035        };
1036    }
1037
1038    #[inline]
1039    pub fn reset_dead_keys(&self) {
1040        // `ToUnicode` consumes the dead-key by default, so we are constructing a fake (but valid)
1041        // key input which we can call `ToUnicode` with.
1042        unsafe {
1043            let vk = VK_SPACE as VIRTUAL_KEY;
1044            let scancode = MapVirtualKeyW(vk as u32, MAPVK_VK_TO_VSC);
1045            let kbd_state = [0; 256];
1046            let mut char_buff = [MaybeUninit::uninit(); 8];
1047            ToUnicode(
1048                vk as u32,
1049                scancode,
1050                kbd_state.as_ptr(),
1051                char_buff[0].as_mut_ptr(),
1052                char_buff.len() as i32,
1053                0,
1054            );
1055        }
1056    }
1057
1058    #[inline]
1059    pub fn set_border_color(&self, color: Color) {
1060        unsafe {
1061            DwmSetWindowAttribute(
1062                self.hwnd(),
1063                DWMWA_BORDER_COLOR as u32,
1064                &color as *const _ as _,
1065                mem::size_of::<Color>() as _,
1066            );
1067        }
1068    }
1069
1070    #[inline]
1071    pub fn set_title_background_color(&self, color: Color) {
1072        unsafe {
1073            DwmSetWindowAttribute(
1074                self.hwnd(),
1075                DWMWA_CAPTION_COLOR as u32,
1076                &color as *const _ as _,
1077                mem::size_of::<Color>() as _,
1078            );
1079        }
1080    }
1081
1082    #[inline]
1083    pub fn set_title_text_color(&self, color: Color) {
1084        unsafe {
1085            DwmSetWindowAttribute(
1086                self.hwnd(),
1087                DWMWA_TEXT_COLOR as u32,
1088                &color as *const _ as _,
1089                mem::size_of::<Color>() as _,
1090            );
1091        }
1092    }
1093
1094    #[inline]
1095    pub fn set_corner_preference(&self, preference: CornerPreference) {
1096        unsafe {
1097            DwmSetWindowAttribute(
1098                self.hwnd(),
1099                DWMWA_WINDOW_CORNER_PREFERENCE as u32,
1100                &(preference as DWM_WINDOW_CORNER_PREFERENCE) as *const _ as _,
1101                mem::size_of::<DWM_WINDOW_CORNER_PREFERENCE>() as _,
1102            );
1103        }
1104    }
1105}
1106
1107impl Drop for Window {
1108    #[inline]
1109    fn drop(&mut self) {
1110        unsafe {
1111            // The window must be destroyed from the same thread that created it, so we send a
1112            // custom message to be handled by our callback to do the actual work.
1113            PostMessageW(self.hwnd(), DESTROY_MSG_ID.get(), 0, 0);
1114        }
1115    }
1116}
1117
1118pub(super) struct InitData<'a> {
1119    // inputs
1120    pub event_loop: &'a ActiveEventLoop,
1121    pub attributes: WindowAttributes,
1122    pub window_flags: WindowFlags,
1123    // outputs
1124    pub window: Option<Window>,
1125}
1126
1127impl InitData<'_> {
1128    unsafe fn create_window(&self, window: HWND) -> Window {
1129        // Register for touch events if applicable
1130        {
1131            let digitizer = unsafe { GetSystemMetrics(SM_DIGITIZER) as u32 };
1132            if digitizer & NID_READY != 0 {
1133                unsafe { RegisterTouchWindow(window, TWF_WANTPALM) };
1134            }
1135        }
1136
1137        let dpi = unsafe { hwnd_dpi(window) };
1138        let scale_factor = dpi_to_scale_factor(dpi);
1139
1140        // If the system theme is dark, we need to set the window theme now
1141        // before we update the window flags (and possibly show the
1142        // window for the first time).
1143        let current_theme = try_theme(window, self.attributes.preferred_theme);
1144
1145        let window_state = {
1146            let window_state = WindowState::new(
1147                &self.attributes,
1148                scale_factor,
1149                current_theme,
1150                self.attributes.preferred_theme,
1151            );
1152            let window_state = Arc::new(Mutex::new(window_state));
1153            WindowState::set_window_flags(window_state.lock().unwrap(), window, |f| {
1154                *f = self.window_flags
1155            });
1156            window_state
1157        };
1158
1159        enable_non_client_dpi_scaling(window);
1160
1161        unsafe { ImeContext::set_ime_allowed(window, false) };
1162
1163        Window { window, window_state, thread_executor: self.event_loop.create_thread_executor() }
1164    }
1165
1166    unsafe fn create_window_data(&self, win: &Window) -> event_loop::WindowData {
1167        let file_drop_handler = if self.attributes.platform_specific.drag_and_drop {
1168            let ole_init_result = unsafe { OleInitialize(ptr::null_mut()) };
1169            // It is ok if the initialize result is `S_FALSE` because it might happen that
1170            // multiple windows are created on the same thread.
1171            if ole_init_result == OLE_E_WRONGCOMPOBJ {
1172                panic!("OleInitialize failed! Result was: `OLE_E_WRONGCOMPOBJ`");
1173            } else if ole_init_result == RPC_E_CHANGED_MODE {
1174                panic!(
1175                    "OleInitialize failed! Result was: `RPC_E_CHANGED_MODE`. Make sure other \
1176                     crates are not using multithreaded COM library on the same thread or disable \
1177                     drag and drop support."
1178                );
1179            }
1180
1181            let file_drop_runner = self.event_loop.runner_shared.clone();
1182            let file_drop_handler = FileDropHandler::new(
1183                win.window,
1184                Box::new(move |event| {
1185                    if let Ok(e) = event.map_nonuser_event() {
1186                        file_drop_runner.send_event(e)
1187                    }
1188                }),
1189            );
1190
1191            let handler_interface_ptr =
1192                unsafe { &mut (*file_drop_handler.data).interface as *mut _ as *mut c_void };
1193
1194            assert_eq!(unsafe { RegisterDragDrop(win.window, handler_interface_ptr) }, S_OK);
1195            Some(file_drop_handler)
1196        } else {
1197            None
1198        };
1199
1200        event_loop::WindowData {
1201            window_state: win.window_state.clone(),
1202            event_loop_runner: self.event_loop.runner_shared.clone(),
1203            key_event_builder: KeyEventBuilder::default(),
1204            _file_drop_handler: file_drop_handler,
1205            userdata_removed: Cell::new(false),
1206            recurse_depth: Cell::new(0),
1207        }
1208    }
1209
1210    // Returns a pointer to window user data on success.
1211    // The user data will be registered for the window and can be accessed within the window event
1212    // callback.
1213    pub unsafe fn on_nccreate(&mut self, window: HWND) -> Option<isize> {
1214        let runner = self.event_loop.runner_shared.clone();
1215        let result = runner.catch_unwind(|| {
1216            let window = unsafe { self.create_window(window) };
1217            let window_data = unsafe { self.create_window_data(&window) };
1218            (window, window_data)
1219        });
1220
1221        result.map(|(win, userdata)| {
1222            self.window = Some(win);
1223            let userdata = Box::into_raw(Box::new(userdata));
1224            userdata as _
1225        })
1226    }
1227
1228    pub unsafe fn on_create(&mut self) {
1229        let win = self.window.as_mut().expect("failed window creation");
1230
1231        // making the window transparent
1232        if self.attributes.transparent && !self.attributes.platform_specific.no_redirection_bitmap {
1233            // Empty region for the blur effect, so the window is fully transparent
1234            let region = unsafe { CreateRectRgn(0, 0, -1, -1) };
1235
1236            let bb = DWM_BLURBEHIND {
1237                dwFlags: DWM_BB_ENABLE | DWM_BB_BLURREGION,
1238                fEnable: true.into(),
1239                hRgnBlur: region,
1240                fTransitionOnMaximized: false.into(),
1241            };
1242            let hr = unsafe { DwmEnableBlurBehindWindow(win.hwnd(), &bb) };
1243            if hr < 0 {
1244                warn!("Setting transparent window is failed. HRESULT Code: 0x{:X}", hr);
1245            }
1246            unsafe { DeleteObject(region) };
1247        }
1248
1249        win.set_skip_taskbar(self.attributes.platform_specific.skip_taskbar);
1250        win.set_window_icon(self.attributes.window_icon.clone());
1251        win.set_taskbar_icon(self.attributes.platform_specific.taskbar_icon.clone());
1252
1253        let attributes = self.attributes.clone();
1254
1255        if attributes.content_protected {
1256            win.set_content_protected(true);
1257        }
1258
1259        win.set_cursor(attributes.cursor);
1260
1261        // Set visible before setting the size to ensure the
1262        // attribute is correctly applied.
1263        win.set_visible(attributes.visible);
1264
1265        win.set_enabled_buttons(attributes.enabled_buttons);
1266
1267        let size = attributes.inner_size.unwrap_or_else(|| PhysicalSize::new(800, 600).into());
1268        let max_size = attributes
1269            .max_inner_size
1270            .unwrap_or_else(|| PhysicalSize::new(f64::MAX, f64::MAX).into());
1271        let min_size = attributes.min_inner_size.unwrap_or_else(|| PhysicalSize::new(0, 0).into());
1272        let clamped_size = Size::clamp(size, min_size, max_size, win.scale_factor());
1273        win.request_inner_size(clamped_size);
1274
1275        // let margins = MARGINS {
1276        //     cxLeftWidth: 1,
1277        //     cxRightWidth: 1,
1278        //     cyTopHeight: 1,
1279        //     cyBottomHeight: 1,
1280        // };
1281        // dbg!(DwmExtendFrameIntoClientArea(win.hwnd(), &margins as *const _));
1282
1283        if let Some(position) = attributes.position {
1284            win.set_outer_position(position);
1285        }
1286
1287        win.set_system_backdrop(self.attributes.platform_specific.backdrop_type);
1288
1289        if let Some(color) = self.attributes.platform_specific.border_color {
1290            win.set_border_color(color);
1291        }
1292        if let Some(color) = self.attributes.platform_specific.title_background_color {
1293            win.set_title_background_color(color);
1294        }
1295        if let Some(color) = self.attributes.platform_specific.title_text_color {
1296            win.set_title_text_color(color);
1297        }
1298        if let Some(corner) = self.attributes.platform_specific.corner_preference {
1299            win.set_corner_preference(corner);
1300        }
1301    }
1302}
1303unsafe fn init(
1304    attributes: WindowAttributes,
1305    event_loop: &ActiveEventLoop,
1306) -> Result<Window, RootOsError> {
1307    let title = util::encode_wide(&attributes.title);
1308
1309    let class_name = util::encode_wide(&attributes.platform_specific.class_name);
1310    unsafe { register_window_class(&class_name) };
1311
1312    let mut window_flags = WindowFlags::empty();
1313    window_flags.set(WindowFlags::MARKER_DECORATIONS, attributes.decorations);
1314    window_flags.set(
1315        WindowFlags::MARKER_UNDECORATED_SHADOW,
1316        attributes.platform_specific.decoration_shadow,
1317    );
1318    window_flags
1319        .set(WindowFlags::ALWAYS_ON_TOP, attributes.window_level == WindowLevel::AlwaysOnTop);
1320    window_flags
1321        .set(WindowFlags::ALWAYS_ON_BOTTOM, attributes.window_level == WindowLevel::AlwaysOnBottom);
1322    window_flags
1323        .set(WindowFlags::NO_BACK_BUFFER, attributes.platform_specific.no_redirection_bitmap);
1324    window_flags.set(WindowFlags::MARKER_ACTIVATE, attributes.active);
1325    window_flags.set(WindowFlags::TRANSPARENT, attributes.transparent);
1326    // WindowFlags::VISIBLE and MAXIMIZED are set down below after the window has been configured.
1327    window_flags.set(WindowFlags::RESIZABLE, attributes.resizable);
1328    // Will be changed later using `window.set_enabled_buttons` but we need to set a default here
1329    // so the diffing later can work.
1330    window_flags.set(WindowFlags::CLOSABLE, true);
1331    window_flags.set(WindowFlags::CLIP_CHILDREN, attributes.platform_specific.clip_children);
1332
1333    let mut fallback_parent = || match attributes.platform_specific.owner {
1334        Some(parent) => {
1335            window_flags.set(WindowFlags::POPUP, true);
1336            Some(parent)
1337        },
1338        None => {
1339            window_flags.set(WindowFlags::ON_TASKBAR, true);
1340            None
1341        },
1342    };
1343
1344    #[cfg(feature = "rwh_06")]
1345    let parent = match attributes.parent_window.as_ref().map(|handle| handle.0) {
1346        Some(rwh_06::RawWindowHandle::Win32(handle)) => {
1347            window_flags.set(WindowFlags::CHILD, true);
1348            if attributes.platform_specific.menu.is_some() {
1349                warn!("Setting a menu on a child window is unsupported");
1350            }
1351            Some(handle.hwnd.get() as HWND)
1352        },
1353        Some(raw) => unreachable!("Invalid raw window handle {raw:?} on Windows"),
1354        None => fallback_parent(),
1355    };
1356
1357    #[cfg(not(feature = "rwh_06"))]
1358    let parent = fallback_parent();
1359
1360    let menu = attributes.platform_specific.menu;
1361    let fullscreen = attributes.fullscreen.clone();
1362    let maximized = attributes.maximized;
1363    let mut initdata = InitData { event_loop, attributes, window_flags, window: None };
1364
1365    let (style, ex_style) = window_flags.to_window_styles();
1366    let handle = unsafe {
1367        CreateWindowExW(
1368            ex_style,
1369            class_name.as_ptr(),
1370            title.as_ptr(),
1371            style,
1372            CW_USEDEFAULT,
1373            CW_USEDEFAULT,
1374            CW_USEDEFAULT,
1375            CW_USEDEFAULT,
1376            parent.unwrap_or(0),
1377            menu.unwrap_or(0),
1378            util::get_instance_handle(),
1379            &mut initdata as *mut _ as *mut _,
1380        )
1381    };
1382
1383    // If the window creation in `InitData` panicked, then should resume panicking here
1384    if let Err(panic_error) = event_loop.runner_shared.take_panic_error() {
1385        panic::resume_unwind(panic_error)
1386    }
1387
1388    if handle == 0 {
1389        return Err(os_error!(io::Error::last_os_error()));
1390    }
1391
1392    // If the handle is non-null, then window creation must have succeeded, which means
1393    // that we *must* have populated the `InitData.window` field.
1394    let win = initdata.window.unwrap();
1395
1396    // Need to set FULLSCREEN or MAXIMIZED after CreateWindowEx
1397    // This is because if the size is changed in WM_CREATE, the restored size will be stored in that
1398    // size.
1399    if fullscreen.is_some() {
1400        win.set_fullscreen(fullscreen.map(Into::into));
1401        unsafe { force_window_active(win.window) };
1402    } else if maximized {
1403        win.set_maximized(true);
1404    }
1405
1406    Ok(win)
1407}
1408
1409unsafe fn register_window_class(class_name: &[u16]) {
1410    let class = WNDCLASSEXW {
1411        cbSize: mem::size_of::<WNDCLASSEXW>() as u32,
1412        style: CS_HREDRAW | CS_VREDRAW,
1413        lpfnWndProc: Some(super::event_loop::public_window_callback),
1414        cbClsExtra: 0,
1415        cbWndExtra: 0,
1416        hInstance: util::get_instance_handle(),
1417        hIcon: 0,
1418        hCursor: 0, // must be null in order for cursor state to work properly
1419        hbrBackground: 0,
1420        lpszMenuName: ptr::null(),
1421        lpszClassName: class_name.as_ptr(),
1422        hIconSm: 0,
1423    };
1424
1425    // We ignore errors because registering the same window class twice would trigger
1426    //  an error, and because errors here are detected during CreateWindowEx anyway.
1427    // Also since there is no weird element in the struct, there is no reason for this
1428    //  call to fail.
1429    unsafe { RegisterClassExW(&class) };
1430}
1431
1432struct ComInitialized(#[allow(dead_code)] *mut ());
1433impl Drop for ComInitialized {
1434    fn drop(&mut self) {
1435        unsafe { CoUninitialize() };
1436    }
1437}
1438
1439thread_local! {
1440    static COM_INITIALIZED: ComInitialized = {
1441        unsafe {
1442            CoInitializeEx(ptr::null(), COINIT_APARTMENTTHREADED as u32);
1443            ComInitialized(ptr::null_mut())
1444        }
1445    };
1446
1447    static TASKBAR_LIST: Cell<*mut ITaskbarList> = const { Cell::new(ptr::null_mut()) };
1448    static TASKBAR_LIST2: Cell<*mut ITaskbarList2> = const { Cell::new(ptr::null_mut()) };
1449}
1450
1451pub fn com_initialized() {
1452    COM_INITIALIZED.with(|_| {});
1453}
1454
1455// Reference Implementation:
1456// https://github.com/chromium/chromium/blob/f18e79d901f56154f80eea1e2218544285e62623/ui/views/win/fullscreen_handler.cc
1457//
1458// As per MSDN marking the window as fullscreen should ensure that the
1459// taskbar is moved to the bottom of the Z-order when the fullscreen window
1460// is activated. If the window is not fullscreen, the Shell falls back to
1461// heuristics to determine how the window should be treated, which means
1462// that it could still consider the window as fullscreen. :(
1463unsafe fn taskbar_mark_fullscreen(handle: HWND, fullscreen: bool) {
1464    com_initialized();
1465
1466    TASKBAR_LIST2.with(|task_bar_list2_ptr| {
1467        let mut task_bar_list2 = task_bar_list2_ptr.get();
1468
1469        if task_bar_list2.is_null() {
1470            let hr = unsafe {
1471                CoCreateInstance(
1472                    &CLSID_TaskbarList,
1473                    ptr::null_mut(),
1474                    CLSCTX_ALL,
1475                    &IID_ITaskbarList2,
1476                    &mut task_bar_list2 as *mut _ as *mut _,
1477                )
1478            };
1479            if hr != S_OK {
1480                // In visual studio retrieving the taskbar list fails
1481                return;
1482            }
1483
1484            let hr_init = unsafe { (*(*task_bar_list2).lpVtbl).parent.HrInit };
1485            if unsafe { hr_init(task_bar_list2.cast()) } != S_OK {
1486                // In some old windows, the taskbar object could not be created, we just ignore it
1487                return;
1488            }
1489            task_bar_list2_ptr.set(task_bar_list2)
1490        }
1491
1492        task_bar_list2 = task_bar_list2_ptr.get();
1493        let mark_fullscreen_window = unsafe { (*(*task_bar_list2).lpVtbl).MarkFullscreenWindow };
1494        unsafe { mark_fullscreen_window(task_bar_list2, handle, fullscreen.into()) };
1495    })
1496}
1497
1498pub(crate) unsafe fn set_skip_taskbar(hwnd: HWND, skip: bool) {
1499    com_initialized();
1500    TASKBAR_LIST.with(|task_bar_list_ptr| {
1501        let mut task_bar_list = task_bar_list_ptr.get();
1502
1503        if task_bar_list.is_null() {
1504            let hr = unsafe {
1505                CoCreateInstance(
1506                    &CLSID_TaskbarList,
1507                    ptr::null_mut(),
1508                    CLSCTX_ALL,
1509                    &IID_ITaskbarList,
1510                    &mut task_bar_list as *mut _ as *mut _,
1511                )
1512            };
1513            if hr != S_OK {
1514                // In visual studio retrieving the taskbar list fails
1515                return;
1516            }
1517
1518            let hr_init = unsafe { (*(*task_bar_list).lpVtbl).HrInit };
1519            if unsafe { hr_init(task_bar_list.cast()) } != S_OK {
1520                // In some old windows, the taskbar object could not be created, we just ignore it
1521                return;
1522            }
1523            task_bar_list_ptr.set(task_bar_list)
1524        }
1525
1526        task_bar_list = task_bar_list_ptr.get();
1527        if skip {
1528            let delete_tab = unsafe { (*(*task_bar_list).lpVtbl).DeleteTab };
1529            unsafe { delete_tab(task_bar_list, hwnd) };
1530        } else {
1531            let add_tab = unsafe { (*(*task_bar_list).lpVtbl).AddTab };
1532            unsafe { add_tab(task_bar_list, hwnd) };
1533        }
1534    });
1535}
1536
1537unsafe fn force_window_active(handle: HWND) {
1538    // In some situation, calling SetForegroundWindow could not bring up the window,
1539    // This is a little hack which can "steal" the foreground window permission
1540    // We only call this function in the window creation, so it should be fine.
1541    // See : https://stackoverflow.com/questions/10740346/setforegroundwindow-only-working-while-visual-studio-is-open
1542    let alt_sc = unsafe { MapVirtualKeyW(VK_MENU as u32, MAPVK_VK_TO_VSC) };
1543
1544    let inputs = [
1545        INPUT {
1546            r#type: INPUT_KEYBOARD,
1547            Anonymous: INPUT_0 {
1548                ki: KEYBDINPUT {
1549                    wVk: VK_LMENU,
1550                    wScan: alt_sc as u16,
1551                    dwFlags: KEYEVENTF_EXTENDEDKEY,
1552                    dwExtraInfo: 0,
1553                    time: 0,
1554                },
1555            },
1556        },
1557        INPUT {
1558            r#type: INPUT_KEYBOARD,
1559            Anonymous: INPUT_0 {
1560                ki: KEYBDINPUT {
1561                    wVk: VK_LMENU,
1562                    wScan: alt_sc as u16,
1563                    dwFlags: KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP,
1564                    dwExtraInfo: 0,
1565                    time: 0,
1566                },
1567            },
1568        },
1569    ];
1570
1571    // Simulate a key press and release
1572    unsafe { SendInput(inputs.len() as u32, inputs.as_ptr(), mem::size_of::<INPUT>() as i32) };
1573
1574    unsafe { SetForegroundWindow(handle) };
1575}