diff --git a/examples/run_return.rs b/examples/run_return.rs new file mode 100644 index 000000000..d93b9aa81 --- /dev/null +++ b/examples/run_return.rs @@ -0,0 +1,41 @@ +extern crate winit; +use winit::platform::desktop::EventLoopExtDesktop; + +fn main() { + let mut events_loop = winit::EventLoop::new(); + + let window = winit::WindowBuilder::new() + .with_title("A fantastic window!") + .build(&events_loop) + .unwrap(); + + println!("Close the window to continue."); + events_loop.run_return(|event, _, control_flow| { + match event { + winit::Event::WindowEvent { + event: winit::WindowEvent::CloseRequested, + .. + } => *control_flow = winit::ControlFlow::Exit, + _ => *control_flow = winit::ControlFlow::Wait, + } + }); + drop(window); + + let _window_2 = winit::WindowBuilder::new() + .with_title("A second, fantasticer window!") + .build(&events_loop) + .unwrap(); + + println!("Wa ha ha! You thought that closing the window would finish this?!"); + events_loop.run_return(|event, _, control_flow| { + match event { + winit::Event::WindowEvent { + event: winit::WindowEvent::CloseRequested, + .. + } => *control_flow = winit::ControlFlow::Exit, + _ => *control_flow = winit::ControlFlow::Wait, + } + }); + + println!("Okay we're done now for real."); +} diff --git a/src/platform/desktop.rs b/src/platform/desktop.rs new file mode 100644 index 000000000..5ab9be666 --- /dev/null +++ b/src/platform/desktop.rs @@ -0,0 +1,28 @@ +#![cfg(any( + target_os = "windows", + target_os = "macos", + target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd" +))] + +use {EventLoop, Event, ControlFlow}; + +/// Additional methods on `EventLoop` that are specific to desktop platforms. +pub trait EventLoopExtDesktop { + type UserEvent; + /// Initializes the `winit` event loop. + /// + /// Unlikes `run`, this function *does* return control flow to the caller when `control_flow` + /// is set to `ControlFlow::Exit`. + fn run_return(&mut self, event_handler: F) + where F: FnMut(Event, &EventLoop, &mut ControlFlow); +} + +impl EventLoopExtDesktop for EventLoop { + type UserEvent = T; + + fn run_return(&mut self, event_handler: F) + where F: FnMut(Event, &EventLoop, &mut ControlFlow) + { + self.events_loop.run_return(event_handler) + } +} diff --git a/src/platform/mod.rs b/src/platform/mod.rs index 249676956..27ce048d9 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -15,3 +15,5 @@ pub mod ios; pub mod macos; pub mod unix; pub mod windows; + +pub mod desktop; diff --git a/src/platform_impl/windows/events_loop.rs b/src/platform_impl/windows/events_loop.rs index f367abf7a..dba70c059 100644 --- a/src/platform_impl/windows/events_loop.rs +++ b/src/platform_impl/windows/events_loop.rs @@ -182,35 +182,44 @@ impl EventLoop { } } - pub fn run(self, mut event_handler: F) -> ! + pub fn run(mut self, event_handler: F) -> ! where F: 'static + FnMut(Event, &::EventLoop, &mut ControlFlow) { - unsafe { - winuser::IsGUIThread(1); + self.run_return(event_handler); + ::std::process::exit(0); + } - let mut runner = EventLoopRunner { - event_loop: ::EventLoop { - events_loop: self, - _marker: ::std::marker::PhantomData - }, - control_flow: ControlFlow::default(), - runner_state: RunnerState::New, - modal_loop_data: None, - event_handler: &mut event_handler - }; - { - let runner_shared = runner.event_loop.events_loop.runner_shared.clone(); - let mut runner_shared = runner_shared.borrow_mut(); - let mut event_buffer = vec![]; - if let ELRSharedOption::Buffer(ref mut buffer) = *runner_shared { - mem::swap(buffer, &mut event_buffer); - } - for event in event_buffer.drain(..) { - runner.process_event(event); - } - *runner_shared = ELRSharedOption::Runner(&mut runner); + pub fn run_return(&mut self, mut event_handler: F) + where F: FnMut(Event, &::EventLoop, &mut ControlFlow) + { + unsafe{ winuser::IsGUIThread(1); } + let mut runner = EventLoopRunner { + event_loop: self, + control_flow: ControlFlow::default(), + runner_state: RunnerState::New, + modal_loop_data: None, + event_handler: unsafe { + // Transmute used to erase lifetimes. + mem::transmute::< + &mut FnMut(Event, &::EventLoop, &mut ControlFlow), + *mut FnMut(Event, &::EventLoop, &mut ControlFlow) + >(&mut event_handler) } + }; + { + let runner_shared = self.runner_shared.clone(); + let mut runner_shared = runner_shared.borrow_mut(); + let mut event_buffer = vec![]; + if let ELRSharedOption::Buffer(ref mut buffer) = *runner_shared { + mem::swap(buffer, &mut event_buffer); + } + for event in event_buffer.drain(..) { + unsafe{ runner.process_event(event); } + } + *runner_shared = ELRSharedOption::Runner(&mut runner); + } + unsafe { let timer_handle = winuser::SetTimer(ptr::null_mut(), 0, 0x7FFFFFFF, None); let mut msg = mem::uninitialized(); @@ -253,13 +262,10 @@ impl EventLoop { ControlFlow::Poll => () } } - - runner.call_event_handler(Event::LoopDestroyed); - *runner.event_loop.events_loop.runner_shared.borrow_mut() = ELRSharedOption::Buffer(vec![]); } - drop(event_handler); - ::std::process::exit(0); + unsafe{ runner.call_event_handler(Event::LoopDestroyed) } + *self.runner_shared.borrow_mut() = ELRSharedOption::Buffer(vec![]); } pub fn create_proxy(&self) -> EventLoopProxy { @@ -284,7 +290,7 @@ pub(crate) enum ELRSharedOption { Buffer(Vec>) } pub(crate) struct EventLoopRunner { - event_loop: ::EventLoop, + event_loop: *const EventLoop, control_flow: ControlFlow, runner_state: RunnerState, modal_loop_data: Option, @@ -457,15 +463,18 @@ impl EventLoopRunner { unsafe fn call_event_handler(&mut self, event: Event) { if self.event_handler != mem::zeroed() { match event { - Event::NewEvents(_) => self.event_loop.events_loop.trigger_newevents_on_redraw.store(true, Ordering::Relaxed), - Event::EventsCleared => self.event_loop.events_loop.trigger_newevents_on_redraw.store(false, Ordering::Relaxed), + Event::NewEvents(_) => (*self.event_loop).trigger_newevents_on_redraw.store(true, Ordering::Relaxed), + Event::EventsCleared => (*self.event_loop).trigger_newevents_on_redraw.store(false, Ordering::Relaxed), _ => () } + assert_eq!(mem::size_of::<::EventLoop>(), mem::size_of::>()); + let event_loop_ref = &*(self.event_loop as *const ::EventLoop); + if self.control_flow != ControlFlow::Exit { - (*self.event_handler)(event, &self.event_loop, &mut self.control_flow); + (*self.event_handler)(event, event_loop_ref, &mut self.control_flow); } else { - (*self.event_handler)(event, &self.event_loop, &mut ControlFlow::Exit); + (*self.event_handler)(event, event_loop_ref, &mut ControlFlow::Exit); } } else { panic!("Tried to call event handler with null handler");