Add platform::desktop module with EventLoopExt::run_return

This commit is contained in:
Osspial
2018-08-22 22:07:39 -04:00
parent dad24d086a
commit f20fac99f6
4 changed files with 114 additions and 34 deletions

41
examples/run_return.rs Normal file
View File

@@ -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.");
}

28
src/platform/desktop.rs Normal file
View File

@@ -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<F>(&mut self, event_handler: F)
where F: FnMut(Event<Self::UserEvent>, &EventLoop<Self::UserEvent>, &mut ControlFlow);
}
impl<T> EventLoopExtDesktop for EventLoop<T> {
type UserEvent = T;
fn run_return<F>(&mut self, event_handler: F)
where F: FnMut(Event<T>, &EventLoop<T>, &mut ControlFlow)
{
self.events_loop.run_return(event_handler)
}
}

View File

@@ -15,3 +15,5 @@ pub mod ios;
pub mod macos;
pub mod unix;
pub mod windows;
pub mod desktop;

View File

@@ -182,35 +182,44 @@ impl<T> EventLoop<T> {
}
}
pub fn run<F>(self, mut event_handler: F) -> !
pub fn run<F>(mut self, event_handler: F) -> !
where F: 'static + FnMut(Event<T>, &::EventLoop<T>, &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<F>(&mut self, mut event_handler: F)
where F: FnMut(Event<T>, &::EventLoop<T>, &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<T>, &::EventLoop<T>, &mut ControlFlow),
*mut FnMut(Event<T>, &::EventLoop<T>, &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<T> EventLoop<T> {
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<T> {
@@ -284,7 +290,7 @@ pub(crate) enum ELRSharedOption<T> {
Buffer(Vec<Event<T>>)
}
pub(crate) struct EventLoopRunner<T> {
event_loop: ::EventLoop<T>,
event_loop: *const EventLoop<T>,
control_flow: ControlFlow,
runner_state: RunnerState,
modal_loop_data: Option<ModalLoopData>,
@@ -457,15 +463,18 @@ impl<T> EventLoopRunner<T> {
unsafe fn call_event_handler(&mut self, event: Event<T>) {
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<T>>(), mem::size_of::<EventLoop<T>>());
let event_loop_ref = &*(self.event_loop as *const ::EventLoop<T>);
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");