Skip to content

Commit

Permalink
Add platform::desktop module with EventLoopExt::run_return
Browse files Browse the repository at this point in the history
  • Loading branch information
Osspial committed Nov 9, 2018
1 parent dad24d0 commit f20fac9
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 34 deletions.
41 changes: 41 additions & 0 deletions examples/run_return.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 28 additions & 0 deletions src/platform/desktop.rs
Original file line number Diff line number Diff line change
@@ -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)
}
}
2 changes: 2 additions & 0 deletions src/platform/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@ pub mod ios;
pub mod macos;
pub mod unix;
pub mod windows;

pub mod desktop;
77 changes: 43 additions & 34 deletions src/platform_impl/windows/events_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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> {
Expand All @@ -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>,
Expand Down Expand Up @@ -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");
Expand Down

0 comments on commit f20fac9

Please sign in to comment.