1#![allow(non_snake_case)]
2
3mod runner;
4
5use std::cell::Cell;
6use std::collections::VecDeque;
7use std::ffi::c_void;
8use std::marker::PhantomData;
9use std::os::windows::io::{AsRawHandle as _, FromRawHandle as _, OwnedHandle, RawHandle};
10use std::rc::Rc;
11use std::sync::atomic::{AtomicU32, Ordering};
12use std::sync::mpsc::{self, Receiver, Sender};
13use std::sync::{Arc, Mutex, MutexGuard};
14use std::time::{Duration, Instant};
15use std::{mem, panic, ptr};
16
17use crate::utils::Lazy;
18
19use windows_sys::Win32::Devices::HumanInterfaceDevice::MOUSE_MOVE_RELATIVE;
20use windows_sys::Win32::Foundation::{
21 GetLastError, FALSE, HANDLE, HWND, LPARAM, LRESULT, POINT, RECT, WAIT_FAILED, WPARAM,
22};
23use windows_sys::Win32::Graphics::Gdi::{
24 GetMonitorInfoW, MonitorFromRect, MonitorFromWindow, RedrawWindow, ScreenToClient,
25 ValidateRect, MONITORINFO, MONITOR_DEFAULTTONULL, RDW_INTERNALPAINT, SC_SCREENSAVE,
26};
27use windows_sys::Win32::System::Ole::RevokeDragDrop;
28use windows_sys::Win32::System::Threading::{
29 CreateWaitableTimerExW, GetCurrentThreadId, SetWaitableTimer,
30 CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, INFINITE, TIMER_ALL_ACCESS,
31};
32use windows_sys::Win32::UI::Controls::{HOVER_DEFAULT, WM_MOUSELEAVE};
33use windows_sys::Win32::UI::Input::Ime::{GCS_COMPSTR, GCS_RESULTSTR, ISC_SHOWUICOMPOSITIONWINDOW};
34use windows_sys::Win32::UI::Input::KeyboardAndMouse::{
35 ReleaseCapture, SetCapture, TrackMouseEvent, TME_LEAVE, TRACKMOUSEEVENT,
36};
37use windows_sys::Win32::UI::Input::Pointer::{
38 POINTER_FLAG_DOWN, POINTER_FLAG_UP, POINTER_FLAG_UPDATE,
39};
40use windows_sys::Win32::UI::Input::Touch::{
41 CloseTouchInputHandle, GetTouchInputInfo, TOUCHEVENTF_DOWN, TOUCHEVENTF_MOVE, TOUCHEVENTF_UP,
42 TOUCHINPUT,
43};
44use windows_sys::Win32::UI::Input::{RAWINPUT, RIM_TYPEKEYBOARD, RIM_TYPEMOUSE};
45use windows_sys::Win32::UI::WindowsAndMessaging::{
46 CreateWindowExW, DefWindowProcW, DestroyWindow, DispatchMessageW, GetClientRect, GetCursorPos,
47 GetMenu, LoadCursorW, MsgWaitForMultipleObjectsEx, PeekMessageW, PostMessageW,
48 RegisterClassExW, RegisterWindowMessageA, SetCursor, SetWindowPos, TranslateMessage,
49 CREATESTRUCTW, GIDC_ARRIVAL, GIDC_REMOVAL, GWL_STYLE, GWL_USERDATA, HTCAPTION, HTCLIENT,
50 MINMAXINFO, MNC_CLOSE, MSG, MWMO_INPUTAVAILABLE, NCCALCSIZE_PARAMS, PM_REMOVE, PT_PEN,
51 PT_TOUCH, QS_ALLINPUT, RI_MOUSE_HWHEEL, RI_MOUSE_WHEEL, SC_MINIMIZE, SC_RESTORE,
52 SIZE_MAXIMIZED, SWP_NOACTIVATE, SWP_NOMOVE, SWP_NOSIZE, SWP_NOZORDER, WHEEL_DELTA, WINDOWPOS,
53 WMSZ_BOTTOM, WMSZ_BOTTOMLEFT, WMSZ_BOTTOMRIGHT, WMSZ_LEFT, WMSZ_RIGHT, WMSZ_TOP, WMSZ_TOPLEFT,
54 WMSZ_TOPRIGHT, WM_CAPTURECHANGED, WM_CLOSE, WM_CREATE, WM_DESTROY, WM_DPICHANGED,
55 WM_ENTERSIZEMOVE, WM_EXITSIZEMOVE, WM_GETMINMAXINFO, WM_IME_COMPOSITION, WM_IME_ENDCOMPOSITION,
56 WM_IME_SETCONTEXT, WM_IME_STARTCOMPOSITION, WM_INPUT, WM_INPUT_DEVICE_CHANGE, WM_KEYDOWN,
57 WM_KEYUP, WM_KILLFOCUS, WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MBUTTONDOWN, WM_MBUTTONUP,
58 WM_MENUCHAR, WM_MOUSEHWHEEL, WM_MOUSEMOVE, WM_MOUSEWHEEL, WM_NCACTIVATE, WM_NCCALCSIZE,
59 WM_NCCREATE, WM_NCDESTROY, WM_NCLBUTTONDOWN, WM_PAINT, WM_POINTERDOWN, WM_POINTERUP,
60 WM_POINTERUPDATE, WM_RBUTTONDOWN, WM_RBUTTONUP, WM_SETCURSOR, WM_SETFOCUS, WM_SETTINGCHANGE,
61 WM_SIZE, WM_SIZING, WM_SYSCOMMAND, WM_SYSKEYDOWN, WM_SYSKEYUP, WM_TOUCH, WM_WINDOWPOSCHANGED,
62 WM_WINDOWPOSCHANGING, WM_XBUTTONDOWN, WM_XBUTTONUP, WNDCLASSEXW, WS_EX_LAYERED,
63 WS_EX_NOACTIVATE, WS_EX_TOOLWINDOW, WS_EX_TRANSPARENT, WS_OVERLAPPED, WS_POPUP, WS_VISIBLE,
64};
65
66use crate::dpi::{PhysicalPosition, PhysicalSize};
67use crate::error::EventLoopError;
68use crate::event::{
69 DeviceEvent, Event, Force, Ime, InnerSizeWriter, RawKeyEvent, Touch, TouchPhase, WindowEvent,
70};
71use crate::event_loop::{ActiveEventLoop as RootAEL, ControlFlow, DeviceEvents, EventLoopClosed};
72use crate::keyboard::ModifiersState;
73use crate::platform::pump_events::PumpStatus;
74use crate::platform_impl::platform::dark_mode::try_theme;
75use crate::platform_impl::platform::dpi::{become_dpi_aware, dpi_to_scale_factor};
76use crate::platform_impl::platform::drop_handler::FileDropHandler;
77use crate::platform_impl::platform::icon::WinCursor;
78use crate::platform_impl::platform::ime::ImeContext;
79use crate::platform_impl::platform::keyboard::KeyEventBuilder;
80use crate::platform_impl::platform::keyboard_layout::LAYOUT_CACHE;
81use crate::platform_impl::platform::monitor::{self, MonitorHandle};
82use crate::platform_impl::platform::window::InitData;
83use crate::platform_impl::platform::window_state::{
84 CursorFlags, ImeState, WindowFlags, WindowState,
85};
86use crate::platform_impl::platform::{
87 raw_input, util, wrap_device_id, Fullscreen, WindowId, DEVICE_ID,
88};
89use crate::window::{
90 CustomCursor as RootCustomCursor, CustomCursorSource, Theme, WindowId as RootWindowId,
91};
92use runner::{EventLoopRunner, EventLoopRunnerShared};
93
94use super::window::set_skip_taskbar;
95use super::SelectedCursor;
96
97pub(crate) struct UserEventPlaceholder;
110
111pub(crate) struct WindowData {
119 pub window_state: Arc<Mutex<WindowState>>,
120 pub event_loop_runner: EventLoopRunnerShared<UserEventPlaceholder>,
121 pub key_event_builder: KeyEventBuilder,
122 pub _file_drop_handler: Option<FileDropHandler>,
123 pub userdata_removed: Cell<bool>,
124 pub recurse_depth: Cell<u32>,
125}
126
127impl WindowData {
128 fn send_event(&self, event: Event<UserEventPlaceholder>) {
129 self.event_loop_runner.send_event(event);
130 }
131
132 fn window_state_lock(&self) -> MutexGuard<'_, WindowState> {
133 self.window_state.lock().unwrap()
134 }
135}
136
137struct ThreadMsgTargetData {
138 event_loop_runner: EventLoopRunnerShared<UserEventPlaceholder>,
139}
140
141impl ThreadMsgTargetData {
142 fn send_event(&self, event: Event<UserEventPlaceholder>) {
143 self.event_loop_runner.send_event(event);
144 }
145}
146
147#[derive(Clone, Copy)]
149pub(crate) enum ProcResult {
150 DefWindowProc(WPARAM),
151 Value(isize),
152}
153
154pub struct EventLoop<T: 'static> {
155 user_event_sender: Sender<T>,
156 user_event_receiver: Receiver<T>,
157 window_target: RootAEL,
158 msg_hook: Option<Box<dyn FnMut(*const c_void) -> bool + 'static>>,
159 high_resolution_timer: Option<OwnedHandle>,
163}
164
165pub(crate) struct PlatformSpecificEventLoopAttributes {
166 pub(crate) any_thread: bool,
167 pub(crate) dpi_aware: bool,
168 pub(crate) msg_hook: Option<Box<dyn FnMut(*const c_void) -> bool + 'static>>,
169}
170
171impl Default for PlatformSpecificEventLoopAttributes {
172 fn default() -> Self {
173 Self { any_thread: false, dpi_aware: true, msg_hook: None }
174 }
175}
176
177pub struct ActiveEventLoop {
178 thread_id: u32,
179 thread_msg_target: HWND,
180 pub(crate) runner_shared: EventLoopRunnerShared<UserEventPlaceholder>,
181}
182
183impl<T: 'static> EventLoop<T> {
184 pub(crate) fn new(
185 attributes: &mut PlatformSpecificEventLoopAttributes,
186 ) -> Result<Self, EventLoopError> {
187 let thread_id = unsafe { GetCurrentThreadId() };
188
189 if !attributes.any_thread && thread_id != main_thread_id() {
190 panic!(
191 "Initializing the event loop outside of the main thread is a significant \
192 cross-platform compatibility hazard. If you absolutely need to create an \
193 EventLoop on a different thread, you can use the \
194 `EventLoopBuilderExtWindows::any_thread` function."
195 );
196 }
197
198 if attributes.dpi_aware {
199 become_dpi_aware();
200 }
201
202 let thread_msg_target = create_event_target_window();
203
204 let runner_shared = Rc::new(EventLoopRunner::new(thread_msg_target));
205
206 let (user_event_sender, user_event_receiver) = mpsc::channel();
207 insert_event_target_window_data(thread_msg_target, runner_shared.clone());
208 raw_input::register_all_mice_and_keyboards_for_raw_input(
209 thread_msg_target,
210 Default::default(),
211 );
212
213 Ok(EventLoop {
214 user_event_sender,
215 user_event_receiver,
216 window_target: RootAEL {
217 p: ActiveEventLoop { thread_id, thread_msg_target, runner_shared },
218 _marker: PhantomData,
219 },
220 msg_hook: attributes.msg_hook.take(),
221 high_resolution_timer: None,
222 })
223 }
224
225 pub fn window_target(&self) -> &RootAEL {
226 &self.window_target
227 }
228
229 pub fn run<F>(mut self, event_handler: F) -> Result<(), EventLoopError>
230 where
231 F: FnMut(Event<T>, &RootAEL),
232 {
233 self.run_on_demand(event_handler)
234 }
235
236 pub fn run_on_demand<F>(&mut self, mut event_handler: F) -> Result<(), EventLoopError>
237 where
238 F: FnMut(Event<T>, &RootAEL),
239 {
240 {
241 let runner = &self.window_target.p.runner_shared;
242
243 let event_loop_windows_ref = &self.window_target;
244 let user_event_receiver = &self.user_event_receiver;
245 unsafe {
249 runner.set_event_handler(move |event| {
250 let event = match event.map_nonuser_event() {
257 Ok(non_user_event) => non_user_event,
258 Err(_user_event_placeholder) => Event::UserEvent(
259 user_event_receiver
260 .try_recv()
261 .expect("user event signaled but not received"),
262 ),
263 };
264 event_handler(event, event_loop_windows_ref)
265 });
266 }
267 }
268
269 let exit_code = loop {
270 self.wait_for_messages(None);
271 if let Some(code) = self.exit_code() {
274 break code;
275 }
276
277 self.dispatch_peeked_messages();
278
279 if let Some(code) = self.exit_code() {
280 break code;
281 }
282 };
283
284 let runner = &self.window_target.p.runner_shared;
285 runner.loop_destroyed();
286
287 runner.reset_runner();
291
292 if exit_code == 0 {
293 Ok(())
294 } else {
295 Err(EventLoopError::ExitFailure(exit_code))
296 }
297 }
298
299 pub fn pump_events<F>(&mut self, timeout: Option<Duration>, mut event_handler: F) -> PumpStatus
300 where
301 F: FnMut(Event<T>, &RootAEL),
302 {
303 {
304 let runner = &self.window_target.p.runner_shared;
305 let event_loop_windows_ref = &self.window_target;
306 let user_event_receiver = &self.user_event_receiver;
307
308 unsafe {
316 runner.set_event_handler(move |event| {
317 let event = match event.map_nonuser_event() {
318 Ok(non_user_event) => non_user_event,
319 Err(_user_event_placeholder) => Event::UserEvent(
320 user_event_receiver
321 .recv()
322 .expect("user event signaled but not received"),
323 ),
324 };
325 event_handler(event, event_loop_windows_ref)
326 });
327 runner.wakeup();
328 }
329 }
330
331 if self.exit_code().is_none() {
332 self.wait_for_messages(timeout);
333 }
334 if self.exit_code().is_none() {
337 self.dispatch_peeked_messages();
338 }
339
340 let runner = &self.window_target.p.runner_shared;
341
342 let status = if let Some(code) = runner.exit_code() {
343 runner.loop_destroyed();
344
345 runner.reset_runner();
348 PumpStatus::Exit(code)
349 } else {
350 runner.prepare_wait();
351 PumpStatus::Continue
352 };
353
354 runner.clear_event_handler();
361
362 status
363 }
364
365 fn wait_for_messages(&mut self, timeout: Option<Duration>) {
371 let runner = &self.window_target.p.runner_shared;
372
373 runner.prepare_wait();
383 wait_for_messages_impl(&mut self.high_resolution_timer, runner.control_flow(), timeout);
384 runner.wakeup();
386 }
387
388 fn dispatch_peeked_messages(&mut self) {
390 let runner = &self.window_target.p.runner_shared;
391
392 runner.interrupt_msg_dispatch.set(false);
398
399 let mut msg: MSG = unsafe { mem::zeroed() };
405
406 loop {
407 unsafe {
408 if PeekMessageW(&mut msg, 0, 0, 0, PM_REMOVE) == false.into() {
409 break;
410 }
411
412 let handled = if let Some(callback) = self.msg_hook.as_deref_mut() {
413 callback(&mut msg as *mut _ as *mut _)
414 } else {
415 false
416 };
417 if !handled {
418 TranslateMessage(&msg);
419 DispatchMessageW(&msg);
420 }
421 }
422
423 if let Err(payload) = runner.take_panic_error() {
424 runner.reset_runner();
425 panic::resume_unwind(payload);
426 }
427
428 if let Some(_code) = runner.exit_code() {
429 break;
430 }
431
432 if runner.interrupt_msg_dispatch.get() {
433 break;
434 }
435 }
436 }
437
438 pub fn create_proxy(&self) -> EventLoopProxy<T> {
439 EventLoopProxy {
440 target_window: self.window_target.p.thread_msg_target,
441 event_send: self.user_event_sender.clone(),
442 }
443 }
444
445 fn exit_code(&self) -> Option<i32> {
446 self.window_target.p.exit_code()
447 }
448}
449
450impl ActiveEventLoop {
451 #[inline(always)]
452 pub(crate) fn create_thread_executor(&self) -> EventLoopThreadExecutor {
453 EventLoopThreadExecutor { thread_id: self.thread_id, target_window: self.thread_msg_target }
454 }
455
456 pub fn create_custom_cursor(&self, source: CustomCursorSource) -> RootCustomCursor {
457 let inner = match WinCursor::new(&source.inner.0) {
458 Ok(cursor) => cursor,
459 Err(err) => {
460 tracing::warn!("Failed to create custom cursor: {err}");
461 WinCursor::Failed
462 },
463 };
464
465 RootCustomCursor { inner }
466 }
467
468 pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
470 monitor::available_monitors()
471 }
472
473 pub fn primary_monitor(&self) -> Option<MonitorHandle> {
474 let monitor = monitor::primary_monitor();
475 Some(monitor)
476 }
477
478 #[cfg(feature = "rwh_05")]
479 pub fn raw_display_handle_rwh_05(&self) -> rwh_05::RawDisplayHandle {
480 rwh_05::RawDisplayHandle::Windows(rwh_05::WindowsDisplayHandle::empty())
481 }
482
483 #[cfg(feature = "rwh_06")]
484 pub fn raw_display_handle_rwh_06(
485 &self,
486 ) -> Result<rwh_06::RawDisplayHandle, rwh_06::HandleError> {
487 Ok(rwh_06::RawDisplayHandle::Windows(rwh_06::WindowsDisplayHandle::new()))
488 }
489
490 pub fn listen_device_events(&self, allowed: DeviceEvents) {
491 raw_input::register_all_mice_and_keyboards_for_raw_input(self.thread_msg_target, allowed);
492 }
493
494 pub fn system_theme(&self) -> Option<Theme> {
495 Some(if super::dark_mode::should_use_dark_mode() { Theme::Dark } else { Theme::Light })
496 }
497
498 pub(crate) fn set_control_flow(&self, control_flow: ControlFlow) {
499 self.runner_shared.set_control_flow(control_flow)
500 }
501
502 pub(crate) fn control_flow(&self) -> ControlFlow {
503 self.runner_shared.control_flow()
504 }
505
506 pub(crate) fn exit(&self) {
507 self.runner_shared.set_exit_code(0)
508 }
509
510 pub(crate) fn exiting(&self) -> bool {
511 self.runner_shared.exit_code().is_some()
512 }
513
514 pub(crate) fn clear_exit(&self) {
515 self.runner_shared.clear_exit();
516 }
517
518 pub(crate) fn owned_display_handle(&self) -> OwnedDisplayHandle {
519 OwnedDisplayHandle
520 }
521
522 fn exit_code(&self) -> Option<i32> {
523 self.runner_shared.exit_code()
524 }
525}
526
527#[derive(Clone)]
528pub(crate) struct OwnedDisplayHandle;
529
530impl OwnedDisplayHandle {
531 #[cfg(feature = "rwh_05")]
532 #[inline]
533 pub fn raw_display_handle_rwh_05(&self) -> rwh_05::RawDisplayHandle {
534 rwh_05::WindowsDisplayHandle::empty().into()
535 }
536
537 #[cfg(feature = "rwh_06")]
538 #[inline]
539 pub fn raw_display_handle_rwh_06(
540 &self,
541 ) -> Result<rwh_06::RawDisplayHandle, rwh_06::HandleError> {
542 Ok(rwh_06::WindowsDisplayHandle::new().into())
543 }
544}
545
546fn main_thread_id() -> u32 {
565 static mut MAIN_THREAD_ID: u32 = 0;
566
567 #[used]
571 #[allow(non_upper_case_globals)]
572 #[link_section = ".CRT$XCU"]
577 static INIT_MAIN_THREAD_ID: unsafe extern "C" fn() = {
578 unsafe extern "C" fn initer() {
579 unsafe {
580 MAIN_THREAD_ID = GetCurrentThreadId();
581 }
582 }
583 initer
584 };
585
586 unsafe { MAIN_THREAD_ID }
587}
588
589fn min_timeout(a: Option<Duration>, b: Option<Duration>) -> Option<Duration> {
593 a.map_or(b, |a_timeout| b.map_or(Some(a_timeout), |b_timeout| Some(a_timeout.min(b_timeout))))
594}
595
596fn dur2timeout(dur: Duration) -> u32 {
598 dur.as_secs()
605 .checked_mul(1000)
606 .and_then(|ms| ms.checked_add((dur.subsec_nanos() as u64) / 1_000_000))
607 .and_then(
608 |ms| {
609 if dur.subsec_nanos() % 1_000_000 > 0 {
610 ms.checked_add(1)
611 } else {
612 Some(ms)
613 }
614 },
615 )
616 .map(|ms| if ms > u32::MAX as u64 { INFINITE } else { ms as u32 })
617 .unwrap_or(INFINITE)
618}
619
620impl<T> Drop for EventLoop<T> {
621 fn drop(&mut self) {
622 unsafe {
623 DestroyWindow(self.window_target.p.thread_msg_target);
624 }
625 }
626}
627
628const FIFTY_DAYS: Duration = Duration::from_secs(50_u64 * 24 * 60 * 60);
631const MIN_WAIT: Duration = Duration::from_nanos(100);
636
637fn create_high_resolution_timer() -> Option<OwnedHandle> {
638 unsafe {
639 let handle: HANDLE = CreateWaitableTimerExW(
640 ptr::null(),
641 ptr::null(),
642 CREATE_WAITABLE_TIMER_HIGH_RESOLUTION,
643 TIMER_ALL_ACCESS,
644 );
645 if handle == 0 {
649 None
650 } else {
651 Some(OwnedHandle::from_raw_handle(handle as *mut c_void))
652 }
653 }
654}
655
656unsafe fn set_high_resolution_timer(timer: RawHandle, timeout: Duration) -> Result<(), u32> {
665 const INTERVAL_NS: u32 = MIN_WAIT.subsec_nanos();
666 const INTERVALS_IN_SEC: u64 = (Duration::from_secs(1).as_nanos() / INTERVAL_NS as u128) as u64;
667 let intervals_to_wait: u64 =
668 timeout.as_secs() * INTERVALS_IN_SEC + u64::from(timeout.subsec_nanos() / INTERVAL_NS);
669 debug_assert!(intervals_to_wait < i64::MAX as u64, "Must be called with smaller duration",);
670 let due_time: i64 = -(intervals_to_wait as i64);
672 unsafe {
673 let set_result = SetWaitableTimer(timer as HANDLE, &due_time, 0, None, ptr::null(), FALSE);
674 if set_result != FALSE {
675 Ok(())
676 } else {
677 Err(GetLastError())
678 }
679 }
680}
681
682fn wait_for_messages_impl(
687 high_resolution_timer: &mut Option<OwnedHandle>,
688 control_flow: ControlFlow,
689 timeout: Option<Duration>,
690) {
691 let timeout = {
692 let control_flow_timeout = match control_flow {
693 ControlFlow::Wait => None,
694 ControlFlow::Poll => Some(Duration::ZERO),
695 ControlFlow::WaitUntil(wait_deadline) => {
696 let start = Instant::now();
697 Some(wait_deadline.saturating_duration_since(start))
698 },
699 };
700 let timeout = min_timeout(timeout, control_flow_timeout);
701 if timeout == Some(Duration::ZERO) {
702 return;
704 }
705 timeout
708 .map(|t| t.min(FIFTY_DAYS))
709 .map(|t| t.max(MIN_WAIT))
712 };
713
714 if timeout.is_some() && high_resolution_timer.is_none() {
715 *high_resolution_timer = create_high_resolution_timer();
716 }
717
718 let high_resolution_timer: Option<RawHandle> =
719 high_resolution_timer.as_ref().map(OwnedHandle::as_raw_handle);
720
721 let use_timer: bool;
722 if let (Some(handle), Some(timeout)) = (high_resolution_timer, timeout) {
723 let res = unsafe {
724 set_high_resolution_timer(handle, timeout)
728 };
729 if let Err(error_code) = res {
730 tracing::trace!("Failed to set high resolution timer: last error {}", error_code);
733 use_timer = false;
734 } else {
735 use_timer = true;
736 }
737 } else {
738 use_timer = false;
739 }
740
741 unsafe {
742 let wait_duration_ms = timeout.map(dur2timeout).unwrap_or(INFINITE);
746
747 let (num_handles, raw_handles) =
748 if use_timer { (1, [high_resolution_timer.unwrap()]) } else { (0, [ptr::null_mut()]) };
749
750 let result = MsgWaitForMultipleObjectsEx(
752 num_handles,
753 raw_handles.as_ptr() as *const _,
754 wait_duration_ms,
755 QS_ALLINPUT,
756 MWMO_INPUTAVAILABLE,
757 );
758 if result == WAIT_FAILED {
759 tracing::warn!("Failed to MsgWaitForMultipleObjectsEx: error code {}", GetLastError(),);
762 }
763 }
764}
765
766pub(crate) struct EventLoopThreadExecutor {
767 thread_id: u32,
768 target_window: HWND,
769}
770
771unsafe impl Send for EventLoopThreadExecutor {}
772unsafe impl Sync for EventLoopThreadExecutor {}
773
774impl EventLoopThreadExecutor {
775 pub(super) fn in_event_loop_thread(&self) -> bool {
777 let cur_thread_id = unsafe { GetCurrentThreadId() };
778 self.thread_id == cur_thread_id
779 }
780
781 pub(super) fn execute_in_thread<F>(&self, mut function: F)
795 where
796 F: FnMut() + Send + 'static,
797 {
798 unsafe {
799 if self.in_event_loop_thread() {
800 function();
801 } else {
802 let boxed2: ThreadExecFn = Box::new(Box::new(function));
804
805 let raw = Box::into_raw(boxed2);
806
807 let res = PostMessageW(self.target_window, EXEC_MSG_ID.get(), raw as usize, 0);
808 assert!(res != false.into(), "PostMessage failed; is the messages queue full?");
809 }
810 }
811 }
812}
813
814type ThreadExecFn = Box<Box<dyn FnMut()>>;
815
816pub struct EventLoopProxy<T: 'static> {
817 target_window: HWND,
818 event_send: Sender<T>,
819}
820unsafe impl<T: Send + 'static> Send for EventLoopProxy<T> {}
821
822impl<T: 'static> Clone for EventLoopProxy<T> {
823 fn clone(&self) -> Self {
824 Self { target_window: self.target_window, event_send: self.event_send.clone() }
825 }
826}
827
828impl<T: 'static> EventLoopProxy<T> {
829 pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
830 self.event_send
831 .send(event)
832 .map(|result| {
833 unsafe { PostMessageW(self.target_window, USER_EVENT_MSG_ID.get(), 0, 0) };
834 result
835 })
836 .map_err(|e| EventLoopClosed(e.0))
837 }
838}
839
840pub struct LazyMessageId {
842 id: AtomicU32,
844
845 name: &'static str,
847}
848
849const INVALID_ID: u32 = 0x0;
851
852impl LazyMessageId {
853 const fn new(name: &'static str) -> Self {
855 Self { id: AtomicU32::new(INVALID_ID), name }
856 }
857
858 pub fn get(&self) -> u32 {
860 let id = self.id.load(Ordering::Relaxed);
862
863 if id != INVALID_ID {
864 return id;
865 }
866
867 assert!(self.name.ends_with('\0'));
870 let new_id = unsafe { RegisterWindowMessageA(self.name.as_ptr()) };
871
872 assert_ne!(
873 new_id,
874 0,
875 "RegisterWindowMessageA returned zero for '{}': {}",
876 self.name,
877 std::io::Error::last_os_error()
878 );
879
880 self.id.store(new_id, Ordering::Relaxed);
885
886 new_id
887 }
888}
889
890static USER_EVENT_MSG_ID: LazyMessageId = LazyMessageId::new("Winit::WakeupMsg\0");
893static EXEC_MSG_ID: LazyMessageId = LazyMessageId::new("Winit::ExecMsg\0");
897pub(crate) static DESTROY_MSG_ID: LazyMessageId = LazyMessageId::new("Winit::DestroyMsg\0");
900pub(crate) static SET_RETAIN_STATE_ON_SIZE_MSG_ID: LazyMessageId =
903 LazyMessageId::new("Winit::SetRetainMaximized\0");
904static THREAD_EVENT_TARGET_WINDOW_CLASS: Lazy<Vec<u16>> =
905 Lazy::new(|| util::encode_wide("Winit Thread Event Target"));
906pub(crate) static TASKBAR_CREATED: LazyMessageId = LazyMessageId::new("TaskbarCreated\0");
909
910fn create_event_target_window() -> HWND {
911 use windows_sys::Win32::UI::WindowsAndMessaging::{CS_HREDRAW, CS_VREDRAW};
912 unsafe {
913 let class = WNDCLASSEXW {
914 cbSize: mem::size_of::<WNDCLASSEXW>() as u32,
915 style: CS_HREDRAW | CS_VREDRAW,
916 lpfnWndProc: Some(thread_event_target_callback),
917 cbClsExtra: 0,
918 cbWndExtra: 0,
919 hInstance: util::get_instance_handle(),
920 hIcon: 0,
921 hCursor: 0, hbrBackground: 0,
923 lpszMenuName: ptr::null(),
924 lpszClassName: THREAD_EVENT_TARGET_WINDOW_CLASS.as_ptr(),
925 hIconSm: 0,
926 };
927
928 RegisterClassExW(&class);
929 }
930
931 unsafe {
932 let window = CreateWindowExW(
940 WS_EX_NOACTIVATE | WS_EX_TRANSPARENT | WS_EX_LAYERED | WS_EX_TOOLWINDOW,
941 THREAD_EVENT_TARGET_WINDOW_CLASS.as_ptr(),
942 ptr::null(),
943 WS_OVERLAPPED,
944 0,
945 0,
946 0,
947 0,
948 0,
949 0,
950 util::get_instance_handle(),
951 ptr::null(),
952 );
953
954 super::set_window_long(
955 window,
956 GWL_STYLE,
957 (WS_VISIBLE | WS_POPUP) as isize,
961 );
962 window
963 }
964}
965
966fn insert_event_target_window_data(
967 thread_msg_target: HWND,
968 event_loop_runner: EventLoopRunnerShared<UserEventPlaceholder>,
969) {
970 let userdata = ThreadMsgTargetData { event_loop_runner };
971 let input_ptr = Box::into_raw(Box::new(userdata));
972
973 unsafe { super::set_window_long(thread_msg_target, GWL_USERDATA, input_ptr as isize) };
974}
975
976unsafe fn capture_mouse(window: HWND, window_state: &mut WindowState) {
979 window_state.mouse.capture_count += 1;
980 unsafe { SetCapture(window) };
981}
982
983unsafe fn release_mouse(mut window_state: MutexGuard<'_, WindowState>) {
986 window_state.mouse.capture_count = window_state.mouse.capture_count.saturating_sub(1);
987 if window_state.mouse.capture_count == 0 {
988 drop(window_state);
990 unsafe { ReleaseCapture() };
991 }
992}
993
994fn normalize_pointer_pressure(pressure: u32) -> Option<Force> {
995 match pressure {
996 1..=1024 => Some(Force::Normalized(pressure as f64 / 1024.0)),
997 _ => None,
998 }
999}
1000
1001fn update_modifiers(window: HWND, userdata: &WindowData) {
1004 use crate::event::WindowEvent::ModifiersChanged;
1005
1006 let modifiers = {
1007 let mut layouts = LAYOUT_CACHE.lock().unwrap();
1008 layouts.get_agnostic_mods()
1009 };
1010
1011 let mut window_state = userdata.window_state.lock().unwrap();
1012 if window_state.modifiers_state != modifiers {
1013 window_state.modifiers_state = modifiers;
1014
1015 drop(window_state);
1017
1018 userdata.send_event(Event::WindowEvent {
1019 window_id: RootWindowId(WindowId(window)),
1020 event: ModifiersChanged(modifiers.into()),
1021 });
1022 }
1023}
1024
1025unsafe fn gain_active_focus(window: HWND, userdata: &WindowData) {
1026 use crate::event::WindowEvent::Focused;
1027
1028 update_modifiers(window, userdata);
1029
1030 userdata.send_event(Event::WindowEvent {
1031 window_id: RootWindowId(WindowId(window)),
1032 event: Focused(true),
1033 });
1034}
1035
1036unsafe fn lose_active_focus(window: HWND, userdata: &WindowData) {
1037 use crate::event::WindowEvent::{Focused, ModifiersChanged};
1038
1039 userdata.window_state_lock().modifiers_state = ModifiersState::empty();
1040 userdata.send_event(Event::WindowEvent {
1041 window_id: RootWindowId(WindowId(window)),
1042 event: ModifiersChanged(ModifiersState::empty().into()),
1043 });
1044
1045 userdata.send_event(Event::WindowEvent {
1046 window_id: RootWindowId(WindowId(window)),
1047 event: Focused(false),
1048 });
1049}
1050
1051pub(super) unsafe extern "system" fn public_window_callback(
1058 window: HWND,
1059 msg: u32,
1060 wparam: WPARAM,
1061 lparam: LPARAM,
1062) -> LRESULT {
1063 let userdata = unsafe { super::get_window_long(window, GWL_USERDATA) };
1064
1065 let userdata_ptr = match (userdata, msg) {
1066 (0, WM_NCCREATE) => {
1067 let createstruct = unsafe { &mut *(lparam as *mut CREATESTRUCTW) };
1068 let initdata = unsafe { &mut *(createstruct.lpCreateParams as *mut InitData<'_>) };
1069
1070 let result = match unsafe { initdata.on_nccreate(window) } {
1071 Some(userdata) => unsafe {
1072 super::set_window_long(window, GWL_USERDATA, userdata as _);
1073 DefWindowProcW(window, msg, wparam, lparam)
1074 },
1075 None => -1, };
1077
1078 return result;
1079 },
1080 (0, WM_CREATE) => return -1,
1083 (_, WM_CREATE) => unsafe {
1084 let createstruct = &mut *(lparam as *mut CREATESTRUCTW);
1085 let initdata = createstruct.lpCreateParams;
1086 let initdata = &mut *(initdata as *mut InitData<'_>);
1087
1088 initdata.on_create();
1089 return DefWindowProcW(window, msg, wparam, lparam);
1090 },
1091 (0, _) => return unsafe { DefWindowProcW(window, msg, wparam, lparam) },
1092 _ => userdata as *mut WindowData,
1093 };
1094
1095 let (result, userdata_removed, recurse_depth) = {
1096 let userdata = unsafe { &*(userdata_ptr) };
1097
1098 userdata.recurse_depth.set(userdata.recurse_depth.get() + 1);
1099
1100 let result = unsafe { public_window_callback_inner(window, msg, wparam, lparam, userdata) };
1101
1102 let userdata_removed = userdata.userdata_removed.get();
1103 let recurse_depth = userdata.recurse_depth.get() - 1;
1104 userdata.recurse_depth.set(recurse_depth);
1105
1106 (result, userdata_removed, recurse_depth)
1107 };
1108
1109 if userdata_removed && recurse_depth == 0 {
1110 drop(unsafe { Box::from_raw(userdata_ptr) });
1111 }
1112
1113 result
1114}
1115
1116unsafe fn public_window_callback_inner(
1117 window: HWND,
1118 msg: u32,
1119 wparam: WPARAM,
1120 lparam: LPARAM,
1121 userdata: &WindowData,
1122) -> LRESULT {
1123 let mut result = ProcResult::DefWindowProc(wparam);
1124
1125 let mods_changed_callback = || match msg {
1127 WM_KEYDOWN | WM_SYSKEYDOWN | WM_KEYUP | WM_SYSKEYUP => {
1128 update_modifiers(window, userdata);
1129 result = ProcResult::Value(0);
1130 },
1131 _ => (),
1132 };
1133 userdata
1134 .event_loop_runner
1135 .catch_unwind(mods_changed_callback)
1136 .unwrap_or_else(|| result = ProcResult::Value(-1));
1137
1138 let keyboard_callback = || {
1139 use crate::event::WindowEvent::KeyboardInput;
1140 let events =
1141 userdata.key_event_builder.process_message(window, msg, wparam, lparam, &mut result);
1142 for event in events {
1143 userdata.send_event(Event::WindowEvent {
1144 window_id: RootWindowId(WindowId(window)),
1145 event: KeyboardInput {
1146 device_id: DEVICE_ID,
1147 event: event.event,
1148 is_synthetic: event.is_synthetic,
1149 },
1150 });
1151 }
1152 };
1153 userdata
1154 .event_loop_runner
1155 .catch_unwind(keyboard_callback)
1156 .unwrap_or_else(|| result = ProcResult::Value(-1));
1157
1158 let callback = || match msg {
1162 WM_NCCALCSIZE => {
1163 let window_flags = userdata.window_state_lock().window_flags;
1164 if wparam == 0 || window_flags.contains(WindowFlags::MARKER_DECORATIONS) {
1165 result = ProcResult::DefWindowProc(wparam);
1166 return;
1167 }
1168
1169 let params = unsafe { &mut *(lparam as *mut NCCALCSIZE_PARAMS) };
1170
1171 if util::is_maximized(window) {
1172 let monitor = unsafe { MonitorFromRect(¶ms.rgrc[0], MONITOR_DEFAULTTONULL) };
1179 if let Ok(monitor_info) = monitor::get_monitor_info(monitor) {
1180 params.rgrc[0] = monitor_info.monitorInfo.rcWork;
1181 }
1182 } else if window_flags.contains(WindowFlags::MARKER_UNDECORATED_SHADOW) {
1183 params.rgrc[0].top += 1;
1195 params.rgrc[0].bottom += 1;
1196 }
1197
1198 result = ProcResult::Value(0);
1199 },
1200
1201 WM_ENTERSIZEMOVE => {
1202 userdata
1203 .window_state_lock()
1204 .set_window_flags_in_place(|f| f.insert(WindowFlags::MARKER_IN_SIZE_MOVE));
1205 result = ProcResult::Value(0);
1206 },
1207
1208 WM_EXITSIZEMOVE => {
1209 let mut state = userdata.window_state_lock();
1210 if state.dragging {
1211 state.dragging = false;
1212 unsafe { PostMessageW(window, WM_LBUTTONUP, 0, lparam) };
1213 }
1214
1215 state.set_window_flags_in_place(|f| f.remove(WindowFlags::MARKER_IN_SIZE_MOVE));
1216 result = ProcResult::Value(0);
1217 },
1218
1219 WM_NCLBUTTONDOWN => {
1220 if wparam == HTCAPTION as _ {
1221 let lparam = 0;
1246 unsafe { PostMessageW(window, WM_MOUSEMOVE, 0, lparam) };
1247 }
1248 result = ProcResult::DefWindowProc(wparam);
1249 },
1250
1251 WM_CLOSE => {
1252 use crate::event::WindowEvent::CloseRequested;
1253 userdata.send_event(Event::WindowEvent {
1254 window_id: RootWindowId(WindowId(window)),
1255 event: CloseRequested,
1256 });
1257 result = ProcResult::Value(0);
1258 },
1259
1260 WM_DESTROY => {
1261 use crate::event::WindowEvent::Destroyed;
1262 unsafe { RevokeDragDrop(window) };
1263 userdata.send_event(Event::WindowEvent {
1264 window_id: RootWindowId(WindowId(window)),
1265 event: Destroyed,
1266 });
1267 result = ProcResult::Value(0);
1268 },
1269
1270 WM_NCDESTROY => {
1271 unsafe { super::set_window_long(window, GWL_USERDATA, 0) };
1272 userdata.userdata_removed.set(true);
1273 result = ProcResult::Value(0);
1274 },
1275
1276 WM_PAINT => {
1277 userdata.window_state_lock().redraw_requested =
1278 userdata.event_loop_runner.should_buffer();
1279
1280 if !userdata.event_loop_runner.should_buffer() {
1284 userdata.send_event(Event::WindowEvent {
1285 window_id: RootWindowId(WindowId(window)),
1286 event: WindowEvent::RedrawRequested,
1287 });
1288 }
1289
1290 result = ProcResult::Value(unsafe { DefWindowProcW(window, msg, wparam, lparam) });
1295 if std::mem::take(&mut userdata.window_state_lock().redraw_requested) {
1296 unsafe { RedrawWindow(window, ptr::null(), 0, RDW_INTERNALPAINT) };
1297 }
1298 },
1299 WM_WINDOWPOSCHANGING => {
1300 let mut window_state = userdata.window_state_lock();
1301 if let Some(ref mut fullscreen) = window_state.fullscreen {
1302 let window_pos = unsafe { &mut *(lparam as *mut WINDOWPOS) };
1303 let new_rect = RECT {
1304 left: window_pos.x,
1305 top: window_pos.y,
1306 right: window_pos.x + window_pos.cx,
1307 bottom: window_pos.y + window_pos.cy,
1308 };
1309
1310 const NOMOVE_OR_NOSIZE: u32 = SWP_NOMOVE | SWP_NOSIZE;
1311
1312 let new_rect = if window_pos.flags & NOMOVE_OR_NOSIZE != 0 {
1313 let cur_rect = util::WindowArea::Outer.get_rect(window).expect(
1314 "Unexpected GetWindowRect failure; please report this error to \
1315 rust-windowing/winit",
1316 );
1317
1318 match window_pos.flags & NOMOVE_OR_NOSIZE {
1319 NOMOVE_OR_NOSIZE => None,
1320
1321 SWP_NOMOVE => Some(RECT {
1322 left: cur_rect.left,
1323 top: cur_rect.top,
1324 right: cur_rect.left + window_pos.cx,
1325 bottom: cur_rect.top + window_pos.cy,
1326 }),
1327
1328 SWP_NOSIZE => Some(RECT {
1329 left: window_pos.x,
1330 top: window_pos.y,
1331 right: window_pos.x - cur_rect.left + cur_rect.right,
1332 bottom: window_pos.y - cur_rect.top + cur_rect.bottom,
1333 }),
1334
1335 _ => unreachable!(),
1336 }
1337 } else {
1338 Some(new_rect)
1339 };
1340
1341 if let Some(new_rect) = new_rect {
1342 let new_monitor = unsafe { MonitorFromRect(&new_rect, MONITOR_DEFAULTTONULL) };
1343 match fullscreen {
1344 Fullscreen::Borderless(ref mut fullscreen_monitor) => {
1345 if new_monitor != 0
1346 && fullscreen_monitor
1347 .as_ref()
1348 .map(|monitor| new_monitor != monitor.hmonitor())
1349 .unwrap_or(true)
1350 {
1351 if let Ok(new_monitor_info) = monitor::get_monitor_info(new_monitor)
1352 {
1353 let new_monitor_rect = new_monitor_info.monitorInfo.rcMonitor;
1354 window_pos.x = new_monitor_rect.left;
1355 window_pos.y = new_monitor_rect.top;
1356 window_pos.cx = new_monitor_rect.right - new_monitor_rect.left;
1357 window_pos.cy = new_monitor_rect.bottom - new_monitor_rect.top;
1358 }
1359 *fullscreen_monitor = Some(MonitorHandle::new(new_monitor));
1360 }
1361 },
1362 Fullscreen::Exclusive(ref video_mode) => {
1363 let old_monitor = video_mode.monitor.hmonitor();
1364 if let Ok(old_monitor_info) = monitor::get_monitor_info(old_monitor) {
1365 let old_monitor_rect = old_monitor_info.monitorInfo.rcMonitor;
1366 window_pos.x = old_monitor_rect.left;
1367 window_pos.y = old_monitor_rect.top;
1368 window_pos.cx = old_monitor_rect.right - old_monitor_rect.left;
1369 window_pos.cy = old_monitor_rect.bottom - old_monitor_rect.top;
1370 }
1371 },
1372 }
1373 }
1374 }
1375
1376 result = ProcResult::Value(0);
1377 },
1378
1379 WM_WINDOWPOSCHANGED => {
1381 use crate::event::WindowEvent::Moved;
1382
1383 let windowpos = lparam as *const WINDOWPOS;
1384 if unsafe { (*windowpos).flags & SWP_NOMOVE != SWP_NOMOVE } {
1385 let physical_position =
1386 unsafe { PhysicalPosition::new((*windowpos).x, (*windowpos).y) };
1387 userdata.send_event(Event::WindowEvent {
1388 window_id: RootWindowId(WindowId(window)),
1389 event: Moved(physical_position),
1390 });
1391 }
1392
1393 result = ProcResult::DefWindowProc(wparam);
1395 },
1396
1397 WM_SIZE => {
1398 use crate::event::WindowEvent::Resized;
1399 let w = super::loword(lparam as u32) as u32;
1400 let h = super::hiword(lparam as u32) as u32;
1401
1402 let physical_size = PhysicalSize::new(w, h);
1403 let event = Event::WindowEvent {
1404 window_id: RootWindowId(WindowId(window)),
1405 event: Resized(physical_size),
1406 };
1407
1408 {
1409 let mut w = userdata.window_state_lock();
1410 if !w.window_flags().contains(WindowFlags::MARKER_RETAIN_STATE_ON_SIZE) {
1413 let maximized = wparam == SIZE_MAXIMIZED as usize;
1414 w.set_window_flags_in_place(|f| f.set(WindowFlags::MAXIMIZED, maximized));
1415 }
1416 }
1417 userdata.send_event(event);
1418 result = ProcResult::Value(0);
1419 },
1420
1421 WM_SIZING => {
1422 fn snap_to_nearest_increment_delta(value: i32, increment: i32) -> i32 {
1424 let half_one = increment / 2;
1425 let half_two = increment - half_one;
1426 half_one - (value - half_two) % increment
1427 }
1428
1429 let scale_factor = userdata.window_state_lock().scale_factor;
1430 let Some(inc) = userdata
1431 .window_state_lock()
1432 .resize_increments
1433 .map(|inc| inc.to_physical(scale_factor))
1434 .filter(|inc| inc.width > 0 && inc.height > 0)
1435 else {
1436 result = ProcResult::Value(0);
1437 return;
1438 };
1439
1440 let side = wparam as u32;
1441 let rect = unsafe { &mut *(lparam as *mut RECT) };
1443
1444 let adj_rect = userdata
1447 .window_state_lock()
1448 .window_flags
1449 .adjust_rect(window, *rect)
1450 .unwrap_or(*rect);
1451 let deco_width = rect.left - adj_rect.left + adj_rect.right - rect.right;
1452 let deco_height = rect.top - adj_rect.top + adj_rect.bottom - rect.bottom;
1453
1454 let width = rect.right - rect.left - deco_width;
1455 let height = rect.bottom - rect.top - deco_height;
1456
1457 let mut width_delta = snap_to_nearest_increment_delta(width, inc.width);
1458 let mut height_delta = snap_to_nearest_increment_delta(height, inc.height);
1459
1460 let min_size =
1464 userdata.window_state_lock().min_size.map(|size| size.to_physical(scale_factor));
1465 let max_size =
1466 userdata.window_state_lock().max_size.map(|size| size.to_physical(scale_factor));
1467 let final_width = width + width_delta;
1468 let final_height = height + height_delta;
1469 if let Some(min_size) = min_size {
1470 if final_width < min_size.width {
1471 width_delta += min_size.width - final_width;
1472 }
1473 if final_height < min_size.height {
1474 height_delta += min_size.height - final_height;
1475 }
1476 }
1477 if let Some(max_size) = max_size {
1478 if final_width > max_size.width {
1479 width_delta -= final_width - max_size.width;
1480 }
1481 if final_height > max_size.height {
1482 height_delta -= final_height - max_size.height;
1483 }
1484 }
1485
1486 match side {
1487 WMSZ_LEFT | WMSZ_BOTTOMLEFT | WMSZ_TOPLEFT => {
1488 rect.left -= width_delta;
1489 },
1490 WMSZ_RIGHT | WMSZ_BOTTOMRIGHT | WMSZ_TOPRIGHT => {
1491 rect.right += width_delta;
1492 },
1493 _ => {},
1494 }
1495
1496 match side {
1497 WMSZ_TOP | WMSZ_TOPLEFT | WMSZ_TOPRIGHT => {
1498 rect.top -= height_delta;
1499 },
1500 WMSZ_BOTTOM | WMSZ_BOTTOMLEFT | WMSZ_BOTTOMRIGHT => {
1501 rect.bottom += height_delta;
1502 },
1503 _ => {},
1504 }
1505
1506 result = ProcResult::DefWindowProc(wparam);
1507 },
1508
1509 WM_MENUCHAR => {
1510 result = ProcResult::Value((MNC_CLOSE << 16) as isize);
1511 },
1512
1513 WM_IME_STARTCOMPOSITION => {
1514 let ime_allowed = userdata.window_state_lock().ime_allowed;
1515 if ime_allowed {
1516 userdata.window_state_lock().ime_state = ImeState::Enabled;
1517
1518 userdata.send_event(Event::WindowEvent {
1519 window_id: RootWindowId(WindowId(window)),
1520 event: WindowEvent::Ime(Ime::Enabled),
1521 });
1522 }
1523
1524 result = ProcResult::DefWindowProc(wparam);
1525 },
1526
1527 WM_IME_COMPOSITION => {
1528 let ime_allowed_and_composing = {
1529 let w = userdata.window_state_lock();
1530 w.ime_allowed && w.ime_state != ImeState::Disabled
1531 };
1532 if ime_allowed_and_composing {
1535 let ime_context = unsafe { ImeContext::current(window) };
1536
1537 if lparam == 0 {
1538 userdata.send_event(Event::WindowEvent {
1539 window_id: RootWindowId(WindowId(window)),
1540 event: WindowEvent::Ime(Ime::Preedit(String::new(), None)),
1541 });
1542 }
1543
1544 if (lparam as u32 & GCS_RESULTSTR) != 0 {
1547 if let Some(text) = unsafe { ime_context.get_composed_text() } {
1548 userdata.window_state_lock().ime_state = ImeState::Enabled;
1549
1550 userdata.send_event(Event::WindowEvent {
1551 window_id: RootWindowId(WindowId(window)),
1552 event: WindowEvent::Ime(Ime::Preedit(String::new(), None)),
1553 });
1554 userdata.send_event(Event::WindowEvent {
1555 window_id: RootWindowId(WindowId(window)),
1556 event: WindowEvent::Ime(Ime::Commit(text)),
1557 });
1558 }
1559 }
1560
1561 if (lparam as u32 & GCS_COMPSTR) != 0 {
1563 if let Some((text, first, last)) =
1564 unsafe { ime_context.get_composing_text_and_cursor() }
1565 {
1566 userdata.window_state_lock().ime_state = ImeState::Preedit;
1567 let cursor_range = first.map(|f| (f, last.unwrap_or(f)));
1568
1569 userdata.send_event(Event::WindowEvent {
1570 window_id: RootWindowId(WindowId(window)),
1571 event: WindowEvent::Ime(Ime::Preedit(text, cursor_range)),
1572 });
1573 }
1574 }
1575 }
1576
1577 result = ProcResult::Value(0);
1579 },
1580
1581 WM_IME_ENDCOMPOSITION => {
1582 let ime_allowed_or_composing = {
1583 let w = userdata.window_state_lock();
1584 w.ime_allowed || w.ime_state != ImeState::Disabled
1585 };
1586 if ime_allowed_or_composing {
1587 if userdata.window_state_lock().ime_state == ImeState::Preedit {
1588 let ime_context = unsafe { ImeContext::current(window) };
1591 if let Some(text) = unsafe { ime_context.get_composed_text() } {
1592 userdata.send_event(Event::WindowEvent {
1593 window_id: RootWindowId(WindowId(window)),
1594 event: WindowEvent::Ime(Ime::Preedit(String::new(), None)),
1595 });
1596 userdata.send_event(Event::WindowEvent {
1597 window_id: RootWindowId(WindowId(window)),
1598 event: WindowEvent::Ime(Ime::Commit(text)),
1599 });
1600 }
1601 }
1602
1603 userdata.window_state_lock().ime_state = ImeState::Disabled;
1604
1605 userdata.send_event(Event::WindowEvent {
1606 window_id: RootWindowId(WindowId(window)),
1607 event: WindowEvent::Ime(Ime::Disabled),
1608 });
1609 }
1610
1611 result = ProcResult::DefWindowProc(wparam);
1612 },
1613
1614 WM_IME_SETCONTEXT => {
1615 let lparam = lparam & !(ISC_SHOWUICOMPOSITIONWINDOW as isize);
1617 result = ProcResult::Value(unsafe { DefWindowProcW(window, msg, wparam, lparam) });
1618 },
1619
1620 WM_SYSCOMMAND => {
1622 if wparam == SC_RESTORE as usize {
1623 let mut w = userdata.window_state_lock();
1624 w.set_window_flags_in_place(|f| f.set(WindowFlags::MINIMIZED, false));
1625 }
1626 if wparam == SC_MINIMIZE as usize {
1627 let mut w = userdata.window_state_lock();
1628 w.set_window_flags_in_place(|f| f.set(WindowFlags::MINIMIZED, true));
1629 }
1630 if wparam == SC_SCREENSAVE as usize {
1633 let window_state = userdata.window_state_lock();
1634 if window_state.fullscreen.is_some() {
1635 result = ProcResult::Value(0);
1636 return;
1637 }
1638 }
1639
1640 result = ProcResult::DefWindowProc(wparam);
1641 },
1642
1643 WM_MOUSEMOVE => {
1644 use crate::event::WindowEvent::{CursorEntered, CursorLeft, CursorMoved};
1645
1646 let x = super::get_x_lparam(lparam as u32) as i32;
1647 let y = super::get_y_lparam(lparam as u32) as i32;
1648 let position = PhysicalPosition::new(x as f64, y as f64);
1649
1650 let cursor_moved;
1651 {
1652 let mut w = userdata.window_state_lock();
1653 let mouse_was_inside_window =
1654 w.mouse.cursor_flags().contains(CursorFlags::IN_WINDOW);
1655
1656 match get_pointer_move_kind(window, mouse_was_inside_window, x, y) {
1657 PointerMoveKind::Enter => {
1658 w.mouse
1659 .set_cursor_flags(window, |f| f.set(CursorFlags::IN_WINDOW, true))
1660 .ok();
1661
1662 drop(w);
1663 userdata.send_event(Event::WindowEvent {
1664 window_id: RootWindowId(WindowId(window)),
1665 event: CursorEntered { device_id: DEVICE_ID },
1666 });
1667
1668 unsafe {
1670 TrackMouseEvent(&mut TRACKMOUSEEVENT {
1671 cbSize: mem::size_of::<TRACKMOUSEEVENT>() as u32,
1672 dwFlags: TME_LEAVE,
1673 hwndTrack: window,
1674 dwHoverTime: HOVER_DEFAULT,
1675 })
1676 };
1677 },
1678 PointerMoveKind::Leave => {
1679 w.mouse
1680 .set_cursor_flags(window, |f| f.set(CursorFlags::IN_WINDOW, false))
1681 .ok();
1682
1683 drop(w);
1684 userdata.send_event(Event::WindowEvent {
1685 window_id: RootWindowId(WindowId(window)),
1686 event: CursorLeft { device_id: DEVICE_ID },
1687 });
1688 },
1689 PointerMoveKind::None => drop(w),
1690 }
1691
1692 let mut w = userdata.window_state_lock();
1696 cursor_moved = w.mouse.last_position != Some(position);
1697 w.mouse.last_position = Some(position);
1698 }
1699
1700 if cursor_moved {
1701 update_modifiers(window, userdata);
1702
1703 userdata.send_event(Event::WindowEvent {
1704 window_id: RootWindowId(WindowId(window)),
1705 event: CursorMoved { device_id: DEVICE_ID, position },
1706 });
1707 }
1708
1709 result = ProcResult::Value(0);
1710 },
1711
1712 WM_MOUSELEAVE => {
1713 use crate::event::WindowEvent::CursorLeft;
1714 {
1715 let mut w = userdata.window_state_lock();
1716 w.mouse.set_cursor_flags(window, |f| f.set(CursorFlags::IN_WINDOW, false)).ok();
1717 }
1718
1719 userdata.send_event(Event::WindowEvent {
1720 window_id: RootWindowId(WindowId(window)),
1721 event: CursorLeft { device_id: DEVICE_ID },
1722 });
1723
1724 result = ProcResult::Value(0);
1725 },
1726
1727 WM_MOUSEWHEEL => {
1728 use crate::event::MouseScrollDelta::LineDelta;
1729
1730 let value = (wparam >> 16) as i16;
1731 let value = value as f32 / WHEEL_DELTA as f32;
1732
1733 update_modifiers(window, userdata);
1734
1735 userdata.send_event(Event::WindowEvent {
1736 window_id: RootWindowId(WindowId(window)),
1737 event: WindowEvent::MouseWheel {
1738 device_id: DEVICE_ID,
1739 delta: LineDelta(0.0, value),
1740 phase: TouchPhase::Moved,
1741 },
1742 });
1743
1744 result = ProcResult::Value(0);
1745 },
1746
1747 WM_MOUSEHWHEEL => {
1748 use crate::event::MouseScrollDelta::LineDelta;
1749
1750 let value = (wparam >> 16) as i16;
1751 let value = -value as f32 / WHEEL_DELTA as f32; update_modifiers(window, userdata);
1754
1755 userdata.send_event(Event::WindowEvent {
1756 window_id: RootWindowId(WindowId(window)),
1757 event: WindowEvent::MouseWheel {
1758 device_id: DEVICE_ID,
1759 delta: LineDelta(value, 0.0),
1760 phase: TouchPhase::Moved,
1761 },
1762 });
1763
1764 result = ProcResult::Value(0);
1765 },
1766
1767 WM_KEYDOWN | WM_SYSKEYDOWN => {
1768 if msg == WM_SYSKEYDOWN {
1769 result = ProcResult::DefWindowProc(wparam);
1770 }
1771 },
1772
1773 WM_KEYUP | WM_SYSKEYUP => {
1774 if msg == WM_SYSKEYUP && unsafe { GetMenu(window) != 0 } {
1775 result = ProcResult::DefWindowProc(wparam);
1778 }
1779 },
1780
1781 WM_LBUTTONDOWN => {
1782 use crate::event::ElementState::Pressed;
1783 use crate::event::MouseButton::Left;
1784 use crate::event::WindowEvent::MouseInput;
1785
1786 unsafe { capture_mouse(window, &mut userdata.window_state_lock()) };
1787
1788 update_modifiers(window, userdata);
1789
1790 userdata.send_event(Event::WindowEvent {
1791 window_id: RootWindowId(WindowId(window)),
1792 event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Left },
1793 });
1794 result = ProcResult::Value(0);
1795 },
1796
1797 WM_LBUTTONUP => {
1798 use crate::event::ElementState::Released;
1799 use crate::event::MouseButton::Left;
1800 use crate::event::WindowEvent::MouseInput;
1801
1802 unsafe { release_mouse(userdata.window_state_lock()) };
1803
1804 update_modifiers(window, userdata);
1805
1806 userdata.send_event(Event::WindowEvent {
1807 window_id: RootWindowId(WindowId(window)),
1808 event: MouseInput { device_id: DEVICE_ID, state: Released, button: Left },
1809 });
1810 result = ProcResult::Value(0);
1811 },
1812
1813 WM_RBUTTONDOWN => {
1814 use crate::event::ElementState::Pressed;
1815 use crate::event::MouseButton::Right;
1816 use crate::event::WindowEvent::MouseInput;
1817
1818 unsafe { capture_mouse(window, &mut userdata.window_state_lock()) };
1819
1820 update_modifiers(window, userdata);
1821
1822 userdata.send_event(Event::WindowEvent {
1823 window_id: RootWindowId(WindowId(window)),
1824 event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Right },
1825 });
1826 result = ProcResult::Value(0);
1827 },
1828
1829 WM_RBUTTONUP => {
1830 use crate::event::ElementState::Released;
1831 use crate::event::MouseButton::Right;
1832 use crate::event::WindowEvent::MouseInput;
1833
1834 unsafe { release_mouse(userdata.window_state_lock()) };
1835
1836 update_modifiers(window, userdata);
1837
1838 userdata.send_event(Event::WindowEvent {
1839 window_id: RootWindowId(WindowId(window)),
1840 event: MouseInput { device_id: DEVICE_ID, state: Released, button: Right },
1841 });
1842 result = ProcResult::Value(0);
1843 },
1844
1845 WM_MBUTTONDOWN => {
1846 use crate::event::ElementState::Pressed;
1847 use crate::event::MouseButton::Middle;
1848 use crate::event::WindowEvent::MouseInput;
1849
1850 unsafe { capture_mouse(window, &mut userdata.window_state_lock()) };
1851
1852 update_modifiers(window, userdata);
1853
1854 userdata.send_event(Event::WindowEvent {
1855 window_id: RootWindowId(WindowId(window)),
1856 event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Middle },
1857 });
1858 result = ProcResult::Value(0);
1859 },
1860
1861 WM_MBUTTONUP => {
1862 use crate::event::ElementState::Released;
1863 use crate::event::MouseButton::Middle;
1864 use crate::event::WindowEvent::MouseInput;
1865
1866 unsafe { release_mouse(userdata.window_state_lock()) };
1867
1868 update_modifiers(window, userdata);
1869
1870 userdata.send_event(Event::WindowEvent {
1871 window_id: RootWindowId(WindowId(window)),
1872 event: MouseInput { device_id: DEVICE_ID, state: Released, button: Middle },
1873 });
1874 result = ProcResult::Value(0);
1875 },
1876
1877 WM_XBUTTONDOWN => {
1878 use crate::event::ElementState::Pressed;
1879 use crate::event::MouseButton::{Back, Forward, Other};
1880 use crate::event::WindowEvent::MouseInput;
1881 let xbutton = super::get_xbutton_wparam(wparam as u32);
1882
1883 unsafe { capture_mouse(window, &mut userdata.window_state_lock()) };
1884
1885 update_modifiers(window, userdata);
1886
1887 userdata.send_event(Event::WindowEvent {
1888 window_id: RootWindowId(WindowId(window)),
1889 event: MouseInput {
1890 device_id: DEVICE_ID,
1891 state: Pressed,
1892 button: match xbutton {
1893 1 => Back,
1894 2 => Forward,
1895 _ => Other(xbutton),
1896 },
1897 },
1898 });
1899 result = ProcResult::Value(0);
1900 },
1901
1902 WM_XBUTTONUP => {
1903 use crate::event::ElementState::Released;
1904 use crate::event::MouseButton::{Back, Forward, Other};
1905 use crate::event::WindowEvent::MouseInput;
1906 let xbutton = super::get_xbutton_wparam(wparam as u32);
1907
1908 unsafe { release_mouse(userdata.window_state_lock()) };
1909
1910 update_modifiers(window, userdata);
1911
1912 userdata.send_event(Event::WindowEvent {
1913 window_id: RootWindowId(WindowId(window)),
1914 event: MouseInput {
1915 device_id: DEVICE_ID,
1916 state: Released,
1917 button: match xbutton {
1918 1 => Back,
1919 2 => Forward,
1920 _ => Other(xbutton),
1921 },
1922 },
1923 });
1924 result = ProcResult::Value(0);
1925 },
1926
1927 WM_CAPTURECHANGED => {
1928 if lparam != window {
1933 userdata.window_state_lock().mouse.capture_count = 0;
1934 }
1935 result = ProcResult::Value(0);
1936 },
1937
1938 WM_TOUCH => {
1939 let pcount = super::loword(wparam as u32) as usize;
1940 let mut inputs = Vec::with_capacity(pcount);
1941 let htouch = lparam;
1942 if unsafe {
1943 GetTouchInputInfo(
1944 htouch,
1945 pcount as u32,
1946 inputs.as_mut_ptr(),
1947 mem::size_of::<TOUCHINPUT>() as i32,
1948 ) > 0
1949 } {
1950 unsafe { inputs.set_len(pcount) };
1951 for input in &inputs {
1952 let mut location = POINT { x: input.x / 100, y: input.y / 100 };
1953
1954 if unsafe { ScreenToClient(window, &mut location) } == false.into() {
1955 continue;
1956 }
1957
1958 let x = location.x as f64 + (input.x % 100) as f64 / 100f64;
1959 let y = location.y as f64 + (input.y % 100) as f64 / 100f64;
1960 let location = PhysicalPosition::new(x, y);
1961 userdata.send_event(Event::WindowEvent {
1962 window_id: RootWindowId(WindowId(window)),
1963 event: WindowEvent::Touch(Touch {
1964 phase: if util::has_flag(input.dwFlags, TOUCHEVENTF_DOWN) {
1965 TouchPhase::Started
1966 } else if util::has_flag(input.dwFlags, TOUCHEVENTF_UP) {
1967 TouchPhase::Ended
1968 } else if util::has_flag(input.dwFlags, TOUCHEVENTF_MOVE) {
1969 TouchPhase::Moved
1970 } else {
1971 continue;
1972 },
1973 location,
1974 force: None, id: input.dwID as u64,
1976 device_id: DEVICE_ID,
1977 }),
1978 });
1979 }
1980 }
1981 unsafe { CloseTouchInputHandle(htouch) };
1982 result = ProcResult::Value(0);
1983 },
1984
1985 WM_POINTERDOWN | WM_POINTERUPDATE | WM_POINTERUP => {
1986 if let (
1987 Some(GetPointerFrameInfoHistory),
1988 Some(SkipPointerFrameMessages),
1989 Some(GetPointerDeviceRects),
1990 ) = (
1991 *util::GET_POINTER_FRAME_INFO_HISTORY,
1992 *util::SKIP_POINTER_FRAME_MESSAGES,
1993 *util::GET_POINTER_DEVICE_RECTS,
1994 ) {
1995 let pointer_id = super::loword(wparam as u32) as u32;
1996 let mut entries_count = 0u32;
1997 let mut pointers_count = 0u32;
1998 if unsafe {
1999 GetPointerFrameInfoHistory(
2000 pointer_id,
2001 &mut entries_count,
2002 &mut pointers_count,
2003 ptr::null_mut(),
2004 )
2005 } == false.into()
2006 {
2007 result = ProcResult::Value(0);
2008 return;
2009 }
2010
2011 let pointer_info_count = (entries_count * pointers_count) as usize;
2012 let mut pointer_infos = Vec::with_capacity(pointer_info_count);
2013 if unsafe {
2014 GetPointerFrameInfoHistory(
2015 pointer_id,
2016 &mut entries_count,
2017 &mut pointers_count,
2018 pointer_infos.as_mut_ptr(),
2019 )
2020 } == false.into()
2021 {
2022 result = ProcResult::Value(0);
2023 return;
2024 }
2025 unsafe { pointer_infos.set_len(pointer_info_count) };
2026
2027 for pointer_info in pointer_infos.iter().rev() {
2031 let mut device_rect = mem::MaybeUninit::uninit();
2032 let mut display_rect = mem::MaybeUninit::uninit();
2033
2034 if unsafe {
2035 GetPointerDeviceRects(
2036 pointer_info.sourceDevice,
2037 device_rect.as_mut_ptr(),
2038 display_rect.as_mut_ptr(),
2039 )
2040 } == false.into()
2041 {
2042 continue;
2043 }
2044
2045 let device_rect = unsafe { device_rect.assume_init() };
2046 let display_rect = unsafe { display_rect.assume_init() };
2047
2048 let himetric_to_pixel_ratio_x = (display_rect.right - display_rect.left) as f64
2052 / (device_rect.right - device_rect.left) as f64;
2053 let himetric_to_pixel_ratio_y = (display_rect.bottom - display_rect.top) as f64
2054 / (device_rect.bottom - device_rect.top) as f64;
2055
2056 let x = display_rect.left as f64
2060 + pointer_info.ptHimetricLocation.x as f64 * himetric_to_pixel_ratio_x;
2061 let y = display_rect.top as f64
2062 + pointer_info.ptHimetricLocation.y as f64 * himetric_to_pixel_ratio_y;
2063
2064 let mut location = POINT { x: x.floor() as i32, y: y.floor() as i32 };
2065
2066 if unsafe { ScreenToClient(window, &mut location) } == false.into() {
2067 continue;
2068 }
2069
2070 let force = match pointer_info.pointerType {
2071 PT_TOUCH => {
2072 let mut touch_info = mem::MaybeUninit::uninit();
2073 util::GET_POINTER_TOUCH_INFO.and_then(|GetPointerTouchInfo| {
2074 match unsafe {
2075 GetPointerTouchInfo(
2076 pointer_info.pointerId,
2077 touch_info.as_mut_ptr(),
2078 )
2079 } {
2080 0 => None,
2081 _ => normalize_pointer_pressure(unsafe {
2082 touch_info.assume_init().pressure
2083 }),
2084 }
2085 })
2086 },
2087 PT_PEN => {
2088 let mut pen_info = mem::MaybeUninit::uninit();
2089 util::GET_POINTER_PEN_INFO.and_then(|GetPointerPenInfo| {
2090 match unsafe {
2091 GetPointerPenInfo(pointer_info.pointerId, pen_info.as_mut_ptr())
2092 } {
2093 0 => None,
2094 _ => normalize_pointer_pressure(unsafe {
2095 pen_info.assume_init().pressure
2096 }),
2097 }
2098 })
2099 },
2100 _ => None,
2101 };
2102
2103 let x = location.x as f64 + x.fract();
2104 let y = location.y as f64 + y.fract();
2105 let location = PhysicalPosition::new(x, y);
2106 userdata.send_event(Event::WindowEvent {
2107 window_id: RootWindowId(WindowId(window)),
2108 event: WindowEvent::Touch(Touch {
2109 phase: if util::has_flag(pointer_info.pointerFlags, POINTER_FLAG_DOWN) {
2110 TouchPhase::Started
2111 } else if util::has_flag(pointer_info.pointerFlags, POINTER_FLAG_UP) {
2112 TouchPhase::Ended
2113 } else if util::has_flag(pointer_info.pointerFlags, POINTER_FLAG_UPDATE)
2114 {
2115 TouchPhase::Moved
2116 } else {
2117 continue;
2118 },
2119 location,
2120 force,
2121 id: pointer_info.pointerId as u64,
2122 device_id: DEVICE_ID,
2123 }),
2124 });
2125 }
2126
2127 unsafe { SkipPointerFrameMessages(pointer_id) };
2128 }
2129 result = ProcResult::Value(0);
2130 },
2131
2132 WM_NCACTIVATE => {
2133 let is_active = wparam != false.into();
2134 let active_focus_changed = userdata.window_state_lock().set_active(is_active);
2135 if active_focus_changed {
2136 if is_active {
2137 unsafe { gain_active_focus(window, userdata) };
2138 } else {
2139 unsafe { lose_active_focus(window, userdata) };
2140 }
2141 }
2142 result = ProcResult::DefWindowProc(wparam);
2143 },
2144
2145 WM_SETFOCUS => {
2146 let active_focus_changed = userdata.window_state_lock().set_focused(true);
2147 if active_focus_changed {
2148 unsafe { gain_active_focus(window, userdata) };
2149 }
2150 result = ProcResult::Value(0);
2151 },
2152
2153 WM_KILLFOCUS => {
2154 let active_focus_changed = userdata.window_state_lock().set_focused(false);
2155 if active_focus_changed {
2156 unsafe { lose_active_focus(window, userdata) };
2157 }
2158 result = ProcResult::Value(0);
2159 },
2160
2161 WM_SETCURSOR => {
2162 let set_cursor_to = {
2163 let window_state = userdata.window_state_lock();
2164 let in_client_area = super::loword(lparam as u32) as u32 == HTCLIENT;
2168 if in_client_area {
2169 Some(window_state.mouse.selected_cursor.clone())
2170 } else {
2171 None
2172 }
2173 };
2174
2175 match set_cursor_to {
2176 Some(selected_cursor) => {
2177 let hcursor = match selected_cursor {
2178 SelectedCursor::Named(cursor_icon) => unsafe {
2179 LoadCursorW(0, util::to_windows_cursor(cursor_icon))
2180 },
2181 SelectedCursor::Custom(cursor) => cursor.as_raw_handle(),
2182 };
2183 unsafe { SetCursor(hcursor) };
2184 result = ProcResult::Value(0);
2185 },
2186 None => result = ProcResult::DefWindowProc(wparam),
2187 }
2188 },
2189
2190 WM_GETMINMAXINFO => {
2191 let mmi = lparam as *mut MINMAXINFO;
2192
2193 let window_state = userdata.window_state_lock();
2194 let window_flags = window_state.window_flags;
2195
2196 if window_state.min_size.is_some() || window_state.max_size.is_some() {
2197 if let Some(min_size) = window_state.min_size {
2198 let min_size = min_size.to_physical(window_state.scale_factor);
2199 let (width, height): (u32, u32) =
2200 window_flags.adjust_size(window, min_size).into();
2201 unsafe { (*mmi).ptMinTrackSize = POINT { x: width as i32, y: height as i32 } };
2202 }
2203 if let Some(max_size) = window_state.max_size {
2204 let max_size = max_size.to_physical(window_state.scale_factor);
2205 let (width, height): (u32, u32) =
2206 window_flags.adjust_size(window, max_size).into();
2207 unsafe { (*mmi).ptMaxTrackSize = POINT { x: width as i32, y: height as i32 } };
2208 }
2209 }
2210
2211 result = ProcResult::Value(0);
2212 },
2213
2214 WM_DPICHANGED => {
2217 use crate::event::WindowEvent::ScaleFactorChanged;
2218
2219 let new_dpi_x = super::loword(wparam as u32) as u32;
2224 let new_scale_factor = dpi_to_scale_factor(new_dpi_x);
2225 let old_scale_factor: f64;
2226
2227 let (allow_resize, window_flags) = {
2228 let mut window_state = userdata.window_state_lock();
2229 old_scale_factor = window_state.scale_factor;
2230 window_state.scale_factor = new_scale_factor;
2231
2232 if new_scale_factor == old_scale_factor {
2233 result = ProcResult::Value(0);
2234 return;
2235 }
2236
2237 let allow_resize = window_state.fullscreen.is_none()
2238 && !window_state.window_flags().contains(WindowFlags::MAXIMIZED);
2239
2240 (allow_resize, window_state.window_flags)
2241 };
2242
2243 let suggested_rect = unsafe { *(lparam as *const RECT) };
2245
2246 let margin_left: i32;
2251 let margin_top: i32;
2252 {
2255 let adjusted_rect =
2256 window_flags.adjust_rect(window, suggested_rect).unwrap_or(suggested_rect);
2257 margin_left = suggested_rect.left - adjusted_rect.left;
2258 margin_top = suggested_rect.top - adjusted_rect.top;
2259 }
2262
2263 let old_physical_inner_rect = util::WindowArea::Inner
2264 .get_rect(window)
2265 .expect("failed to query (old) inner window area");
2266 let old_physical_inner_size = PhysicalSize::new(
2267 (old_physical_inner_rect.right - old_physical_inner_rect.left) as u32,
2268 (old_physical_inner_rect.bottom - old_physical_inner_rect.top) as u32,
2269 );
2270
2271 let new_physical_inner_size = match allow_resize {
2274 true => old_physical_inner_size
2277 .to_logical::<f64>(old_scale_factor)
2278 .to_physical::<u32>(new_scale_factor),
2279 false => old_physical_inner_size,
2280 };
2281
2282 let new_inner_size = Arc::new(Mutex::new(new_physical_inner_size));
2283 userdata.send_event(Event::WindowEvent {
2284 window_id: RootWindowId(WindowId(window)),
2285 event: ScaleFactorChanged {
2286 scale_factor: new_scale_factor,
2287 inner_size_writer: InnerSizeWriter::new(Arc::downgrade(&new_inner_size)),
2288 },
2289 });
2290
2291 let new_physical_inner_size = *new_inner_size.lock().unwrap();
2292 drop(new_inner_size);
2293
2294 let dragging_window: bool;
2295
2296 {
2297 let window_state = userdata.window_state_lock();
2298 dragging_window =
2299 window_state.window_flags().contains(WindowFlags::MARKER_IN_SIZE_MOVE);
2300 if new_physical_inner_size != old_physical_inner_size {
2302 WindowState::set_window_flags(window_state, window, |f| {
2303 f.set(WindowFlags::MAXIMIZED, false)
2304 });
2305 }
2306 }
2307
2308 let new_outer_rect: RECT;
2309 {
2310 let suggested_ul =
2311 (suggested_rect.left + margin_left, suggested_rect.top + margin_top);
2312
2313 let mut conservative_rect = RECT {
2314 left: suggested_ul.0,
2315 top: suggested_ul.1,
2316 right: suggested_ul.0 + new_physical_inner_size.width as i32,
2317 bottom: suggested_ul.1 + new_physical_inner_size.height as i32,
2318 };
2319
2320 conservative_rect = window_flags
2321 .adjust_rect(window, conservative_rect)
2322 .unwrap_or(conservative_rect);
2323
2324 if dragging_window {
2327 let bias = {
2328 let cursor_pos = {
2329 let mut pos = unsafe { mem::zeroed() };
2330 unsafe { GetCursorPos(&mut pos) };
2331 pos
2332 };
2333 let suggested_cursor_horizontal_ratio = (cursor_pos.x - suggested_rect.left)
2334 as f64
2335 / (suggested_rect.right - suggested_rect.left) as f64;
2336
2337 (cursor_pos.x
2338 - (suggested_cursor_horizontal_ratio
2339 * (conservative_rect.right - conservative_rect.left) as f64)
2340 as i32)
2341 - conservative_rect.left
2342 };
2343 conservative_rect.left += bias;
2344 conservative_rect.right += bias;
2345 }
2346
2347 let new_dpi_monitor = unsafe { MonitorFromWindow(window, MONITOR_DEFAULTTONULL) };
2350 let conservative_rect_monitor =
2351 unsafe { MonitorFromRect(&conservative_rect, MONITOR_DEFAULTTONULL) };
2352 new_outer_rect = if conservative_rect_monitor == new_dpi_monitor {
2353 conservative_rect
2354 } else {
2355 let get_monitor_rect = |monitor| {
2356 let mut monitor_info = MONITORINFO {
2357 cbSize: mem::size_of::<MONITORINFO>() as _,
2358 ..unsafe { mem::zeroed() }
2359 };
2360 unsafe { GetMonitorInfoW(monitor, &mut monitor_info) };
2361 monitor_info.rcMonitor
2362 };
2363 let wrong_monitor = conservative_rect_monitor;
2364 let wrong_monitor_rect = get_monitor_rect(wrong_monitor);
2365 let new_monitor_rect = get_monitor_rect(new_dpi_monitor);
2366
2367 #[allow(clippy::bool_to_int_with_if)]
2371 let delta_nudge_to_dpi_monitor = (
2372 if wrong_monitor_rect.left == new_monitor_rect.right {
2373 -1
2374 } else if wrong_monitor_rect.right == new_monitor_rect.left {
2375 1
2376 } else {
2377 0
2378 },
2379 if wrong_monitor_rect.bottom == new_monitor_rect.top {
2380 1
2381 } else if wrong_monitor_rect.top == new_monitor_rect.bottom {
2382 -1
2383 } else {
2384 0
2385 },
2386 );
2387
2388 let abort_after_iterations = new_monitor_rect.right - new_monitor_rect.left
2389 + new_monitor_rect.bottom
2390 - new_monitor_rect.top;
2391 for _ in 0..abort_after_iterations {
2392 conservative_rect.left += delta_nudge_to_dpi_monitor.0;
2393 conservative_rect.right += delta_nudge_to_dpi_monitor.0;
2394 conservative_rect.top += delta_nudge_to_dpi_monitor.1;
2395 conservative_rect.bottom += delta_nudge_to_dpi_monitor.1;
2396
2397 if unsafe { MonitorFromRect(&conservative_rect, MONITOR_DEFAULTTONULL) }
2398 == new_dpi_monitor
2399 {
2400 break;
2401 }
2402 }
2403
2404 conservative_rect
2405 };
2406 }
2407
2408 unsafe {
2409 SetWindowPos(
2410 window,
2411 0,
2412 new_outer_rect.left,
2413 new_outer_rect.top,
2414 new_outer_rect.right - new_outer_rect.left,
2415 new_outer_rect.bottom - new_outer_rect.top,
2416 SWP_NOZORDER | SWP_NOACTIVATE,
2417 )
2418 };
2419
2420 result = ProcResult::Value(0);
2421 },
2422
2423 WM_SETTINGCHANGE => {
2424 use crate::event::WindowEvent::ThemeChanged;
2425
2426 let preferred_theme = userdata.window_state_lock().preferred_theme;
2427
2428 if preferred_theme.is_none() {
2429 let new_theme = try_theme(window, preferred_theme);
2430 let mut window_state = userdata.window_state_lock();
2431
2432 if window_state.current_theme != new_theme {
2433 window_state.current_theme = new_theme;
2434 drop(window_state);
2435 userdata.send_event(Event::WindowEvent {
2436 window_id: RootWindowId(WindowId(window)),
2437 event: ThemeChanged(new_theme),
2438 });
2439 }
2440 }
2441 result = ProcResult::DefWindowProc(wparam);
2442 },
2443
2444 _ => {
2445 if msg == DESTROY_MSG_ID.get() {
2446 unsafe { DestroyWindow(window) };
2447 result = ProcResult::Value(0);
2448 } else if msg == SET_RETAIN_STATE_ON_SIZE_MSG_ID.get() {
2449 let mut window_state = userdata.window_state_lock();
2450 window_state.set_window_flags_in_place(|f| {
2451 f.set(WindowFlags::MARKER_RETAIN_STATE_ON_SIZE, wparam != 0)
2452 });
2453 result = ProcResult::Value(0);
2454 } else if msg == TASKBAR_CREATED.get() {
2455 let window_state = userdata.window_state_lock();
2456 unsafe { set_skip_taskbar(window, window_state.skip_taskbar) };
2457 result = ProcResult::DefWindowProc(wparam);
2458 } else {
2459 result = ProcResult::DefWindowProc(wparam);
2460 }
2461 },
2462 };
2463
2464 userdata
2465 .event_loop_runner
2466 .catch_unwind(callback)
2467 .unwrap_or_else(|| result = ProcResult::Value(-1));
2468
2469 match result {
2470 ProcResult::DefWindowProc(wparam) => unsafe { DefWindowProcW(window, msg, wparam, lparam) },
2471 ProcResult::Value(val) => val,
2472 }
2473}
2474
2475unsafe extern "system" fn thread_event_target_callback(
2476 window: HWND,
2477 msg: u32,
2478 wparam: WPARAM,
2479 lparam: LPARAM,
2480) -> LRESULT {
2481 let userdata_ptr =
2482 unsafe { super::get_window_long(window, GWL_USERDATA) } as *mut ThreadMsgTargetData;
2483 if userdata_ptr.is_null() {
2484 return unsafe { DefWindowProcW(window, msg, wparam, lparam) };
2487 }
2488 let userdata = unsafe { Box::from_raw(userdata_ptr) };
2489
2490 if msg != WM_PAINT {
2491 unsafe { RedrawWindow(window, ptr::null(), 0, RDW_INTERNALPAINT) };
2492 }
2493
2494 let mut userdata_removed = false;
2495
2496 let callback = || match msg {
2500 WM_NCDESTROY => {
2501 unsafe { super::set_window_long(window, GWL_USERDATA, 0) };
2502 userdata_removed = true;
2503 0
2504 },
2505 WM_PAINT => unsafe {
2506 ValidateRect(window, ptr::null());
2507 DefWindowProcW(window, msg, wparam, lparam)
2510 },
2511
2512 WM_INPUT_DEVICE_CHANGE => {
2513 let event = match wparam as u32 {
2514 GIDC_ARRIVAL => DeviceEvent::Added,
2515 GIDC_REMOVAL => DeviceEvent::Removed,
2516 _ => unreachable!(),
2517 };
2518
2519 userdata
2520 .send_event(Event::DeviceEvent { device_id: wrap_device_id(lparam as u32), event });
2521
2522 0
2523 },
2524
2525 WM_INPUT => {
2526 if let Some(data) = raw_input::get_raw_input_data(lparam as _) {
2527 unsafe { handle_raw_input(&userdata, data) };
2528 }
2529
2530 unsafe { DefWindowProcW(window, msg, wparam, lparam) }
2531 },
2532
2533 _ if msg == USER_EVENT_MSG_ID.get() => {
2534 userdata.send_event(Event::UserEvent(UserEventPlaceholder));
2540 0
2541 },
2542 _ if msg == EXEC_MSG_ID.get() => {
2543 let mut function: ThreadExecFn = unsafe { Box::from_raw(wparam as *mut _) };
2544 function();
2545 0
2546 },
2547 _ => unsafe { DefWindowProcW(window, msg, wparam, lparam) },
2548 };
2549
2550 let result = userdata.event_loop_runner.catch_unwind(callback).unwrap_or(-1);
2551 if userdata_removed {
2552 drop(userdata);
2553 } else {
2554 Box::leak(userdata);
2555 }
2556 result
2557}
2558
2559unsafe fn handle_raw_input(userdata: &ThreadMsgTargetData, data: RAWINPUT) {
2560 use crate::event::DeviceEvent::{Button, Key, Motion, MouseMotion, MouseWheel};
2561 use crate::event::ElementState::{Pressed, Released};
2562 use crate::event::MouseScrollDelta::LineDelta;
2563
2564 let device_id = wrap_device_id(data.header.hDevice as _);
2565
2566 if data.header.dwType == RIM_TYPEMOUSE {
2567 let mouse = unsafe { data.data.mouse };
2568
2569 if util::has_flag(mouse.usFlags as u32, MOUSE_MOVE_RELATIVE) {
2570 let x = mouse.lLastX as f64;
2571 let y = mouse.lLastY as f64;
2572
2573 if x != 0.0 {
2574 userdata.send_event(Event::DeviceEvent {
2575 device_id,
2576 event: Motion { axis: 0, value: x },
2577 });
2578 }
2579
2580 if y != 0.0 {
2581 userdata.send_event(Event::DeviceEvent {
2582 device_id,
2583 event: Motion { axis: 1, value: y },
2584 });
2585 }
2586
2587 if x != 0.0 || y != 0.0 {
2588 userdata.send_event(Event::DeviceEvent {
2589 device_id,
2590 event: MouseMotion { delta: (x, y) },
2591 });
2592 }
2593 }
2594
2595 let button_flags = unsafe { mouse.Anonymous.Anonymous.usButtonFlags };
2596 if util::has_flag(button_flags as u32, RI_MOUSE_WHEEL) {
2597 let button_data = unsafe { mouse.Anonymous.Anonymous.usButtonData } as i16;
2598 let delta = button_data as f32 / WHEEL_DELTA as f32;
2599 userdata.send_event(Event::DeviceEvent {
2600 device_id,
2601 event: MouseWheel { delta: LineDelta(0.0, delta) },
2602 });
2603 }
2604 if util::has_flag(button_flags as u32, RI_MOUSE_HWHEEL) {
2605 let button_data = unsafe { mouse.Anonymous.Anonymous.usButtonData } as i16;
2606 let delta = -button_data as f32 / WHEEL_DELTA as f32;
2607 userdata.send_event(Event::DeviceEvent {
2608 device_id,
2609 event: MouseWheel { delta: LineDelta(delta, 0.0) },
2610 });
2611 }
2612
2613 let button_state = raw_input::get_raw_mouse_button_state(button_flags as u32);
2614 for (button, state) in button_state.iter().enumerate() {
2615 if let Some(state) = *state {
2616 userdata.send_event(Event::DeviceEvent {
2617 device_id,
2618 event: Button { button: button as _, state },
2619 });
2620 }
2621 }
2622 } else if data.header.dwType == RIM_TYPEKEYBOARD {
2623 let keyboard = unsafe { data.data.keyboard };
2624
2625 let pressed = keyboard.Message == WM_KEYDOWN || keyboard.Message == WM_SYSKEYDOWN;
2626 let released = keyboard.Message == WM_KEYUP || keyboard.Message == WM_SYSKEYUP;
2627
2628 if !pressed && !released {
2629 return;
2630 }
2631
2632 if let Some(physical_key) = raw_input::get_keyboard_physical_key(keyboard) {
2633 let state = if pressed { Pressed } else { Released };
2634
2635 userdata.send_event(Event::DeviceEvent {
2636 device_id,
2637 event: Key(RawKeyEvent { physical_key, state }),
2638 });
2639 }
2640 }
2641}
2642
2643enum PointerMoveKind {
2644 Enter,
2646 Leave,
2648 None,
2650}
2651
2652fn get_pointer_move_kind(
2653 window: HWND,
2654 mouse_was_inside_window: bool,
2655 x: i32,
2656 y: i32,
2657) -> PointerMoveKind {
2658 let rect: RECT = unsafe {
2659 let mut rect: RECT = mem::zeroed();
2660 if GetClientRect(window, &mut rect) == false.into() {
2661 return PointerMoveKind::None; }
2663 rect
2664 };
2665
2666 let x = (rect.left..rect.right).contains(&x);
2667 let y = (rect.top..rect.bottom).contains(&y);
2668
2669 if !mouse_was_inside_window && x && y {
2670 PointerMoveKind::Enter
2671 } else if mouse_was_inside_window && !(x && y) {
2672 PointerMoveKind::Leave
2673 } else {
2674 PointerMoveKind::None
2675 }
2676}