From 81a5c10830e3decd4976baee9b5c828db9e291d6 Mon Sep 17 00:00:00 2001 From: Osspial Date: Mon, 9 Mar 2020 16:20:48 -0400 Subject: [PATCH 1/4] Add EventLoopWindowTargetExtWindows::schedule_modal_fn function --- examples/win32_modal_dialog.rs | 57 +++++++++++++++++++ src/platform/windows.rs | 53 ++++++++++++++++- src/platform_impl/windows/event_loop.rs | 4 ++ .../windows/event_loop/runner.rs | 16 ++++++ 4 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 examples/win32_modal_dialog.rs diff --git a/examples/win32_modal_dialog.rs b/examples/win32_modal_dialog.rs new file mode 100644 index 0000000000..e865590cbf --- /dev/null +++ b/examples/win32_modal_dialog.rs @@ -0,0 +1,57 @@ +use winit::{ + event::{Event, KeyboardInput, WindowEvent, VirtualKeyCode, ElementState}, + event_loop::{ControlFlow, EventLoop}, + window::WindowBuilder, + platform::windows::{WindowExtWindows, EventLoopWindowTargetExtWindows}, +}; +use winapi::um::winuser; + +#[derive(Debug, Clone, Copy)] +enum ModalDialogEvent { + CloseWindow, +} + +fn main() { + simple_logger::init().unwrap(); + + let event_loop = EventLoop::::with_user_event(); + let proxy = event_loop.create_proxy(); + + let window = WindowBuilder::new() + .with_title("Your faithful window") + .build(&event_loop) + .unwrap(); + + event_loop.run(move |event, window_target, control_flow| { + *control_flow = ControlFlow::Wait; + println!("{:?}", event); + + match event { + Event::WindowEvent{ event: WindowEvent::CloseRequested, .. } | + Event::WindowEvent{ event: WindowEvent::KeyboardInput{ input: KeyboardInput{ virtual_keycode: Some(VirtualKeyCode::Escape), state: ElementState::Pressed, ..}, ..}, ..} => { + let hwnd = window.hwnd(); + let proxy = proxy.clone(); + window_target.schedule_modal_fn(move || unsafe { + println!("\n\t\tstart modal loop\n"); + + let msg_box_id = winuser::MessageBoxA( + hwnd as _, + "Are you sure you want close the window?\0".as_ptr() as *const _, + "Confirm Close\0".as_ptr() as *const _, + winuser::MB_ICONEXCLAMATION | winuser::MB_YESNO + ); + + println!("\n\t\tend modal loop\n"); + + if msg_box_id == winuser::IDYES { + proxy.send_event(ModalDialogEvent::CloseWindow).unwrap(); + } + }); + }, + Event::UserEvent(ModalDialogEvent::CloseWindow) => { + *control_flow = ControlFlow::Exit; + } + _ => (), + } + }); +} diff --git a/src/platform/windows.rs b/src/platform/windows.rs index a356f1e1c0..77833614a9 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -10,7 +10,7 @@ use winapi::shared::windef::HWND; use crate::{ dpi::PhysicalSize, event::DeviceId, - event_loop::EventLoop, + event_loop::{EventLoop, EventLoopWindowTarget}, monitor::MonitorHandle, platform_impl::{EventLoop as WindowsEventLoop, WinIcon}, window::{BadIcon, Icon, Window, WindowBuilder}, @@ -69,6 +69,57 @@ impl EventLoopExtWindows for EventLoop { } } +/// Additional methods on `EventLoopWindowTarget` that are specific to Windows. +pub trait EventLoopWindowTargetExtWindows { + /// Schedule a closure to be invoked after the current event handler returns. + /// + /// This is useful if you're calling one of the Windows API's many *modal functions*. Modal + /// functions take over control of the event loop for the duration of their execution, and don't + /// return control flow to the caller until the operation they perform has been completed. + /// They're typically used for popup windows that the user must click through to continue using + /// the program - the [`MessageBox`](https://docs.microsoft.com/en-us/windows/win32/dlgbox/using-dialog-boxes#displaying-a-message-box) + /// function is a good example of this. + /// + /// The reason this function is necessary is that, if you call a modal function inside of the + /// standard Winit event handler closure, Winit cannot dispatch OS events to that closure + /// while the modal loop is running since the closure is being borrowed by the closure + /// invocation that called the modal function. This function sidesteps that issue by allowing + /// you to call modal functions outside the scope of the normal event handler function, which + /// prevents the double-borrowing and allows event loop execution to continue as normal. + /// + /// # Examples + /// + /// ```rust,no_run + /// event_loop_window_target.schedule_modal_fn(move || unsafe { + /// println!("\n\t\tstart modal loop\n"); + /// + /// let msg_box_id = winuser::MessageBoxA( + /// hwnd as _, + /// "Please press Yes or No\0".as_ptr() as *const _, + /// "Dialog Box\0".as_ptr() as *const _, + /// winuser::MB_ICONEXCLAMATION | winuser::MB_YESNO + /// ); + /// + /// println!("\n\t\tend modal loop\n"); + /// + /// if msg_box_id == winuser::IDYES { + /// println!("Yes pressed!"); + /// } else { + /// println!("No pressed!"); + /// } + /// }); + /// ``` + /// + /// See also the `win32_modal_dialog.rs` example. + fn schedule_modal_fn(&self, f: impl 'static + FnOnce()); +} + +impl EventLoopWindowTargetExtWindows for EventLoopWindowTarget { + fn schedule_modal_fn(&self, f: impl 'static + FnOnce()) { + self.p.schedule_modal_fn(f); + } +} + /// Additional methods on `Window` that are specific to Windows. pub trait WindowExtWindows { /// Returns the HINSTANCE of the window diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index a7deac50c5..cbda2c9b29 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -247,6 +247,10 @@ impl EventLoopWindowTarget { target_window: self.thread_msg_target, } } + + pub fn schedule_modal_fn(&self, f: impl 'static + FnOnce()) { + self.runner_shared.schedule_modal_fn(f); + } } fn main_thread_id() -> DWORD { diff --git a/src/platform_impl/windows/event_loop/runner.rs b/src/platform_impl/windows/event_loop/runner.rs index 258a40c08c..2ef891731b 100644 --- a/src/platform_impl/windows/event_loop/runner.rs +++ b/src/platform_impl/windows/event_loop/runner.rs @@ -33,6 +33,8 @@ pub(crate) struct EventLoopRunner { event_handler: Cell, &mut ControlFlow)>>>, event_buffer: RefCell>>, + modal_fns: RefCell>>, + owned_windows: Cell>, panic_error: Cell>, @@ -71,6 +73,7 @@ impl EventLoopRunner { last_events_cleared: Cell::new(Instant::now()), event_handler: Cell::new(None), event_buffer: RefCell::new(VecDeque::new()), + modal_fns: RefCell::new(VecDeque::new()), owned_windows: Cell::new(HashSet::new()), } } @@ -96,6 +99,7 @@ impl EventLoopRunner { last_events_cleared: _, event_handler, event_buffer: _, + modal_fns: _, owned_windows: _, } = self; runner_state.set(RunnerState::Uninitialized); @@ -191,6 +195,10 @@ impl EventLoopRunner { owned_windows.extend(&new_owned_windows); self.owned_windows.set(owned_windows); } + + pub fn schedule_modal_fn(&self, f: impl 'static + FnOnce()) { + self.modal_fns.borrow_mut().push_back(Box::new(f)); + } } /// Event dispatch functions. @@ -243,6 +251,14 @@ impl EventLoopRunner { assert!(self.event_handler.replace(Some(event_handler)).is_none()); self.control_flow.set(control_flow); + + loop { + let modal_fn_opt = self.modal_fns.borrow_mut().pop_front(); + match modal_fn_opt { + Some(f) => f(), + None => break, + } + } }); } From 324c4c44d6e693409353531022b933258547d1e7 Mon Sep 17 00:00:00 2001 From: Osspial Date: Mon, 9 Mar 2020 16:56:29 -0400 Subject: [PATCH 2/4] Fix potential use-after-free error when calling modal functions --- src/platform_impl/windows/event_loop.rs | 69 +++++++++++++++++-------- 1 file changed, 48 insertions(+), 21 deletions(-) diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index cbda2c9b29..47429a6dd4 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -594,7 +594,7 @@ fn subclass_event_target_window( event_loop_runner, user_event_receiver: rx, }; - let input_ptr = Box::into_raw(Box::new(subclass_input)); + let input_ptr = Rc::into_raw(Rc::new(subclass_input)); let subclass_result = commctrl::SetWindowSubclass( window, Some(thread_event_target_callback::), @@ -627,7 +627,7 @@ const WINDOW_SUBCLASS_ID: UINT_PTR = 0; const THREAD_EVENT_TARGET_SUBCLASS_ID: UINT_PTR = 1; pub(crate) fn subclass_window(window: HWND, subclass_input: SubclassInput) { subclass_input.event_loop_runner.register_window(window); - let input_ptr = Box::into_raw(Box::new(subclass_input)); + let input_ptr = Rc::into_raw(Rc::new(subclass_input)); let subclass_result = unsafe { commctrl::SetWindowSubclass( window, @@ -639,6 +639,23 @@ pub(crate) fn subclass_window(window: HWND, subclass_input: SubclassInput) assert_eq!(subclass_result, 1); } +/// Get a subclass input `Rc` and increment the reference count. +unsafe fn get_subclass_input_rc(t: *const S) -> Rc { + let rc = Rc::from_raw(t); + let rc_cloned = rc.clone(); + mem::forget(rc); + rc_cloned +} + +/// Destroy the original subclass input `Rc` and decrements the reference count. +/// +/// This should only be called in the `WM_DESTROY` handler. If the event handler function isn't +/// re-entrant, this will destroy the subclass data immediately. If it *is* re-entrant, the subclass +/// data will be destroyed when the highest-level event handler returns. +unsafe fn destroy_subclass_input_rc(t: *const S) { + Rc::from_raw(t); +} + fn normalize_pointer_pressure(pressure: u32) -> Option { match pressure { 1..=1024 => Some(Force::Normalized(pressure as f64 / 1024.0)), @@ -744,7 +761,9 @@ unsafe extern "system" fn public_window_callback( _: UINT_PTR, subclass_input_ptr: DWORD_PTR, ) -> LRESULT { - let subclass_input = &*(subclass_input_ptr as *const SubclassInput); + let subclass_input_ptr = subclass_input_ptr as *const SubclassInput; + let subclass_input_rc = get_subclass_input_rc(subclass_input_ptr); + let subclass_input = &*subclass_input_rc; winuser::RedrawWindow( subclass_input.event_loop_runner.thread_msg_target(), @@ -757,6 +776,23 @@ unsafe extern "system" fn public_window_callback( // the closure to catch_unwind directly so that the match body indendation wouldn't change and // the git blame and history would be preserved. let callback = || match msg { + // We use WM_NCDESTROY instead of WM_DESTROY because WM_NCDESTROY is dispatched after + // WM_DESTROY, and de-allocating the subclass data in WM_DESTROY causes the above + // subclass_input fields to point to uninitialized memory, which triggers undefined + // behavior. + winuser::WM_NCDESTROY => { + use crate::event::WindowEvent::Destroyed; + ole2::RevokeDragDrop(window); + subclass_input.send_event(Event::WindowEvent { + window_id: RootWindowId(WindowId(window)), + event: Destroyed, + }); + subclass_input.event_loop_runner.remove_window(window); + + destroy_subclass_input_rc(subclass_input_ptr); + 0 + } + winuser::WM_ENTERSIZEMOVE => { subclass_input .window_state @@ -793,20 +829,6 @@ unsafe extern "system" fn public_window_callback( 0 } - winuser::WM_DESTROY => { - use crate::event::WindowEvent::Destroyed; - ole2::RevokeDragDrop(window); - subclass_input.send_event(Event::WindowEvent { - window_id: RootWindowId(WindowId(window)), - event: Destroyed, - }); - subclass_input.event_loop_runner.remove_window(window); - - drop(subclass_input); - Box::from_raw(subclass_input_ptr as *mut SubclassInput); - 0 - } - winuser::WM_PAINT => { if subclass_input.event_loop_runner.should_buffer() { // this branch can happen in response to `UpdateWindow`, if win32 decides to @@ -1908,7 +1930,9 @@ unsafe extern "system" fn thread_event_target_callback( _: UINT_PTR, subclass_input_ptr: DWORD_PTR, ) -> LRESULT { - let subclass_input = &mut *(subclass_input_ptr as *mut ThreadMsgTargetSubclassInput); + let subclass_input_ptr = subclass_input_ptr as *const ThreadMsgTargetSubclassInput; + let subclass_input_rc = get_subclass_input_rc(subclass_input_ptr); + let subclass_input = &*subclass_input_rc; let runner = subclass_input.event_loop_runner.clone(); if msg != winuser::WM_PAINT { @@ -1924,9 +1948,12 @@ unsafe extern "system" fn thread_event_target_callback( // the closure to catch_unwind directly so that the match body indendation wouldn't change and // the git blame and history would be preserved. let callback = || match msg { - winuser::WM_DESTROY => { - Box::from_raw(subclass_input); - drop(subclass_input); + // We use WM_NCDESTROY instead of WM_DESTROY because WM_NCDESTROY is dispatched after + // WM_DESTROY, and de-allocating the subclass data in WM_DESTROY causes the above + // subclass_input fields to point to uninitialized memory, which triggers undefined + // behavior. + winuser::WM_NCDESTROY => { + destroy_subclass_input_rc(subclass_input_ptr); 0 } // Because WM_PAINT comes after all other messages, we use it during modal loops to detect From c04ace538cbe084f930d819d85a79e74849f6c45 Mon Sep 17 00:00:00 2001 From: Osspial Date: Tue, 10 Mar 2020 16:08:29 -0400 Subject: [PATCH 3/4] Add initial implementation of run_embedded --- src/platform/windows.rs | 45 +++++++++- src/platform_impl/windows/event_loop.rs | 109 +++++++++++++++++------- src/platform_impl/windows/mod.rs | 2 +- 3 files changed, 119 insertions(+), 37 deletions(-) diff --git a/src/platform/windows.rs b/src/platform/windows.rs index 77833614a9..20ee7eed81 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -9,15 +9,20 @@ use winapi::shared::windef::HWND; use crate::{ dpi::PhysicalSize, - event::DeviceId, - event_loop::{EventLoop, EventLoopWindowTarget}, + event::{DeviceId, Event}, + event_loop::{ControlFlow, EventLoop, EventLoopWindowTarget}, monitor::MonitorHandle, - platform_impl::{EventLoop as WindowsEventLoop, WinIcon}, + platform_impl::{EventLoop as WindowsEventLoop, WinIcon, EventLoopEmbedded as WindowsEventLoopEmbedded}, window::{BadIcon, Icon, Window, WindowBuilder}, }; +pub struct EventLoopEmbedded<'a, T: 'static> { + p: WindowsEventLoopEmbedded<'a, T>, +} + /// Additional methods on `EventLoop` that are specific to Windows. pub trait EventLoopExtWindows { + type UserEvent; /// Creates an event loop off of the main thread. /// /// # `Window` caveats @@ -41,9 +46,24 @@ pub trait EventLoopExtWindows { fn new_dpi_unaware_any_thread() -> Self where Self: Sized; + + /// Initialize an event loop that can run through somebody else's event pump. + /// + /// This does *not* dispatch events without external assistance! Other code must be running a + /// [Win32 message loop](https://docs.microsoft.com/en-us/windows/win32/learnwin32/window-messages), + /// and the `event_handler` closure will be called while the `EventLoopEmbedded` is in scope. + /// The loop can come from any code that calls the native Win32 message loop functions - for + /// example, this could be used to embed a Winit message loop in an SDL or GLFW application, or + /// create a DAW plugin. + /// + /// TODO: REWRITE `exit_requested` and `resume_panic_if_necessary` as trait functions. + fn run_embedded<'a, F>(self, event_handler: F) -> EventLoopEmbedded<'a, Self::UserEvent> + where + F: 'a + FnMut(Event<'_, Self::UserEvent>, &EventLoopWindowTarget, &mut ControlFlow); } impl EventLoopExtWindows for EventLoop { + type UserEvent = T; #[inline] fn new_any_thread() -> Self { EventLoop { @@ -67,6 +87,25 @@ impl EventLoopExtWindows for EventLoop { _marker: ::std::marker::PhantomData, } } + + fn run_embedded<'a, F>(self, event_handler: F) -> EventLoopEmbedded<'a, Self::UserEvent> + where + F: 'a + FnMut(Event<'_, Self::UserEvent>, &EventLoopWindowTarget, &mut ControlFlow) + { + EventLoopEmbedded { + p: self.event_loop.run_embedded(event_handler) + } + } +} + +impl EventLoopEmbedded<'_, T> { + pub fn exit_requested(&self) -> bool { + self.p.exit_requested() + } + + pub fn resume_panic_if_necessary(&self) { + self.p.resume_panic_if_necessary() + } } /// Additional methods on `EventLoopWindowTarget` that are specific to Windows. diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index 47429a6dd4..83918ec7e5 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -104,7 +104,7 @@ impl ThreadMsgTargetSubclassInput { pub struct EventLoop { thread_msg_sender: Sender, - window_target: RootELW, + window_target: Rc>, } pub struct EventLoopWindowTarget { @@ -113,6 +113,11 @@ pub struct EventLoopWindowTarget { pub(crate) runner_shared: EventLoopRunnerShared, } +pub struct EventLoopEmbedded<'a, T: 'static> { + window_target: Rc>, + _function_lifetime: PhantomData<&'a ()>, +} + macro_rules! main_thread_check { ($fn_name:literal) => {{ let thread_id = unsafe { processthreadsapi::GetCurrentThreadId() }; @@ -163,14 +168,14 @@ impl EventLoop { EventLoop { thread_msg_sender, - window_target: RootELW { + window_target: Rc::new(RootELW { p: EventLoopWindowTarget { thread_id, thread_msg_target, runner_shared, }, _marker: PhantomData, - }, + }), } } @@ -186,27 +191,14 @@ impl EventLoop { ::std::process::exit(0); } - pub fn run_return(&mut self, mut event_handler: F) + pub fn run_return(&mut self, event_handler: F) where F: FnMut(Event<'_, T>, &RootELW, &mut ControlFlow), { - let event_loop_windows_ref = &self.window_target; - - unsafe { - self.window_target - .p - .runner_shared - .set_event_handler(move |event, control_flow| { - event_handler(event, event_loop_windows_ref, control_flow) - }); - } - - let runner = &self.window_target.p.runner_shared; - unsafe { + let runner = self.embedded_runner(event_handler); let mut msg = mem::zeroed(); - runner.poll(); 'main: loop { if 0 == winuser::GetMessageW(&mut msg, ptr::null_mut(), 0, 0) { break 'main; @@ -214,21 +206,47 @@ impl EventLoop { winuser::TranslateMessage(&mut msg); winuser::DispatchMessageW(&mut msg); - if let Err(payload) = runner.take_panic_error() { - runner.reset_runner(); - panic::resume_unwind(payload); - } + runner.resume_panic_if_necessary(); - if runner.control_flow() == ControlFlow::Exit && !runner.handling_events() { + if runner.exit_requested() { break 'main; } } } + } + pub fn run_embedded<'a, F>(mut self, event_handler: F) -> EventLoopEmbedded<'a, T> + where + F: 'a + FnMut(Event<'_, T>, &RootELW, &mut ControlFlow) + { unsafe { - runner.call_event_handler(Event::LoopDestroyed); + self.embedded_runner(event_handler) + } + } + + unsafe fn embedded_runner<'a, F>( + &mut self, + mut event_handler: F + ) -> EventLoopEmbedded<'a, T> + where + F: 'a + FnMut(Event<'_, T>, &RootELW, &mut ControlFlow) + { + let window_target = self.window_target.clone(); + let event_loop_windows_ptr = &*window_target as *const RootELW; + + window_target + .p + .runner_shared + .set_event_handler(move |event, control_flow| { + event_handler(event, &*event_loop_windows_ptr, control_flow) + }); + + window_target.p.runner_shared.poll(); + + EventLoopEmbedded { + window_target, + _function_lifetime: PhantomData, } - runner.reset_runner(); } pub fn create_proxy(&self) -> EventLoopProxy { @@ -239,6 +257,39 @@ impl EventLoop { } } +impl EventLoopEmbedded<'_, T> { + pub fn exit_requested(&self) -> bool { + let runner = &self.window_target.p.runner_shared; + runner.control_flow() == ControlFlow::Exit && !runner.handling_events() + } + + pub fn resume_panic_if_necessary(&self) { + let runner = &self.window_target.p.runner_shared; + + if let Err(payload) = runner.take_panic_error() { + runner.reset_runner(); + panic::resume_unwind(payload); + } + } +} + +impl Drop for EventLoopEmbedded<'_, T> { + fn drop(&mut self) { + unsafe { + self.window_target.p.runner_shared.call_event_handler(Event::LoopDestroyed); + self.window_target.p.runner_shared.reset_runner(); + } + } +} + +impl Drop for EventLoopWindowTarget { + fn drop(&mut self) { + unsafe { + winuser::DestroyWindow(self.thread_msg_target); + } + } +} + impl EventLoopWindowTarget { #[inline(always)] pub(crate) fn create_thread_executor(&self) -> EventLoopThreadExecutor { @@ -380,14 +431,6 @@ fn dur2timeout(dur: Duration) -> DWORD { .unwrap_or(winbase::INFINITE) } -impl Drop for EventLoop { - fn drop(&mut self) { - unsafe { - winuser::DestroyWindow(self.window_target.p.thread_msg_target); - } - } -} - pub(crate) struct EventLoopThreadExecutor { thread_id: DWORD, target_window: HWND, diff --git a/src/platform_impl/windows/mod.rs b/src/platform_impl/windows/mod.rs index 021c903b8d..e9ad0435b6 100644 --- a/src/platform_impl/windows/mod.rs +++ b/src/platform_impl/windows/mod.rs @@ -3,7 +3,7 @@ use winapi::{self, shared::windef::HWND}; pub use self::{ - event_loop::{EventLoop, EventLoopProxy, EventLoopWindowTarget}, + event_loop::{EventLoop, EventLoopEmbedded, EventLoopProxy, EventLoopWindowTarget}, icon::WinIcon, monitor::{MonitorHandle, VideoMode}, window::Window, From 52157c21f8c65af9e899c51645015648aa2152fb Mon Sep 17 00:00:00 2001 From: Osspial Date: Tue, 10 Mar 2020 16:12:43 -0400 Subject: [PATCH 4/4] Format --- examples/win32_modal_dialog.rs | 29 +++++++++++++++++++------ src/platform/windows.rs | 20 +++++++++++++---- src/platform_impl/windows/event_loop.rs | 18 +++++++-------- 3 files changed, 46 insertions(+), 21 deletions(-) diff --git a/examples/win32_modal_dialog.rs b/examples/win32_modal_dialog.rs index e865590cbf..c4aba62735 100644 --- a/examples/win32_modal_dialog.rs +++ b/examples/win32_modal_dialog.rs @@ -1,10 +1,10 @@ +use winapi::um::winuser; use winit::{ - event::{Event, KeyboardInput, WindowEvent, VirtualKeyCode, ElementState}, + event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent}, event_loop::{ControlFlow, EventLoop}, + platform::windows::{EventLoopWindowTargetExtWindows, WindowExtWindows}, window::WindowBuilder, - platform::windows::{WindowExtWindows, EventLoopWindowTargetExtWindows}, }; -use winapi::um::winuser; #[derive(Debug, Clone, Copy)] enum ModalDialogEvent { @@ -27,8 +27,23 @@ fn main() { println!("{:?}", event); match event { - Event::WindowEvent{ event: WindowEvent::CloseRequested, .. } | - Event::WindowEvent{ event: WindowEvent::KeyboardInput{ input: KeyboardInput{ virtual_keycode: Some(VirtualKeyCode::Escape), state: ElementState::Pressed, ..}, ..}, ..} => { + Event::WindowEvent { + event: WindowEvent::CloseRequested, + .. + } + | Event::WindowEvent { + event: + WindowEvent::KeyboardInput { + input: + KeyboardInput { + virtual_keycode: Some(VirtualKeyCode::Escape), + state: ElementState::Pressed, + .. + }, + .. + }, + .. + } => { let hwnd = window.hwnd(); let proxy = proxy.clone(); window_target.schedule_modal_fn(move || unsafe { @@ -38,7 +53,7 @@ fn main() { hwnd as _, "Are you sure you want close the window?\0".as_ptr() as *const _, "Confirm Close\0".as_ptr() as *const _, - winuser::MB_ICONEXCLAMATION | winuser::MB_YESNO + winuser::MB_ICONEXCLAMATION | winuser::MB_YESNO, ); println!("\n\t\tend modal loop\n"); @@ -47,7 +62,7 @@ fn main() { proxy.send_event(ModalDialogEvent::CloseWindow).unwrap(); } }); - }, + } Event::UserEvent(ModalDialogEvent::CloseWindow) => { *control_flow = ControlFlow::Exit; } diff --git a/src/platform/windows.rs b/src/platform/windows.rs index 20ee7eed81..f71cd2c9f2 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -12,7 +12,9 @@ use crate::{ event::{DeviceId, Event}, event_loop::{ControlFlow, EventLoop, EventLoopWindowTarget}, monitor::MonitorHandle, - platform_impl::{EventLoop as WindowsEventLoop, WinIcon, EventLoopEmbedded as WindowsEventLoopEmbedded}, + platform_impl::{ + EventLoop as WindowsEventLoop, EventLoopEmbedded as WindowsEventLoopEmbedded, WinIcon, + }, window::{BadIcon, Icon, Window, WindowBuilder}, }; @@ -59,7 +61,12 @@ pub trait EventLoopExtWindows { /// TODO: REWRITE `exit_requested` and `resume_panic_if_necessary` as trait functions. fn run_embedded<'a, F>(self, event_handler: F) -> EventLoopEmbedded<'a, Self::UserEvent> where - F: 'a + FnMut(Event<'_, Self::UserEvent>, &EventLoopWindowTarget, &mut ControlFlow); + F: 'a + + FnMut( + Event<'_, Self::UserEvent>, + &EventLoopWindowTarget, + &mut ControlFlow, + ); } impl EventLoopExtWindows for EventLoop { @@ -90,10 +97,15 @@ impl EventLoopExtWindows for EventLoop { fn run_embedded<'a, F>(self, event_handler: F) -> EventLoopEmbedded<'a, Self::UserEvent> where - F: 'a + FnMut(Event<'_, Self::UserEvent>, &EventLoopWindowTarget, &mut ControlFlow) + F: 'a + + FnMut( + Event<'_, Self::UserEvent>, + &EventLoopWindowTarget, + &mut ControlFlow, + ), { EventLoopEmbedded { - p: self.event_loop.run_embedded(event_handler) + p: self.event_loop.run_embedded(event_handler), } } } diff --git a/src/platform_impl/windows/event_loop.rs b/src/platform_impl/windows/event_loop.rs index 83918ec7e5..de7c9726a0 100644 --- a/src/platform_impl/windows/event_loop.rs +++ b/src/platform_impl/windows/event_loop.rs @@ -217,19 +217,14 @@ impl EventLoop { pub fn run_embedded<'a, F>(mut self, event_handler: F) -> EventLoopEmbedded<'a, T> where - F: 'a + FnMut(Event<'_, T>, &RootELW, &mut ControlFlow) + F: 'a + FnMut(Event<'_, T>, &RootELW, &mut ControlFlow), { - unsafe { - self.embedded_runner(event_handler) - } + unsafe { self.embedded_runner(event_handler) } } - unsafe fn embedded_runner<'a, F>( - &mut self, - mut event_handler: F - ) -> EventLoopEmbedded<'a, T> + unsafe fn embedded_runner<'a, F>(&mut self, mut event_handler: F) -> EventLoopEmbedded<'a, T> where - F: 'a + FnMut(Event<'_, T>, &RootELW, &mut ControlFlow) + F: 'a + FnMut(Event<'_, T>, &RootELW, &mut ControlFlow), { let window_target = self.window_target.clone(); let event_loop_windows_ptr = &*window_target as *const RootELW; @@ -276,7 +271,10 @@ impl EventLoopEmbedded<'_, T> { impl Drop for EventLoopEmbedded<'_, T> { fn drop(&mut self) { unsafe { - self.window_target.p.runner_shared.call_event_handler(Event::LoopDestroyed); + self.window_target + .p + .runner_shared + .call_event_handler(Event::LoopDestroyed); self.window_target.p.runner_shared.reset_runner(); } }