Allow calling winit with the 'run_return' variant of the run function (#243)

This adds a new WinitConfig resource that can be used to configure the behavior of winit.
When `return_from_run` is set to `true`, `App::run()` will return on `target_os` configurations that
support it.

Closes bevyengine/bevy#167.
This commit is contained in:
Jake Kerr 2020-08-21 14:37:19 +09:00 committed by GitHub
parent 505c79b60d
commit db1bf6478c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 104 additions and 6 deletions

View file

@ -123,6 +123,10 @@ path = "examples/app/headless.rs"
name = "plugin"
path = "examples/app/plugin.rs"
[[example]]
name = "return_after_run"
path = "examples/app/return_after_run.rs"
[[example]]
name = "thread_pool_resources"
path = "examples/app/thread_pool_resources.rs"
@ -221,4 +225,4 @@ path = "examples/window/multiple_windows.rs"
[[example]]
name = "window_settings"
path = "examples/window/window_settings.rs"
path = "examples/window/window_settings.rs"

View file

@ -1,11 +1,12 @@
mod converters;
mod winit_config;
mod winit_windows;
pub use winit_windows::*;
use bevy_input::{
keyboard::KeyboardInput,
mouse::{MouseButtonInput, MouseMotion, MouseScrollUnit, MouseWheel},
};
pub use winit_config::*;
pub use winit_windows::*;
use bevy_app::{prelude::*, AppExit};
use bevy_ecs::Resources;
@ -13,6 +14,7 @@ use bevy_math::Vec2;
use bevy_window::{
CreateWindow, CursorMoved, Window, WindowCloseRequested, WindowCreated, WindowResized, Windows,
};
use event::Event;
use winit::{
event,
event::{DeviceEvent, WindowEvent},
@ -33,8 +35,51 @@ impl Plugin for WinitPlugin {
}
}
fn run<F>(event_loop: EventLoop<()>, event_handler: F) -> !
where
F: 'static + FnMut(Event<'_, ()>, &EventLoopWindowTarget<()>, &mut ControlFlow),
{
event_loop.run(event_handler)
}
// TODO: It may be worth moving this cfg into a procedural macro so that it can be referenced by
// a single name instead of being copied around.
// https://gist.github.com/jakerr/231dee4a138f7a5f25148ea8f39b382e seems to work.
#[cfg(any(
target_os = "windows",
target_os = "macos",
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd"
))]
fn run_return<F>(event_loop: &mut EventLoop<()>, event_handler: F)
where
F: FnMut(Event<'_, ()>, &EventLoopWindowTarget<()>, &mut ControlFlow),
{
use winit::platform::desktop::EventLoopExtDesktop;
event_loop.run_return(event_handler)
}
#[cfg(not(any(
target_os = "windows",
target_os = "macos",
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd"
)))]
fn run_return<F>(event_loop: &mut EventLoop<()>, event_handler: F)
where
F: FnMut(Event<'_, ()>, &EventLoopWindowTarget<()>, &mut ControlFlow),
{
panic!("Run return is not supported on this platform!")
}
pub fn winit_runner(mut app: App) {
let event_loop = EventLoop::new();
let mut event_loop = EventLoop::new();
let mut create_window_event_reader = EventReader::<CreateWindow>::default();
let mut app_exit_event_reader = EventReader::<AppExit>::default();
@ -45,7 +90,15 @@ pub fn winit_runner(mut app: App) {
);
log::debug!("Entering winit event loop");
event_loop.run(move |event, event_loop, control_flow| {
let should_return_from_run = app
.resources
.get::<WinitConfig>()
.map_or(false, |config| config.return_from_run);
let event_handler = move |event: Event<()>,
event_loop: &EventLoopWindowTarget<()>,
control_flow: &mut ControlFlow| {
*control_flow = if cfg!(feature = "metal-auto-capture") {
ControlFlow::Exit
} else {
@ -160,7 +213,12 @@ pub fn winit_runner(mut app: App) {
}
_ => (),
}
});
};
if should_return_from_run {
run_return(&mut event_loop, event_handler);
} else {
run(event_loop, event_handler);
}
}
fn handle_create_window_events(

View file

@ -0,0 +1,15 @@
/// A resource for configuring usage of the `rust_winit` library.
#[derive(Default)]
pub struct WinitConfig {
/// Configures the winit library to return control to the main thread after
/// the [run](bevy_app::App::run) loop is exited. Winit strongly recommends
/// avoiding this when possible. Before using this please read and understand
/// the [caveats](winit::platform::desktop::EventLoopExtDesktop::run_return)
/// in the winit documentation.
///
/// This feature is only available on desktop `target_os` configurations.
/// Namely `windows`, `macos`, `linux`, `dragonfly`, `freebsd`, `netbsd`, and
/// `openbsd`. If set to true on an unsupported platform
/// [run](bevy_app::App::run) will panic.
pub return_from_run: bool,
}

View file

@ -0,0 +1,21 @@
use bevy::{prelude::*, render::pass::ClearColor, winit::WinitConfig};
fn main() {
println!("Running first App.");
App::build()
.add_resource(WinitConfig {
return_from_run: true,
})
.add_resource(ClearColor(Color::rgb(0.2, 0.2, 0.8)))
.add_default_plugins()
.run();
println!("Running another App.");
App::build()
.add_resource(WinitConfig {
return_from_run: true,
})
.add_resource(ClearColor(Color::rgb(0.2, 0.8, 0.2)))
.add_default_plugins()
.run();
println!("Done.");
}