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
76pub(crate) struct Window {
78 window: HWND,
80
81 window_state: Arc<Mutex<WindowState>>,
83
84 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 unsafe { init(w_attr, event_loop) }
98 }
99
100 pub(crate) fn maybe_queue_on_main(&self, f: impl FnOnce(&Self) + Send + 'static) {
101 f(self)
103 }
104
105 pub(crate) fn maybe_wait_on_main<R: Send>(&self, f: impl FnOnce(&Self) -> R + Send) -> R {
106 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 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 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 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 #[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 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 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 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 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 let h_menu = GetSystemMenu(self.hwnd(), 0);
569 if h_menu == 0 {
570 warn!("The corresponding window doesn't have a system menu");
571 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 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 SetMenuDefaultItem(h_menu, SC_CLOSE, 0);
599
600 let result = TrackPopupMenu(
602 h_menu,
603 TPM_RETURNCMD | TPM_LEFTALIGN, point.x,
606 point.y,
607 0,
608 self.hwnd(),
609 std::ptr::null_mut(),
610 );
611
612 if result == 0 {
613 return;
615 }
616
617 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 _ if old_fullscreen == fullscreen => return,
708 (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 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 let mut msg = mem::zeroed();
776 PeekMessageW(&mut msg, 0, 0, 0, PM_NOREMOVE);
777 }
778
779 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 unsafe {
797 taskbar_mark_fullscreen(window, fullscreen.is_some());
798 }
799
800 match &fullscreen {
802 Some(fullscreen) => {
803 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 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 PostMessageW(self.hwnd(), DESTROY_MSG_ID.get(), 0, 0);
1114 }
1115 }
1116}
1117
1118pub(super) struct InitData<'a> {
1119 pub event_loop: &'a ActiveEventLoop,
1121 pub attributes: WindowAttributes,
1122 pub window_flags: WindowFlags,
1123 pub window: Option<Window>,
1125}
1126
1127impl InitData<'_> {
1128 unsafe fn create_window(&self, window: HWND) -> Window {
1129 {
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 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 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 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 if self.attributes.transparent && !self.attributes.platform_specific.no_redirection_bitmap {
1233 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 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 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 window_flags.set(WindowFlags::RESIZABLE, attributes.resizable);
1328 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 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 let win = initdata.window.unwrap();
1395
1396 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, hbrBackground: 0,
1420 lpszMenuName: ptr::null(),
1421 lpszClassName: class_name.as_ptr(),
1422 hIconSm: 0,
1423 };
1424
1425 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
1455unsafe 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 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 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 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 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 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 unsafe { SendInput(inputs.len() as u32, inputs.as_ptr(), mem::size_of::<INPUT>() as i32) };
1573
1574 unsafe { SetForegroundWindow(handle) };
1575}