mirror of
https://github.com/rust-windowing/winit.git
synced 2026-06-26 14:49:07 -04:00
Add initialization closure and drop on exit
This commit is contained in:
@@ -13,26 +13,12 @@ fn main() -> Result<(), impl std::error::Error> {
|
|||||||
#[path = "util/fill.rs"]
|
#[path = "util/fill.rs"]
|
||||||
mod fill;
|
mod fill;
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
struct Application {
|
struct Application {
|
||||||
parent_window_id: Option<WindowId>,
|
parent_window_id: WindowId,
|
||||||
windows: HashMap<WindowId, Box<dyn Window>>,
|
windows: HashMap<WindowId, Box<dyn Window>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ApplicationHandler for Application {
|
impl ApplicationHandler for Application {
|
||||||
fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) {
|
|
||||||
let attributes = WindowAttributes::default()
|
|
||||||
.with_title("parent window")
|
|
||||||
.with_position(Position::Logical(LogicalPosition::new(0.0, 0.0)))
|
|
||||||
.with_surface_size(LogicalSize::new(640.0f32, 480.0f32));
|
|
||||||
let window = event_loop.create_window(attributes).unwrap();
|
|
||||||
|
|
||||||
println!("Parent window id: {:?})", window.id());
|
|
||||||
self.parent_window_id = Some(window.id());
|
|
||||||
|
|
||||||
self.windows.insert(window.id(), window);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn window_event(
|
fn window_event(
|
||||||
&mut self,
|
&mut self,
|
||||||
event_loop: &dyn ActiveEventLoop,
|
event_loop: &dyn ActiveEventLoop,
|
||||||
@@ -56,7 +42,7 @@ fn main() -> Result<(), impl std::error::Error> {
|
|||||||
event: KeyEvent { state: ElementState::Pressed, .. },
|
event: KeyEvent { state: ElementState::Pressed, .. },
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let parent_window = self.windows.get(&self.parent_window_id.unwrap()).unwrap();
|
let parent_window = self.windows.get(&self.parent_window_id).unwrap();
|
||||||
let child_window = spawn_child_window(parent_window.as_ref(), event_loop);
|
let child_window = spawn_child_window(parent_window.as_ref(), event_loop);
|
||||||
let child_id = child_window.id();
|
let child_id = child_window.id();
|
||||||
println!("Child window created with id: {child_id:?}");
|
println!("Child window created with id: {child_id:?}");
|
||||||
@@ -72,6 +58,20 @@ fn main() -> Result<(), impl std::error::Error> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn init(event_loop: &dyn ActiveEventLoop) -> Application {
|
||||||
|
let attributes = WindowAttributes::default()
|
||||||
|
.with_title("parent window")
|
||||||
|
.with_position(Position::Logical(LogicalPosition::new(0.0, 0.0)))
|
||||||
|
.with_surface_size(LogicalSize::new(640.0f32, 480.0f32));
|
||||||
|
let window = event_loop.create_window(attributes).unwrap();
|
||||||
|
|
||||||
|
println!("Parent window id: {:?})", window.id());
|
||||||
|
|
||||||
|
let parent_window_id = window.id();
|
||||||
|
let windows = HashMap::from([(window.id(), window)]);
|
||||||
|
Application { parent_window_id, windows }
|
||||||
|
}
|
||||||
|
|
||||||
fn spawn_child_window(
|
fn spawn_child_window(
|
||||||
parent: &dyn Window,
|
parent: &dyn Window,
|
||||||
event_loop: &dyn ActiveEventLoop,
|
event_loop: &dyn ActiveEventLoop,
|
||||||
@@ -89,7 +89,7 @@ fn main() -> Result<(), impl std::error::Error> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let event_loop = EventLoop::new().unwrap();
|
let event_loop = EventLoop::new().unwrap();
|
||||||
event_loop.run_app(Application::default())
|
event_loop.run(init)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(x11_platform, macos_platform, windows_platform)))]
|
#[cfg(not(any(x11_platform, macos_platform, windows_platform)))]
|
||||||
|
|||||||
@@ -43,16 +43,31 @@ fn main() -> Result<(), impl std::error::Error> {
|
|||||||
|
|
||||||
let event_loop = EventLoop::new().unwrap();
|
let event_loop = EventLoop::new().unwrap();
|
||||||
|
|
||||||
event_loop.run_app(ControlFlowDemo::default())
|
event_loop.run(ControlFlowDemo::new)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
struct ControlFlowDemo {
|
struct ControlFlowDemo {
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
request_redraw: bool,
|
request_redraw: bool,
|
||||||
wait_cancelled: bool,
|
wait_cancelled: bool,
|
||||||
close_requested: bool,
|
close_requested: bool,
|
||||||
window: Option<Box<dyn Window>>,
|
window: Box<dyn Window>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ControlFlowDemo {
|
||||||
|
fn new(event_loop: &dyn ActiveEventLoop) -> Self {
|
||||||
|
let window_attributes = WindowAttributes::default().with_title(
|
||||||
|
"Press 1, 2, 3 to change control flow mode. Press R to toggle redraw requests.",
|
||||||
|
);
|
||||||
|
let window = event_loop.create_window(window_attributes).unwrap();
|
||||||
|
Self {
|
||||||
|
mode: Mode::default(),
|
||||||
|
request_redraw: false,
|
||||||
|
wait_cancelled: false,
|
||||||
|
close_requested: false,
|
||||||
|
window,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ApplicationHandler for ControlFlowDemo {
|
impl ApplicationHandler for ControlFlowDemo {
|
||||||
@@ -65,13 +80,6 @@ impl ApplicationHandler for ControlFlowDemo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) {
|
|
||||||
let window_attributes = WindowAttributes::default().with_title(
|
|
||||||
"Press 1, 2, 3 to change control flow mode. Press R to toggle redraw requests.",
|
|
||||||
);
|
|
||||||
self.window = Some(event_loop.create_window(window_attributes).unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
fn window_event(
|
fn window_event(
|
||||||
&mut self,
|
&mut self,
|
||||||
_event_loop: &dyn ActiveEventLoop,
|
_event_loop: &dyn ActiveEventLoop,
|
||||||
@@ -112,9 +120,8 @@ impl ApplicationHandler for ControlFlowDemo {
|
|||||||
_ => (),
|
_ => (),
|
||||||
},
|
},
|
||||||
WindowEvent::RedrawRequested => {
|
WindowEvent::RedrawRequested => {
|
||||||
let window = self.window.as_ref().unwrap();
|
self.window.pre_present_notify();
|
||||||
window.pre_present_notify();
|
fill::fill_window(&*self.window);
|
||||||
fill::fill_window(window.as_ref());
|
|
||||||
},
|
},
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
@@ -122,7 +129,7 @@ impl ApplicationHandler for ControlFlowDemo {
|
|||||||
|
|
||||||
fn about_to_wait(&mut self, event_loop: &dyn ActiveEventLoop) {
|
fn about_to_wait(&mut self, event_loop: &dyn ActiveEventLoop) {
|
||||||
if self.request_redraw && !self.wait_cancelled && !self.close_requested {
|
if self.request_redraw && !self.wait_cancelled && !self.close_requested {
|
||||||
self.window.as_ref().unwrap().request_redraw();
|
self.window.request_redraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.mode {
|
match self.mode {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ fn main() -> std::process::ExitCode {
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use winit::application::ApplicationHandler;
|
use winit::application::ApplicationHandler;
|
||||||
use winit::event::WindowEvent;
|
use winit::event::{StartCause, WindowEvent};
|
||||||
use winit::event_loop::{ActiveEventLoop, EventLoop};
|
use winit::event_loop::{ActiveEventLoop, EventLoop};
|
||||||
use winit::platform::pump_events::{EventLoopExtPumpEvents, PumpStatus};
|
use winit::platform::pump_events::{EventLoopExtPumpEvents, PumpStatus};
|
||||||
use winit::window::{Window, WindowAttributes, WindowId};
|
use winit::window::{Window, WindowAttributes, WindowId};
|
||||||
@@ -22,9 +22,12 @@ fn main() -> std::process::ExitCode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ApplicationHandler for PumpDemo {
|
impl ApplicationHandler for PumpDemo {
|
||||||
fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) {
|
fn new_events(&mut self, event_loop: &dyn ActiveEventLoop, cause: StartCause) {
|
||||||
let window_attributes = WindowAttributes::default().with_title("A fantastic window!");
|
if matches!(cause, StartCause::Init) && self.window.is_none() {
|
||||||
self.window = Some(event_loop.create_window(window_attributes).unwrap());
|
let window_attributes =
|
||||||
|
WindowAttributes::default().with_title("A fantastic window!");
|
||||||
|
self.window = Some(event_loop.create_window(window_attributes).unwrap());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn window_event(
|
fn window_event(
|
||||||
|
|||||||
@@ -21,14 +21,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
window: Option<Box<dyn Window>>,
|
window: Option<Box<dyn Window>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ApplicationHandler for App {
|
impl App {
|
||||||
fn about_to_wait(&mut self, _event_loop: &dyn ActiveEventLoop) {
|
fn init_window(&mut self, event_loop: &dyn ActiveEventLoop) {
|
||||||
if let Some(window) = self.window.as_ref() {
|
|
||||||
window.request_redraw();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) {
|
|
||||||
let window_attributes = WindowAttributes::default()
|
let window_attributes = WindowAttributes::default()
|
||||||
.with_title("Fantastic window number one!")
|
.with_title("Fantastic window number one!")
|
||||||
.with_surface_size(winit::dpi::LogicalSize::new(128.0, 128.0));
|
.with_surface_size(winit::dpi::LogicalSize::new(128.0, 128.0));
|
||||||
@@ -36,6 +30,14 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
self.window_id = Some(window.id());
|
self.window_id = Some(window.id());
|
||||||
self.window = Some(window);
|
self.window = Some(window);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ApplicationHandler for App {
|
||||||
|
fn about_to_wait(&mut self, _event_loop: &dyn ActiveEventLoop) {
|
||||||
|
if let Some(window) = self.window.as_ref() {
|
||||||
|
window.request_redraw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn window_event(
|
fn window_event(
|
||||||
&mut self,
|
&mut self,
|
||||||
@@ -81,14 +83,20 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
let mut event_loop = EventLoop::new().unwrap();
|
let mut event_loop = EventLoop::new().unwrap();
|
||||||
|
|
||||||
let mut app = App { idx: 1, ..Default::default() };
|
let mut app = App { idx: 1, ..Default::default() };
|
||||||
event_loop.run_app_on_demand(&mut app)?;
|
event_loop.run_on_demand(|event_loop| {
|
||||||
|
app.init_window(event_loop);
|
||||||
|
&mut app
|
||||||
|
})?;
|
||||||
|
|
||||||
println!("--------------------------------------------------------- Finished first loop");
|
println!("--------------------------------------------------------- Finished first loop");
|
||||||
println!("--------------------------------------------------------- Waiting 5 seconds");
|
println!("--------------------------------------------------------- Waiting 5 seconds");
|
||||||
std::thread::sleep(Duration::from_secs(5));
|
std::thread::sleep(Duration::from_secs(5));
|
||||||
|
|
||||||
app.idx += 1;
|
app.idx += 1;
|
||||||
event_loop.run_app_on_demand(&mut app)?;
|
event_loop.run_on_demand(|event_loop| {
|
||||||
|
app.init_window(event_loop);
|
||||||
|
&mut app
|
||||||
|
})?;
|
||||||
println!("--------------------------------------------------------- Finished second loop");
|
println!("--------------------------------------------------------- Finished second loop");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,8 +70,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let app = Application::new(&event_loop, receiver, sender);
|
Ok(event_loop.run(|event_loop| Application::new(event_loop, receiver, sender))?)
|
||||||
Ok(event_loop.run_app(app)?)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Application state and event handling.
|
/// Application state and event handling.
|
||||||
@@ -88,21 +87,24 @@ struct Application {
|
|||||||
///
|
///
|
||||||
/// With OpenGL it could be EGLDisplay.
|
/// With OpenGL it could be EGLDisplay.
|
||||||
#[cfg(not(android_platform))]
|
#[cfg(not(android_platform))]
|
||||||
context: Option<Context<DisplayHandle<'static>>>,
|
context: Context<DisplayHandle<'static>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Application {
|
impl Application {
|
||||||
fn new(event_loop: &EventLoop, receiver: Receiver<Action>, sender: Sender<Action>) -> Self {
|
fn new(
|
||||||
// SAFETY: we drop the context right before the event loop is stopped, thus making it safe.
|
event_loop: &dyn ActiveEventLoop,
|
||||||
|
receiver: Receiver<Action>,
|
||||||
|
sender: Sender<Action>,
|
||||||
|
) -> Self {
|
||||||
|
// SAFETY: The context is stored in the application, which is dropped right before the event
|
||||||
|
// loop is stopped, thus making it safe.
|
||||||
#[cfg(not(android_platform))]
|
#[cfg(not(android_platform))]
|
||||||
let context = Some(
|
let context = Context::new(unsafe {
|
||||||
Context::new(unsafe {
|
std::mem::transmute::<DisplayHandle<'_>, DisplayHandle<'static>>(
|
||||||
std::mem::transmute::<DisplayHandle<'_>, DisplayHandle<'static>>(
|
event_loop.display_handle().unwrap(),
|
||||||
event_loop.display_handle().unwrap(),
|
)
|
||||||
)
|
})
|
||||||
})
|
.unwrap();
|
||||||
.unwrap(),
|
|
||||||
);
|
|
||||||
|
|
||||||
// You'll have to choose an icon size at your own discretion. On X11, the desired size
|
// You'll have to choose an icon size at your own discretion. On X11, the desired size
|
||||||
// varies by WM, and on Windows, you still have to account for screen scaling. Here
|
// varies by WM, and on Windows, you still have to account for screen scaling. Here
|
||||||
@@ -120,7 +122,7 @@ impl Application {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
Self {
|
let mut app = Self {
|
||||||
receiver,
|
receiver,
|
||||||
sender,
|
sender,
|
||||||
#[cfg(not(android_platform))]
|
#[cfg(not(android_platform))]
|
||||||
@@ -128,7 +130,16 @@ impl Application {
|
|||||||
custom_cursors,
|
custom_cursors,
|
||||||
icon,
|
icon,
|
||||||
windows: Default::default(),
|
windows: Default::default(),
|
||||||
}
|
};
|
||||||
|
|
||||||
|
app.dump_monitors(event_loop);
|
||||||
|
|
||||||
|
// Create initial window.
|
||||||
|
app.create_window(event_loop, None).expect("failed to create initial window");
|
||||||
|
|
||||||
|
app.print_help();
|
||||||
|
|
||||||
|
app
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_window(
|
fn create_window(
|
||||||
@@ -560,14 +571,12 @@ impl ApplicationHandler for Application {
|
|||||||
info!("Device {device_id:?} event: {event:?}");
|
info!("Device {device_id:?} event: {event:?}");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) {
|
#[cfg(not(android_platform))]
|
||||||
info!("Ready to create surfaces");
|
fn can_create_surfaces(&mut self, _event_loop: &dyn ActiveEventLoop) {
|
||||||
self.dump_monitors(event_loop);
|
for window in self.windows.values_mut() {
|
||||||
|
window.surface = Some(Surface::new(&self.context, Arc::clone(&window.window)).unwrap());
|
||||||
// Create initial window.
|
window.resize(window.window.surface_size());
|
||||||
self.create_window(event_loop, None).expect("failed to create initial window");
|
}
|
||||||
|
|
||||||
self.print_help();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn about_to_wait(&mut self, event_loop: &dyn ActiveEventLoop) {
|
fn about_to_wait(&mut self, event_loop: &dyn ActiveEventLoop) {
|
||||||
@@ -578,9 +587,10 @@ impl ApplicationHandler for Application {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(android_platform))]
|
#[cfg(not(android_platform))]
|
||||||
fn exiting(&mut self, _event_loop: &dyn ActiveEventLoop) {
|
fn destroy_surfaces(&mut self, _event_loop: &dyn ActiveEventLoop) {
|
||||||
// We must drop the context here.
|
for window in self.windows.values_mut() {
|
||||||
self.context = None;
|
window.surface = None;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
@@ -607,9 +617,9 @@ struct WindowState {
|
|||||||
ime: bool,
|
ime: bool,
|
||||||
/// Render surface.
|
/// Render surface.
|
||||||
///
|
///
|
||||||
/// NOTE: This surface must be dropped before the `Window`.
|
/// `None` when not between `can_create_surfaces` and `destroy_surfaces`.
|
||||||
#[cfg(not(android_platform))]
|
#[cfg(not(android_platform))]
|
||||||
surface: Surface<DisplayHandle<'static>, Arc<dyn Window>>,
|
surface: Option<Surface<DisplayHandle<'static>, Arc<dyn Window>>>,
|
||||||
/// The actual winit Window.
|
/// The actual winit Window.
|
||||||
window: Arc<dyn Window>,
|
window: Arc<dyn Window>,
|
||||||
/// The window theme we're drawing with.
|
/// The window theme we're drawing with.
|
||||||
@@ -642,11 +652,6 @@ impl WindowState {
|
|||||||
fn new(app: &Application, window: Box<dyn Window>) -> Result<Self, Box<dyn Error>> {
|
fn new(app: &Application, window: Box<dyn Window>) -> Result<Self, Box<dyn Error>> {
|
||||||
let window: Arc<dyn Window> = Arc::from(window);
|
let window: Arc<dyn Window> = Arc::from(window);
|
||||||
|
|
||||||
// SAFETY: the surface is dropped before the `window` which provided it with handle, thus
|
|
||||||
// it doesn't outlive it.
|
|
||||||
#[cfg(not(android_platform))]
|
|
||||||
let surface = Surface::new(app.context.as_ref().unwrap(), Arc::clone(&window))?;
|
|
||||||
|
|
||||||
let theme = window.theme().unwrap_or(Theme::Dark);
|
let theme = window.theme().unwrap_or(Theme::Dark);
|
||||||
info!("Theme: {theme:?}");
|
info!("Theme: {theme:?}");
|
||||||
let named_idx = 0;
|
let named_idx = 0;
|
||||||
@@ -656,15 +661,14 @@ impl WindowState {
|
|||||||
let ime = true;
|
let ime = true;
|
||||||
window.set_ime_allowed(ime);
|
window.set_ime_allowed(ime);
|
||||||
|
|
||||||
let size = window.surface_size();
|
Ok(Self {
|
||||||
let mut state = Self {
|
|
||||||
#[cfg(macos_platform)]
|
#[cfg(macos_platform)]
|
||||||
option_as_alt: window.option_as_alt(),
|
option_as_alt: window.option_as_alt(),
|
||||||
custom_idx: app.custom_cursors.as_ref().map(Vec::len).unwrap_or(1) - 1,
|
custom_idx: app.custom_cursors.as_ref().map(Vec::len).unwrap_or(1) - 1,
|
||||||
cursor_grab: CursorGrabMode::None,
|
cursor_grab: CursorGrabMode::None,
|
||||||
named_idx,
|
named_idx,
|
||||||
#[cfg(not(android_platform))]
|
#[cfg(not(android_platform))]
|
||||||
surface,
|
surface: None,
|
||||||
window,
|
window,
|
||||||
theme,
|
theme,
|
||||||
ime,
|
ime,
|
||||||
@@ -675,10 +679,7 @@ impl WindowState {
|
|||||||
rotated: Default::default(),
|
rotated: Default::default(),
|
||||||
panned: Default::default(),
|
panned: Default::default(),
|
||||||
zoom: Default::default(),
|
zoom: Default::default(),
|
||||||
};
|
})
|
||||||
|
|
||||||
state.resize(size);
|
|
||||||
Ok(state)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn toggle_ime(&mut self) {
|
pub fn toggle_ime(&mut self) {
|
||||||
@@ -852,7 +853,11 @@ impl WindowState {
|
|||||||
(Some(width), Some(height)) => (width, height),
|
(Some(width), Some(height)) => (width, height),
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
self.surface.resize(width, height).expect("failed to resize inner buffer");
|
self.surface
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.resize(width, height)
|
||||||
|
.expect("failed to resize inner buffer");
|
||||||
}
|
}
|
||||||
self.window.request_redraw();
|
self.window.request_redraw();
|
||||||
}
|
}
|
||||||
@@ -945,7 +950,7 @@ impl WindowState {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut buffer = self.surface.buffer_mut()?;
|
let mut buffer = self.surface.as_mut().unwrap().buffer_mut()?;
|
||||||
|
|
||||||
// Draw a different color inside the safe area
|
// Draw a different color inside the safe area
|
||||||
let surface_size = self.window.surface_size();
|
let surface_size = self.window.surface_size();
|
||||||
|
|||||||
@@ -13,39 +13,28 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
mod fill;
|
mod fill;
|
||||||
|
|
||||||
pub struct XEmbedDemo {
|
pub struct XEmbedDemo {
|
||||||
parent_window_id: u32,
|
window: Box<dyn Window>,
|
||||||
window: Option<Box<dyn Window>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ApplicationHandler for XEmbedDemo {
|
impl ApplicationHandler for XEmbedDemo {
|
||||||
fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) {
|
|
||||||
let window_attributes = WindowAttributes::default()
|
|
||||||
.with_title("An embedded window!")
|
|
||||||
.with_surface_size(winit::dpi::LogicalSize::new(128.0, 128.0))
|
|
||||||
.with_embed_parent_window(self.parent_window_id);
|
|
||||||
|
|
||||||
self.window = Some(event_loop.create_window(window_attributes).unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
fn window_event(
|
fn window_event(
|
||||||
&mut self,
|
&mut self,
|
||||||
event_loop: &dyn ActiveEventLoop,
|
event_loop: &dyn ActiveEventLoop,
|
||||||
_window_id: WindowId,
|
_window_id: WindowId,
|
||||||
event: WindowEvent,
|
event: WindowEvent,
|
||||||
) {
|
) {
|
||||||
let window = self.window.as_ref().unwrap();
|
|
||||||
match event {
|
match event {
|
||||||
WindowEvent::CloseRequested => event_loop.exit(),
|
WindowEvent::CloseRequested => event_loop.exit(),
|
||||||
WindowEvent::RedrawRequested => {
|
WindowEvent::RedrawRequested => {
|
||||||
window.pre_present_notify();
|
self.window.pre_present_notify();
|
||||||
fill::fill_window(window.as_ref());
|
fill::fill_window(&*self.window);
|
||||||
},
|
},
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn about_to_wait(&mut self, _event_loop: &dyn ActiveEventLoop) {
|
fn about_to_wait(&mut self, _event_loop: &dyn ActiveEventLoop) {
|
||||||
self.window.as_ref().unwrap().request_redraw();
|
self.window.request_redraw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,7 +47,15 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
tracing_subscriber::fmt::init();
|
tracing_subscriber::fmt::init();
|
||||||
let event_loop = EventLoop::new()?;
|
let event_loop = EventLoop::new()?;
|
||||||
|
|
||||||
Ok(event_loop.run_app(XEmbedDemo { parent_window_id, window: None })?)
|
Ok(event_loop.run(|event_loop| {
|
||||||
|
let window_attributes = WindowAttributes::default()
|
||||||
|
.with_title("An embedded window!")
|
||||||
|
.with_surface_size(winit::dpi::LogicalSize::new(128.0, 128.0))
|
||||||
|
.with_embed_parent_window(parent_window_id);
|
||||||
|
|
||||||
|
let window = event_loop.create_window(window_attributes).unwrap();
|
||||||
|
XEmbedDemo { window }
|
||||||
|
})?)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(x11_platform))]
|
#[cfg(not(x11_platform))]
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ use crate::platform::macos::ApplicationHandlerExtMacOS;
|
|||||||
use crate::window::WindowId;
|
use crate::window::WindowId;
|
||||||
|
|
||||||
/// The handler of the application events.
|
/// The handler of the application events.
|
||||||
|
///
|
||||||
|
/// This is [dropped][std::ops::Drop] when the event loop is being shut down.
|
||||||
pub trait ApplicationHandler {
|
pub trait ApplicationHandler {
|
||||||
/// Emitted when new events arrive from the OS to be processed.
|
/// Emitted when new events arrive from the OS to be processed.
|
||||||
///
|
///
|
||||||
@@ -101,7 +103,9 @@ pub trait ApplicationHandler {
|
|||||||
///
|
///
|
||||||
/// [`can_create_surfaces()`]: Self::can_create_surfaces()
|
/// [`can_create_surfaces()`]: Self::can_create_surfaces()
|
||||||
/// [`destroy_surfaces()`]: Self::destroy_surfaces()
|
/// [`destroy_surfaces()`]: Self::destroy_surfaces()
|
||||||
fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop);
|
fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) {
|
||||||
|
let _ = event_loop;
|
||||||
|
}
|
||||||
|
|
||||||
/// Called after a wake up is requested using [`EventLoopProxy::wake_up()`].
|
/// Called after a wake up is requested using [`EventLoopProxy::wake_up()`].
|
||||||
///
|
///
|
||||||
@@ -142,8 +146,6 @@ pub trait ApplicationHandler {
|
|||||||
/// # ) {
|
/// # ) {
|
||||||
/// # }
|
/// # }
|
||||||
/// #
|
/// #
|
||||||
/// # fn can_create_surfaces(&mut self, _event_loop: &dyn ActiveEventLoop) {}
|
|
||||||
/// #
|
|
||||||
/// fn proxy_wake_up(&mut self, _event_loop: &dyn ActiveEventLoop) {
|
/// fn proxy_wake_up(&mut self, _event_loop: &dyn ActiveEventLoop) {
|
||||||
/// // Iterate current events, since wake-ups may have been merged.
|
/// // Iterate current events, since wake-ups may have been merged.
|
||||||
/// //
|
/// //
|
||||||
@@ -162,8 +164,6 @@ pub trait ApplicationHandler {
|
|||||||
///
|
///
|
||||||
/// let (sender, receiver) = mpsc::channel();
|
/// let (sender, receiver) = mpsc::channel();
|
||||||
///
|
///
|
||||||
/// let mut app = MyApp { receiver };
|
|
||||||
///
|
|
||||||
/// // Send an event in a loop
|
/// // Send an event in a loop
|
||||||
/// let proxy = event_loop.create_proxy();
|
/// let proxy = event_loop.create_proxy();
|
||||||
/// let background_thread = thread::spawn(move || {
|
/// let background_thread = thread::spawn(move || {
|
||||||
@@ -182,9 +182,8 @@ pub trait ApplicationHandler {
|
|||||||
/// }
|
/// }
|
||||||
/// });
|
/// });
|
||||||
///
|
///
|
||||||
/// event_loop.run_app(&mut app)?;
|
/// event_loop.run(|_event_loop| MyApp { receiver })?;
|
||||||
///
|
///
|
||||||
/// drop(app);
|
|
||||||
/// background_thread.join().unwrap();
|
/// background_thread.join().unwrap();
|
||||||
///
|
///
|
||||||
/// Ok(())
|
/// Ok(())
|
||||||
@@ -286,13 +285,13 @@ pub trait ApplicationHandler {
|
|||||||
/// with the [`onStop`] lifecycle event which typically results in the surface to be destroyed
|
/// with the [`onStop`] lifecycle event which typically results in the surface to be destroyed
|
||||||
/// after the app becomes invisible.
|
/// after the app becomes invisible.
|
||||||
///
|
///
|
||||||
/// Applications that need to run on Android should assume their [`NativeWindow`] has been
|
/// Applications that need to run on Android must be able to handle their underlying
|
||||||
/// destroyed, which indirectly invalidates any existing render surfaces that may have been
|
/// [`SurfaceView`] being destroyed, which in turn indirectly invalidates any existing
|
||||||
/// created outside of Winit (such as an `EGLSurface`, [`VkSurfaceKHR`] or [`wgpu::Surface`]).
|
/// render surfaces that may have been created outside of Winit (such as an `EGLSurface`,
|
||||||
|
/// [`VkSurfaceKHR`] or [`wgpu::Surface`]).
|
||||||
///
|
///
|
||||||
/// When receiving [`destroy_surfaces()`] Android applications should drop all render surfaces
|
/// This means that in this method, you must drop all render surfaces before the event callback
|
||||||
/// before the event callback completes, which may be re-created when the application next
|
/// completes, and only re-create them in or after [`can_create_surfaces()`] is next recieved.
|
||||||
/// receives [`can_create_surfaces()`].
|
|
||||||
///
|
///
|
||||||
/// [`NativeWindow`]: https://developer.android.com/ndk/reference/group/a-native-window
|
/// [`NativeWindow`]: https://developer.android.com/ndk/reference/group/a-native-window
|
||||||
/// [`Surface`]: https://developer.android.com/reference/android/view/Surface
|
/// [`Surface`]: https://developer.android.com/reference/android/view/Surface
|
||||||
@@ -310,14 +309,6 @@ pub trait ApplicationHandler {
|
|||||||
let _ = event_loop;
|
let _ = event_loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Emitted when the event loop is being shut down.
|
|
||||||
///
|
|
||||||
/// This is irreversible - if this method is called, it is guaranteed that the event loop
|
|
||||||
/// will exit right after.
|
|
||||||
fn exiting(&mut self, event_loop: &dyn ActiveEventLoop) {
|
|
||||||
let _ = event_loop;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Emitted when the application has received a memory warning.
|
/// Emitted when the application has received a memory warning.
|
||||||
///
|
///
|
||||||
/// ## Platform-specific
|
/// ## Platform-specific
|
||||||
@@ -413,11 +404,6 @@ impl<A: ?Sized + ApplicationHandler> ApplicationHandler for &mut A {
|
|||||||
(**self).destroy_surfaces(event_loop);
|
(**self).destroy_surfaces(event_loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn exiting(&mut self, event_loop: &dyn ActiveEventLoop) {
|
|
||||||
(**self).exiting(event_loop);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn memory_warning(&mut self, event_loop: &dyn ActiveEventLoop) {
|
fn memory_warning(&mut self, event_loop: &dyn ActiveEventLoop) {
|
||||||
(**self).memory_warning(event_loop);
|
(**self).memory_warning(event_loop);
|
||||||
@@ -487,11 +473,6 @@ impl<A: ?Sized + ApplicationHandler> ApplicationHandler for Box<A> {
|
|||||||
(**self).destroy_surfaces(event_loop);
|
(**self).destroy_surfaces(event_loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn exiting(&mut self, event_loop: &dyn ActiveEventLoop) {
|
|
||||||
(**self).exiting(event_loop);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn memory_warning(&mut self, event_loop: &dyn ActiveEventLoop) {
|
fn memory_warning(&mut self, event_loop: &dyn ActiveEventLoop) {
|
||||||
(**self).memory_warning(event_loop);
|
(**self).memory_warning(event_loop);
|
||||||
|
|||||||
46
src/event.rs
46
src/event.rs
@@ -1,39 +1,4 @@
|
|||||||
//! The event enums and assorted supporting types.
|
//! The event enums and assorted supporting types.
|
||||||
//!
|
|
||||||
//! These are sent to the closure given to [`EventLoop::run_app(...)`], where they get
|
|
||||||
//! processed and used to modify the program state. For more details, see the root-level
|
|
||||||
//! documentation.
|
|
||||||
//!
|
|
||||||
//! Some of these events represent different "parts" of a traditional event-handling loop. You could
|
|
||||||
//! approximate the basic ordering loop of [`EventLoop::run_app(...)`] like this:
|
|
||||||
//!
|
|
||||||
//! ```rust,ignore
|
|
||||||
//! let mut start_cause = StartCause::Init;
|
|
||||||
//!
|
|
||||||
//! while !elwt.exiting() {
|
|
||||||
//! app.new_events(event_loop, start_cause);
|
|
||||||
//!
|
|
||||||
//! for event in (window events, user events, device events) {
|
|
||||||
//! // This will pick the right method on the application based on the event.
|
|
||||||
//! app.handle_event(event_loop, event);
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! for window_id in (redraw windows) {
|
|
||||||
//! app.window_event(event_loop, window_id, RedrawRequested);
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! app.about_to_wait(event_loop);
|
|
||||||
//! start_cause = wait_if_necessary();
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! app.exiting(event_loop);
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! This leaves out timing details like [`ControlFlow::WaitUntil`] but hopefully
|
|
||||||
//! describes what happens in what order.
|
|
||||||
//!
|
|
||||||
//! [`EventLoop::run_app(...)`]: crate::event_loop::EventLoop::run_app
|
|
||||||
//! [`ControlFlow::WaitUntil`]: crate::event_loop::ControlFlow::WaitUntil
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::{Mutex, Weak};
|
use std::sync::{Mutex, Weak};
|
||||||
#[cfg(not(web_platform))]
|
#[cfg(not(web_platform))]
|
||||||
@@ -85,11 +50,6 @@ pub(crate) enum Event {
|
|||||||
/// [`ApplicationHandler::suspended()`]: crate::application::ApplicationHandler::suspended()
|
/// [`ApplicationHandler::suspended()`]: crate::application::ApplicationHandler::suspended()
|
||||||
Suspended,
|
Suspended,
|
||||||
|
|
||||||
/// See [`ApplicationHandler::can_create_surfaces()`] for details.
|
|
||||||
///
|
|
||||||
/// [`ApplicationHandler::can_create_surfaces()`]: crate::application::ApplicationHandler::can_create_surfaces()
|
|
||||||
CreateSurfaces,
|
|
||||||
|
|
||||||
/// See [`ApplicationHandler::resumed()`] for details.
|
/// See [`ApplicationHandler::resumed()`] for details.
|
||||||
///
|
///
|
||||||
/// [`ApplicationHandler::resumed()`]: crate::application::ApplicationHandler::resumed()
|
/// [`ApplicationHandler::resumed()`]: crate::application::ApplicationHandler::resumed()
|
||||||
@@ -100,11 +60,6 @@ pub(crate) enum Event {
|
|||||||
/// [`ApplicationHandler::about_to_wait()`]: crate::application::ApplicationHandler::about_to_wait()
|
/// [`ApplicationHandler::about_to_wait()`]: crate::application::ApplicationHandler::about_to_wait()
|
||||||
AboutToWait,
|
AboutToWait,
|
||||||
|
|
||||||
/// See [`ApplicationHandler::exiting()`] for details.
|
|
||||||
///
|
|
||||||
/// [`ApplicationHandler::exiting()`]: crate::application::ApplicationHandler::exiting()
|
|
||||||
LoopExiting,
|
|
||||||
|
|
||||||
/// See [`ApplicationHandler::memory_warning()`] for details.
|
/// See [`ApplicationHandler::memory_warning()`] for details.
|
||||||
///
|
///
|
||||||
/// [`ApplicationHandler::memory_warning()`]: crate::application::ApplicationHandler::memory_warning()
|
/// [`ApplicationHandler::memory_warning()`]: crate::application::ApplicationHandler::memory_warning()
|
||||||
@@ -1195,7 +1150,6 @@ mod tests {
|
|||||||
let wid = WindowId::from_raw(0);
|
let wid = WindowId::from_raw(0);
|
||||||
x(NewEvents(event::StartCause::Init));
|
x(NewEvents(event::StartCause::Init));
|
||||||
x(AboutToWait);
|
x(AboutToWait);
|
||||||
x(LoopExiting);
|
|
||||||
x(Suspended);
|
x(Suspended);
|
||||||
x(Resumed);
|
x(Resumed);
|
||||||
|
|
||||||
|
|||||||
@@ -195,10 +195,48 @@ impl EventLoop {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl EventLoop {
|
impl EventLoop {
|
||||||
/// Run the application with the event loop on the calling thread.
|
/// Run the event loop on the current thread.
|
||||||
|
///
|
||||||
|
/// You pass in a closure that returns your application state. This closure has access to the
|
||||||
|
/// currently running event loop, allowing you to initialize your windows and surfaces in here.
|
||||||
///
|
///
|
||||||
/// See the [`set_control_flow()`] docs on how to change the event loop's behavior.
|
/// See the [`set_control_flow()`] docs on how to change the event loop's behavior.
|
||||||
///
|
///
|
||||||
|
/// ## Event loop flow
|
||||||
|
///
|
||||||
|
/// This function internally handles the different parts of a traditional event-handling loop.
|
||||||
|
/// You could imagine this method being implemented like this:
|
||||||
|
///
|
||||||
|
/// ```rust,ignore
|
||||||
|
/// // Initialize.
|
||||||
|
/// let mut app = init_closure(event_loop);
|
||||||
|
/// let mut start_cause = StartCause::Init;
|
||||||
|
///
|
||||||
|
/// // Run loop.
|
||||||
|
/// while !elwt.exiting() {
|
||||||
|
/// // Wake up.
|
||||||
|
/// app.new_events(event_loop, start_cause);
|
||||||
|
///
|
||||||
|
/// // Handle events by the user.
|
||||||
|
/// for (device_id, event) in incoming_device_events {
|
||||||
|
/// app.device_event(event_loop, device_id, event);
|
||||||
|
/// }
|
||||||
|
/// for (window_id, event) in incoming_window_events {
|
||||||
|
/// app.window_event(event_loop, window_id, event);
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// // Done handling events, wait until we're woken up again.
|
||||||
|
/// app.about_to_wait(event_loop);
|
||||||
|
/// start_cause = wait_if_necessary();
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// // Finished running, drop application state.
|
||||||
|
/// drop(app);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// This is of course a very coarse-grained overview, and leaves out timing details like
|
||||||
|
/// [`ControlFlow::WaitUntil`] and life-cycle methods like [`ApplicationHandler::resumed`].
|
||||||
|
///
|
||||||
/// ## Platform-specific
|
/// ## Platform-specific
|
||||||
///
|
///
|
||||||
/// - **iOS:** Will never return to the caller and so values not passed to this function will
|
/// - **iOS:** Will never return to the caller and so values not passed to this function will
|
||||||
@@ -213,7 +251,7 @@ impl EventLoop {
|
|||||||
doc = " [`EventLoopExtWeb::spawn_app()`][crate::platform::web::EventLoopExtWeb::spawn_app()]"
|
doc = " [`EventLoopExtWeb::spawn_app()`][crate::platform::web::EventLoopExtWeb::spawn_app()]"
|
||||||
)]
|
)]
|
||||||
#[cfg_attr(not(any(web_platform, docsrs)), doc = " `EventLoopExtWeb::spawn_app()`")]
|
#[cfg_attr(not(any(web_platform, docsrs)), doc = " `EventLoopExtWeb::spawn_app()`")]
|
||||||
/// [^1] instead of [`run_app()`] to avoid the need for the Javascript exception trick, and to
|
/// [^1] instead of [`run()`] to avoid the need for the Javascript exception trick, and to
|
||||||
/// make it clearer that the event loop runs asynchronously (via the browser's own,
|
/// make it clearer that the event loop runs asynchronously (via the browser's own,
|
||||||
/// internal, event loop) and doesn't block the current thread of execution like it does
|
/// internal, event loop) and doesn't block the current thread of execution like it does
|
||||||
/// on other platforms.
|
/// on other platforms.
|
||||||
@@ -223,11 +261,20 @@ impl EventLoop {
|
|||||||
/// [^1]: `spawn_app()` is only available on the Web platform.
|
/// [^1]: `spawn_app()` is only available on the Web platform.
|
||||||
///
|
///
|
||||||
/// [`set_control_flow()`]: ActiveEventLoop::set_control_flow()
|
/// [`set_control_flow()`]: ActiveEventLoop::set_control_flow()
|
||||||
/// [`run_app()`]: Self::run_app()
|
/// [`run()`]: Self::run()
|
||||||
#[inline]
|
#[inline]
|
||||||
#[cfg(not(all(web_platform, target_feature = "exception-handling")))]
|
#[cfg(not(all(web_platform, target_feature = "exception-handling")))]
|
||||||
|
pub fn run<A: ApplicationHandler>(
|
||||||
|
self,
|
||||||
|
init_closure: impl FnOnce(&dyn ActiveEventLoop) -> A,
|
||||||
|
) -> Result<(), EventLoopError> {
|
||||||
|
self.event_loop.run(init_closure)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run the event loop with the given application state.
|
||||||
|
#[deprecated = "less flexible version of `run`"]
|
||||||
pub fn run_app<A: ApplicationHandler>(self, app: A) -> Result<(), EventLoopError> {
|
pub fn run_app<A: ApplicationHandler>(self, app: A) -> Result<(), EventLoopError> {
|
||||||
self.event_loop.run_app(app)
|
self.run(|_event_loop| app)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an [`EventLoopProxy`] that can be used to dispatch user events
|
/// Creates an [`EventLoopProxy`] that can be used to dispatch user events
|
||||||
@@ -392,9 +439,7 @@ pub trait ActiveEventLoop: AsAny {
|
|||||||
/// Gets the current [`ControlFlow`].
|
/// Gets the current [`ControlFlow`].
|
||||||
fn control_flow(&self) -> ControlFlow;
|
fn control_flow(&self) -> ControlFlow;
|
||||||
|
|
||||||
/// This exits the event loop.
|
/// This stops the event loop.
|
||||||
///
|
|
||||||
/// See [`exiting`][crate::application::ApplicationHandler::exiting].
|
|
||||||
fn exit(&self);
|
fn exit(&self);
|
||||||
|
|
||||||
/// Returns if the [`EventLoop`] is about to stop.
|
/// Returns if the [`EventLoop`] is about to stop.
|
||||||
|
|||||||
85
src/lib.rs
85
src/lib.rs
@@ -1,24 +1,14 @@
|
|||||||
//! Winit is a cross-platform window creation and event loop management library.
|
//! Winit is a cross-platform window creation and event loop management library.
|
||||||
//!
|
//!
|
||||||
//! # Building windows
|
|
||||||
//!
|
|
||||||
//! Before you can create a [`Window`], you first need to build an [`EventLoop`]. This is done with
|
|
||||||
//! the [`EventLoop::new()`] function.
|
|
||||||
//!
|
|
||||||
//! ```no_run
|
|
||||||
//! use winit::event_loop::EventLoop;
|
|
||||||
//!
|
|
||||||
//! # // Intentionally use `fn main` for clarity
|
|
||||||
//! fn main() {
|
|
||||||
//! let event_loop = EventLoop::new().unwrap();
|
|
||||||
//! // ...
|
|
||||||
//! }
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! Then you create a [`Window`] with [`create_window`].
|
|
||||||
//!
|
|
||||||
//! # Event handling
|
//! # Event handling
|
||||||
//!
|
//!
|
||||||
|
//! Basically all of the functionality that Winit exposes requires an [`ActiveEventLoop`], which you
|
||||||
|
//! can get access to by running an [`EventLoop`] using [`EventLoop::new()`] and
|
||||||
|
//! [`EventLoop::run()`].
|
||||||
|
//!
|
||||||
|
//! Once it's running, you can create your [`Window`]s with [`ActiveEventLoop::create_window()`] by
|
||||||
|
//! passing in the desired [`WindowAttributes`].
|
||||||
|
//!
|
||||||
//! Once a [`Window`] has been created, it will generate different *events*. A [`Window`] object can
|
//! Once a [`Window`] has been created, it will generate different *events*. A [`Window`] object can
|
||||||
//! generate [`WindowEvent`]s when certain input events occur, such as a cursor moving over the
|
//! generate [`WindowEvent`]s when certain input events occur, such as a cursor moving over the
|
||||||
//! window or a key getting pressed while the window is focused. Devices can generate
|
//! window or a key getting pressed while the window is focused. Devices can generate
|
||||||
@@ -26,9 +16,10 @@
|
|||||||
//! Some user activity, like mouse movement, can generate both a [`WindowEvent`] *and* a
|
//! Some user activity, like mouse movement, can generate both a [`WindowEvent`] *and* a
|
||||||
//! [`DeviceEvent`].
|
//! [`DeviceEvent`].
|
||||||
//!
|
//!
|
||||||
//! You can retrieve events by calling [`EventLoop::run_app()`]. This function will
|
//! You retrieve by implementing [`ApplicationHandler`] for a new type, which will be the state of
|
||||||
//! dispatch events for every [`Window`] that was created with that particular [`EventLoop`], and
|
//! your application. The methods in this trait will continuously receive events until
|
||||||
//! will run until [`exit()`] is used, at which point [`exiting()`] is called.
|
//! [`ActiveEventLoop::exit()`] is used, at which point your application state will be dropped, and
|
||||||
|
//! the application shuts down.
|
||||||
//!
|
//!
|
||||||
//! Winit no longer uses a `EventLoop::poll_events() -> impl Iterator<Event>`-based event loop
|
//! Winit no longer uses a `EventLoop::poll_events() -> impl Iterator<Event>`-based event loop
|
||||||
//! model, since that can't be implemented properly on some platforms (e.g Web, iOS) and works
|
//! model, since that can't be implemented properly on some platforms (e.g Web, iOS) and works
|
||||||
@@ -49,19 +40,20 @@
|
|||||||
//! use winit::application::ApplicationHandler;
|
//! use winit::application::ApplicationHandler;
|
||||||
//! use winit::event::WindowEvent;
|
//! use winit::event::WindowEvent;
|
||||||
//! use winit::event_loop::{ActiveEventLoop, ControlFlow, EventLoop};
|
//! use winit::event_loop::{ActiveEventLoop, ControlFlow, EventLoop};
|
||||||
//! use winit::window::{Window, WindowId, WindowAttributes};
|
//! use winit::window::{Window, WindowId};
|
||||||
//!
|
//!
|
||||||
//! #[derive(Default)]
|
|
||||||
//! struct App {
|
//! struct App {
|
||||||
//! window: Option<Box<dyn Window>>,
|
//! window: Box<dyn Window>,
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! impl ApplicationHandler for App {
|
//! impl ApplicationHandler for App {
|
||||||
//! fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) {
|
//! fn window_event(
|
||||||
//! self.window = Some(event_loop.create_window(WindowAttributes::default()).unwrap());
|
//! &mut self,
|
||||||
//! }
|
//! event_loop: &dyn ActiveEventLoop,
|
||||||
//!
|
//! id: WindowId,
|
||||||
//! fn window_event(&mut self, event_loop: &dyn ActiveEventLoop, id: WindowId, event: WindowEvent) {
|
//! event: WindowEvent,
|
||||||
|
//! ) {
|
||||||
|
//! // Called by `EventLoop::run` when a new event happens on the window.
|
||||||
//! match event {
|
//! match event {
|
||||||
//! WindowEvent::CloseRequested => {
|
//! WindowEvent::CloseRequested => {
|
||||||
//! println!("The close button was pressed; stopping");
|
//! println!("The close button was pressed; stopping");
|
||||||
@@ -81,16 +73,19 @@
|
|||||||
//! // You only need to call this if you've determined that you need to redraw in
|
//! // You only need to call this if you've determined that you need to redraw in
|
||||||
//! // applications which do not always need to. Applications that redraw continuously
|
//! // applications which do not always need to. Applications that redraw continuously
|
||||||
//! // can render here instead.
|
//! // can render here instead.
|
||||||
//! self.window.as_ref().unwrap().request_redraw();
|
//! self.window.request_redraw();
|
||||||
//! }
|
//! },
|
||||||
//! _ => (),
|
//! _ => (),
|
||||||
//! }
|
//! }
|
||||||
//! }
|
//! }
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! # // Intentionally use `fn main` for clarity
|
//! # // Intentionally use `fn main` for clarity
|
||||||
//! fn main() {
|
//! fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
//! let event_loop = EventLoop::new().unwrap();
|
//! // Create a new event loop.
|
||||||
|
//! let event_loop = EventLoop::new()?;
|
||||||
|
//!
|
||||||
|
//! // Configure settings before launching.
|
||||||
//!
|
//!
|
||||||
//! // ControlFlow::Poll continuously runs the event loop, even if the OS hasn't
|
//! // ControlFlow::Poll continuously runs the event loop, even if the OS hasn't
|
||||||
//! // dispatched any events. This is ideal for games and similar applications.
|
//! // dispatched any events. This is ideal for games and similar applications.
|
||||||
@@ -101,8 +96,21 @@
|
|||||||
//! // input, and uses significantly less power/CPU time than ControlFlow::Poll.
|
//! // input, and uses significantly less power/CPU time than ControlFlow::Poll.
|
||||||
//! event_loop.set_control_flow(ControlFlow::Wait);
|
//! event_loop.set_control_flow(ControlFlow::Wait);
|
||||||
//!
|
//!
|
||||||
//! let mut app = App::default();
|
//! // Launch and begin running our event loop.
|
||||||
//! event_loop.run_app(&mut app);
|
//! event_loop.run(|event_loop| {
|
||||||
|
//! // The event loop has launched, and we can initialize our UI state in this closure.
|
||||||
|
//!
|
||||||
|
//! // Create a simple window with default attributes.
|
||||||
|
//! let window = event_loop
|
||||||
|
//! .create_window(Window::default_attributes())
|
||||||
|
//! .expect("failed creating window");
|
||||||
|
//!
|
||||||
|
//! // Give our newly created application state to Winit, which will, when necessary, call
|
||||||
|
//! // the `ApplicationHandler` methods configured above.
|
||||||
|
//! App { window }
|
||||||
|
//! })?;
|
||||||
|
//!
|
||||||
|
//! Ok(())
|
||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
@@ -250,20 +258,21 @@
|
|||||||
//! |32-bit ARM Android |`arm-linux-androideabi` |Android |
|
//! |32-bit ARM Android |`arm-linux-androideabi` |Android |
|
||||||
//! |64-bit SPARC Linux with glibc |`sparc64-unknown-linux-gnu` |X11, Wayland |
|
//! |64-bit SPARC Linux with glibc |`sparc64-unknown-linux-gnu` |X11, Wayland |
|
||||||
//!
|
//!
|
||||||
|
//! [`ActiveEventLoop`]: event_loop::ActiveEventLoop
|
||||||
//! [`EventLoop`]: event_loop::EventLoop
|
//! [`EventLoop`]: event_loop::EventLoop
|
||||||
//! [`EventLoop::new()`]: event_loop::EventLoop::new
|
//! [`EventLoop::new()`]: event_loop::EventLoop::new
|
||||||
//! [`EventLoop::run_app()`]: event_loop::EventLoop::run_app
|
//! [`EventLoop::run()`]: event_loop::EventLoop::run
|
||||||
//! [`exit()`]: event_loop::ActiveEventLoop::exit
|
//! [`ActiveEventLoop::exit()`]: event_loop::ActiveEventLoop::exit
|
||||||
//! [`Window`]: window::Window
|
//! [`Window`]: window::Window
|
||||||
//! [`WindowId`]: window::WindowId
|
//! [`WindowId`]: window::WindowId
|
||||||
//! [`WindowAttributes`]: window::WindowAttributes
|
//! [`WindowAttributes`]: window::WindowAttributes
|
||||||
//! [window_new]: window::Window::new
|
//! [window_new]: window::Window::new
|
||||||
//! [`create_window`]: event_loop::ActiveEventLoop::create_window
|
//! [`ActiveEventLoop::create_window()`]: event_loop::ActiveEventLoop::create_window
|
||||||
//! [`Window::id()`]: window::Window::id
|
//! [`Window::id()`]: window::Window::id
|
||||||
//! [`WindowEvent`]: event::WindowEvent
|
//! [`WindowEvent`]: event::WindowEvent
|
||||||
//! [`DeviceEvent`]: event::DeviceEvent
|
//! [`DeviceEvent`]: event::DeviceEvent
|
||||||
|
//! [`ApplicationHandler`]: application::ApplicationHandler
|
||||||
//! [`Event::UserEvent`]: event::Event::UserEvent
|
//! [`Event::UserEvent`]: event::Event::UserEvent
|
||||||
//! [`exiting()`]: crate::application::ApplicationHandler::exiting
|
|
||||||
//! [`raw_window_handle`]: ./window/struct.Window.html#method.raw_window_handle
|
//! [`raw_window_handle`]: ./window/struct.Window.html#method.raw_window_handle
|
||||||
//! [`raw_display_handle`]: ./window/struct.Window.html#method.raw_display_handle
|
//! [`raw_display_handle`]: ./window/struct.Window.html#method.raw_display_handle
|
||||||
//! [^1]: `EventLoopExtPumpEvents::pump_app_events()` is only available on Windows, macOS, Android, X11 and Wayland.
|
//! [^1]: `EventLoopExtPumpEvents::pump_app_events()` is only available on Windows, macOS, Android, X11 and Wayland.
|
||||||
|
|||||||
@@ -65,7 +65,7 @@
|
|||||||
//! let app = NSApplication::sharedApplication(mtm);
|
//! let app = NSApplication::sharedApplication(mtm);
|
||||||
//! app.setDelegate(Some(ProtocolObject::from_ref(&*delegate)));
|
//! app.setDelegate(Some(ProtocolObject::from_ref(&*delegate)));
|
||||||
//!
|
//!
|
||||||
//! // event_loop.run_app(&mut my_app);
|
//! // event_loop.run(|event_loop| { ... })?;
|
||||||
//! Ok(())
|
//! Ok(())
|
||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
|
|||||||
@@ -1,16 +1,14 @@
|
|||||||
use crate::application::ApplicationHandler;
|
use crate::application::ApplicationHandler;
|
||||||
use crate::error::EventLoopError;
|
use crate::error::EventLoopError;
|
||||||
use crate::event_loop::EventLoop;
|
use crate::event_loop::{ActiveEventLoop, EventLoop};
|
||||||
#[cfg(doc)]
|
#[cfg(doc)]
|
||||||
use crate::{
|
use crate::{platform::pump_events::EventLoopExtPumpEvents, window::Window};
|
||||||
event_loop::ActiveEventLoop, platform::pump_events::EventLoopExtPumpEvents, window::Window,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Additional methods on [`EventLoop`] to return control flow to the caller.
|
/// Additional methods on [`EventLoop`] to return control flow to the caller.
|
||||||
pub trait EventLoopExtRunOnDemand {
|
pub trait EventLoopExtRunOnDemand {
|
||||||
/// Run the application with the event loop on the calling thread.
|
/// Run the application with the event loop on the calling thread.
|
||||||
///
|
///
|
||||||
/// Unlike [`EventLoop::run_app`], this function accepts non-`'static` (i.e. non-`move`)
|
/// Unlike [`EventLoop::run`], this function accepts non-`'static` (i.e. non-`move`)
|
||||||
/// closures and it is possible to return control back to the caller without
|
/// closures and it is possible to return control back to the caller without
|
||||||
/// consuming the `EventLoop` (by using [`exit()`]) and
|
/// consuming the `EventLoop` (by using [`exit()`]) and
|
||||||
/// so the event loop can be re-run after it has exit.
|
/// so the event loop can be re-run after it has exit.
|
||||||
@@ -23,7 +21,7 @@ pub trait EventLoopExtRunOnDemand {
|
|||||||
/// to while maintaining the full state of your application. (If you need something like this
|
/// to while maintaining the full state of your application. (If you need something like this
|
||||||
/// you can look at the [`EventLoopExtPumpEvents::pump_app_events()`] API)
|
/// you can look at the [`EventLoopExtPumpEvents::pump_app_events()`] API)
|
||||||
///
|
///
|
||||||
/// Each time `run_app_on_demand` is called the startup sequence of `init`, followed by
|
/// Each time `run_on_demand` is called the startup sequence of `init`, followed by
|
||||||
/// `resume` is being preserved.
|
/// `resume` is being preserved.
|
||||||
///
|
///
|
||||||
/// See the [`set_control_flow()`] docs on how to change the event loop's behavior.
|
/// See the [`set_control_flow()`] docs on how to change the event loop's behavior.
|
||||||
@@ -40,7 +38,7 @@ pub trait EventLoopExtRunOnDemand {
|
|||||||
/// [^1] more than once instead).
|
/// [^1] more than once instead).
|
||||||
/// - No [`Window`] state can be carried between separate runs of the event loop.
|
/// - No [`Window`] state can be carried between separate runs of the event loop.
|
||||||
///
|
///
|
||||||
/// You are strongly encouraged to use [`EventLoop::run_app()`] for portability, unless you
|
/// You are strongly encouraged to use [`EventLoop::run()`] for portability, unless you
|
||||||
/// specifically need the ability to re-run a single event loop more than once
|
/// specifically need the ability to re-run a single event loop more than once
|
||||||
///
|
///
|
||||||
/// # Supported Platforms
|
/// # Supported Platforms
|
||||||
@@ -60,12 +58,18 @@ pub trait EventLoopExtRunOnDemand {
|
|||||||
///
|
///
|
||||||
/// [`exit()`]: ActiveEventLoop::exit()
|
/// [`exit()`]: ActiveEventLoop::exit()
|
||||||
/// [`set_control_flow()`]: ActiveEventLoop::set_control_flow()
|
/// [`set_control_flow()`]: ActiveEventLoop::set_control_flow()
|
||||||
fn run_app_on_demand<A: ApplicationHandler>(&mut self, app: A) -> Result<(), EventLoopError>;
|
fn run_on_demand<A: ApplicationHandler>(
|
||||||
|
&mut self,
|
||||||
|
init_closure: impl FnOnce(&dyn ActiveEventLoop) -> A,
|
||||||
|
) -> Result<(), EventLoopError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventLoopExtRunOnDemand for EventLoop {
|
impl EventLoopExtRunOnDemand for EventLoop {
|
||||||
fn run_app_on_demand<A: ApplicationHandler>(&mut self, app: A) -> Result<(), EventLoopError> {
|
fn run_on_demand<A: ApplicationHandler>(
|
||||||
self.event_loop.run_app_on_demand(app)
|
&mut self,
|
||||||
|
init_closure: impl FnOnce(&dyn ActiveEventLoop) -> A,
|
||||||
|
) -> Result<(), EventLoopError> {
|
||||||
|
self.event_loop.run_on_demand(init_closure)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -190,10 +190,10 @@ pub trait EventLoopExtWeb {
|
|||||||
/// Initializes the winit event loop.
|
/// Initializes the winit event loop.
|
||||||
///
|
///
|
||||||
/// Unlike
|
/// Unlike
|
||||||
#[cfg_attr(all(web_platform, target_feature = "exception-handling"), doc = "`run_app()`")]
|
#[cfg_attr(all(web_platform, target_feature = "exception-handling"), doc = "`run()`")]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
not(all(web_platform, target_feature = "exception-handling")),
|
not(all(web_platform, target_feature = "exception-handling")),
|
||||||
doc = "[`run_app()`]"
|
doc = "[`run()`]"
|
||||||
)]
|
)]
|
||||||
/// [^1], this returns immediately, and doesn't throw an exception in order to
|
/// [^1], this returns immediately, and doesn't throw an exception in order to
|
||||||
/// satisfy its [`!`] return type.
|
/// satisfy its [`!`] return type.
|
||||||
@@ -206,9 +206,9 @@ pub trait EventLoopExtWeb {
|
|||||||
///
|
///
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
not(all(web_platform, target_feature = "exception-handling")),
|
not(all(web_platform, target_feature = "exception-handling")),
|
||||||
doc = "[`run_app()`]: EventLoop::run_app()"
|
doc = "[`run()`]: EventLoop::run()"
|
||||||
)]
|
)]
|
||||||
/// [^1]: `run_app()` is _not_ available on Wasm when the target supports `exception-handling`.
|
/// [^1]: `run()` is _not_ available on Wasm when the target supports `exception-handling`.
|
||||||
fn spawn_app<A: ApplicationHandler + 'static>(self, app: A);
|
fn spawn_app<A: ApplicationHandler + 'static>(self, app: A);
|
||||||
|
|
||||||
/// Sets the strategy for [`ControlFlow::Poll`].
|
/// Sets the strategy for [`ControlFlow::Poll`].
|
||||||
|
|||||||
@@ -496,15 +496,21 @@ impl EventLoop {
|
|||||||
input_status
|
input_status
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_app<A: ApplicationHandler>(mut self, app: A) -> Result<(), EventLoopError> {
|
pub fn run<A: ApplicationHandler>(
|
||||||
self.run_app_on_demand(app)
|
mut self,
|
||||||
|
init_closure: impl FnOnce(&dyn RootActiveEventLoop) -> A,
|
||||||
|
) -> Result<(), EventLoopError> {
|
||||||
|
self.run_on_demand(init_closure)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_app_on_demand<A: ApplicationHandler>(
|
pub fn run_on_demand<A: ApplicationHandler>(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut app: A,
|
init_closure: impl FnOnce(&dyn RootActiveEventLoop) -> A,
|
||||||
) -> Result<(), EventLoopError> {
|
) -> Result<(), EventLoopError> {
|
||||||
self.window_target.clear_exit();
|
self.window_target.clear_exit();
|
||||||
|
|
||||||
|
let mut app = init_closure(&self.window_target);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
match self.pump_app_events(None, &mut app) {
|
match self.pump_app_events(None, &mut app) {
|
||||||
PumpStatus::Exit(0) => {
|
PumpStatus::Exit(0) => {
|
||||||
@@ -546,8 +552,6 @@ impl EventLoop {
|
|||||||
if self.exiting() {
|
if self.exiting() {
|
||||||
self.loop_running = false;
|
self.loop_running = false;
|
||||||
|
|
||||||
app.exiting(&self.window_target);
|
|
||||||
|
|
||||||
PumpStatus::Exit(0)
|
PumpStatus::Exit(0)
|
||||||
} else {
|
} else {
|
||||||
PumpStatus::Continue
|
PumpStatus::Continue
|
||||||
|
|||||||
@@ -9,12 +9,12 @@ use objc2_app_kit::{NSApplication, NSApplicationActivationPolicy, NSRunningAppli
|
|||||||
use objc2_foundation::{MainThreadMarker, NSNotification};
|
use objc2_foundation::{MainThreadMarker, NSNotification};
|
||||||
|
|
||||||
use super::super::event_handler::EventHandler;
|
use super::super::event_handler::EventHandler;
|
||||||
use super::event_loop::{stop_app_immediately, ActiveEventLoop, EventLoopProxy, PanicInfo};
|
use super::event_loop::{stop_app_immediately, EventLoopProxy, PanicInfo};
|
||||||
use super::menu;
|
use super::menu;
|
||||||
use super::observer::{EventLoopWaker, RunLoop};
|
use super::observer::{EventLoopWaker, RunLoop};
|
||||||
use crate::application::ApplicationHandler;
|
use crate::application::ApplicationHandler;
|
||||||
use crate::event::{StartCause, WindowEvent};
|
use crate::event::{StartCause, WindowEvent};
|
||||||
use crate::event_loop::ControlFlow;
|
use crate::event_loop::{ActiveEventLoop, ControlFlow};
|
||||||
use crate::window::WindowId;
|
use crate::window::WindowId;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -163,17 +163,25 @@ impl AppState {
|
|||||||
pub fn will_terminate(self: &Rc<Self>, _notification: &NSNotification) {
|
pub fn will_terminate(self: &Rc<Self>, _notification: &NSNotification) {
|
||||||
trace_scope!("NSApplicationWillTerminateNotification");
|
trace_scope!("NSApplicationWillTerminateNotification");
|
||||||
// TODO: Notify every window that it will be destroyed, like done in iOS?
|
// TODO: Notify every window that it will be destroyed, like done in iOS?
|
||||||
|
self.with_handler(|app, event_loop| {
|
||||||
|
app.exiting(event_loop);
|
||||||
|
});
|
||||||
self.internal_exit();
|
self.internal_exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Place the event handler in the application state for the duration
|
/// Place the event handler in the application state for the duration
|
||||||
/// of the given closure.
|
/// of the given closure.
|
||||||
pub fn set_event_handler<R>(
|
pub fn set_init_closure<A: ApplicationHandler, R>(
|
||||||
&self,
|
&self,
|
||||||
handler: &mut dyn ApplicationHandler,
|
init_closure: impl FnOnce(&dyn ActiveEventLoop) -> A,
|
||||||
closure: impl FnOnce() -> R,
|
closure: impl FnOnce() -> R,
|
||||||
) -> R {
|
) -> R {
|
||||||
self.event_handler.set(handler, closure)
|
let init_closure = Box::new(
|
||||||
|
|active_event_loop: &'_ dyn ActiveEventLoop| -> Box<dyn ApplicationHandler + '_> {
|
||||||
|
Box::new(init_closure(active_event_loop))
|
||||||
|
},
|
||||||
|
);
|
||||||
|
self.event_handler.set(init_closure, closure)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn event_loop_proxy(&self) -> &Arc<EventLoopProxy> {
|
pub fn event_loop_proxy(&self) -> &Arc<EventLoopProxy> {
|
||||||
@@ -208,10 +216,6 @@ impl AppState {
|
|||||||
/// NOTE: that if the `NSApplication` has been launched then that state is preserved,
|
/// NOTE: that if the `NSApplication` has been launched then that state is preserved,
|
||||||
/// and we won't need to re-launch the app if subsequent EventLoops are run.
|
/// and we won't need to re-launch the app if subsequent EventLoops are run.
|
||||||
pub fn internal_exit(self: &Rc<Self>) {
|
pub fn internal_exit(self: &Rc<Self>) {
|
||||||
self.with_handler(|app, event_loop| {
|
|
||||||
app.exiting(event_loop);
|
|
||||||
});
|
|
||||||
|
|
||||||
self.set_is_running(false);
|
self.set_is_running(false);
|
||||||
self.set_stop_on_redraw(false);
|
self.set_stop_on_redraw(false);
|
||||||
self.set_stop_before_wait(false);
|
self.set_stop_before_wait(false);
|
||||||
|
|||||||
@@ -274,20 +274,23 @@ impl EventLoop {
|
|||||||
&self.window_target
|
&self.window_target
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_app<A: ApplicationHandler>(mut self, app: A) -> Result<(), EventLoopError> {
|
pub fn run<A: ApplicationHandler>(
|
||||||
self.run_app_on_demand(app)
|
mut self,
|
||||||
|
init_closure: impl FnOnce(&dyn RootActiveEventLoop) -> A,
|
||||||
|
) -> Result<(), EventLoopError> {
|
||||||
|
self.run_on_demand(init_closure)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NB: we don't base this on `pump_events` because for `MacOs` we can't support
|
// NB: we don't base this on `pump_events` because for `MacOs` we can't support
|
||||||
// `pump_events` elegantly (we just ask to run the loop for a "short" amount of
|
// `pump_events` elegantly (we just ask to run the loop for a "short" amount of
|
||||||
// time and so a layered implementation would end up using a lot of CPU due to
|
// time and so a layered implementation would end up using a lot of CPU due to
|
||||||
// redundant wake ups.
|
// redundant wake ups.
|
||||||
pub fn run_app_on_demand<A: ApplicationHandler>(
|
pub fn run_on_demand<A: ApplicationHandler>(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut app: A,
|
init_closure: impl FnOnce(&dyn RootActiveEventLoop) -> A,
|
||||||
) -> Result<(), EventLoopError> {
|
) -> Result<(), EventLoopError> {
|
||||||
self.app_state.clear_exit();
|
self.app_state.clear_exit();
|
||||||
self.app_state.set_event_handler(&mut app, || {
|
self.app_state.set_init_closure(init_closure, || {
|
||||||
autoreleasepool(|_| {
|
autoreleasepool(|_| {
|
||||||
// clear / normalize pump_events state
|
// clear / normalize pump_events state
|
||||||
self.app_state.set_wait_timeout(None);
|
self.app_state.set_wait_timeout(None);
|
||||||
|
|||||||
@@ -1,33 +1,55 @@
|
|||||||
use std::cell::RefCell;
|
use std::cell::Cell;
|
||||||
use std::{fmt, mem};
|
use std::{fmt, mem};
|
||||||
|
|
||||||
use crate::application::ApplicationHandler;
|
use crate::application::ApplicationHandler;
|
||||||
|
use crate::event_loop::ActiveEventLoop;
|
||||||
|
|
||||||
/// A helper type for storing a reference to `ApplicationHandler`, allowing interior mutable access
|
/// A helper type for storing a reference to `ApplicationHandler`, allowing interior mutable access
|
||||||
/// to it within the execution of a closure.
|
/// to it within the execution of a closure.
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub(crate) struct EventHandler {
|
pub(crate) struct EventHandler {
|
||||||
/// This can be in the following states:
|
state: Cell<State>,
|
||||||
/// - Not registered by the event loop (None).
|
}
|
||||||
/// - Present (Some(handler)).
|
|
||||||
/// - Currently executing the handler / in use (RefCell borrowed).
|
type InitClosure<'handler> =
|
||||||
inner: RefCell<Option<&'static mut dyn ApplicationHandler>>,
|
Box<dyn FnOnce(&dyn ActiveEventLoop) -> Box<dyn ApplicationHandler + 'handler> + 'handler>;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
enum State {
|
||||||
|
/// Not registered by the event loop.
|
||||||
|
#[default]
|
||||||
|
NotRegistered,
|
||||||
|
/// The event is registered by the event loop.
|
||||||
|
Registered(InitClosure<'static>),
|
||||||
|
/// The application has been initialized, and we're ready to handle events.
|
||||||
|
Ready(Box<dyn ApplicationHandler + 'static>),
|
||||||
|
/// Currently executing the handler.
|
||||||
|
CurrentlyExecuting,
|
||||||
|
/// The application has been terminated.
|
||||||
|
Terminated,
|
||||||
|
// TODO: Invalid state?
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for EventHandler {
|
impl fmt::Debug for EventHandler {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
let state = match self.inner.try_borrow().as_deref() {
|
let state = self.state.replace(State::CurrentlyExecuting);
|
||||||
Ok(Some(_)) => "<available>",
|
// NOTE: We're very careful not to panic inside the "critial" section here.
|
||||||
Ok(None) => "<not set>",
|
let string = match &state {
|
||||||
Err(_) => "<in use>",
|
State::NotRegistered => "<not registered>",
|
||||||
|
State::Registered(_) => "<registered>",
|
||||||
|
State::Ready(_) => "<ready>",
|
||||||
|
State::CurrentlyExecuting => "<currently executing>",
|
||||||
|
State::Terminated => "<terminated>",
|
||||||
};
|
};
|
||||||
f.debug_struct("EventHandler").field("state", &state).finish_non_exhaustive()
|
self.state.set(state);
|
||||||
|
|
||||||
|
f.debug_struct("EventHandler").field("state", &string).finish_non_exhaustive()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventHandler {
|
impl EventHandler {
|
||||||
pub(crate) fn new() -> Self {
|
pub(crate) const fn new() -> Self {
|
||||||
Self { inner: RefCell::new(None) }
|
Self { state: Cell::new(State::NotRegistered) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the event loop handler for the duration of the given closure.
|
/// Set the event loop handler for the duration of the given closure.
|
||||||
@@ -37,7 +59,7 @@ impl EventHandler {
|
|||||||
/// from within the closure.
|
/// from within the closure.
|
||||||
pub(crate) fn set<'handler, R>(
|
pub(crate) fn set<'handler, R>(
|
||||||
&self,
|
&self,
|
||||||
app: &'handler mut dyn ApplicationHandler,
|
init_closure: InitClosure<'handler>,
|
||||||
closure: impl FnOnce() -> R,
|
closure: impl FnOnce() -> R,
|
||||||
) -> R {
|
) -> R {
|
||||||
// SAFETY: We extend the lifetime of the handler here so that we can
|
// SAFETY: We extend the lifetime of the handler here so that we can
|
||||||
@@ -46,14 +68,9 @@ impl EventHandler {
|
|||||||
// This is sound, since we make sure to unset the handler again at the
|
// This is sound, since we make sure to unset the handler again at the
|
||||||
// end of this function, and as such the lifetime isn't actually
|
// end of this function, and as such the lifetime isn't actually
|
||||||
// extended beyond `'handler`.
|
// extended beyond `'handler`.
|
||||||
let handler = unsafe {
|
let handler = unsafe { mem::transmute::<InitClosure<'handler>, InitClosure<'static>>(app) };
|
||||||
mem::transmute::<
|
|
||||||
&'handler mut dyn ApplicationHandler,
|
|
||||||
&'static mut dyn ApplicationHandler,
|
|
||||||
>(app)
|
|
||||||
};
|
|
||||||
|
|
||||||
match self.inner.try_borrow_mut().as_deref_mut() {
|
match self.state.try_borrow_mut().as_deref_mut() {
|
||||||
Ok(Some(_)) => {
|
Ok(Some(_)) => {
|
||||||
unreachable!("tried to set handler while another was already set");
|
unreachable!("tried to set handler while another was already set");
|
||||||
},
|
},
|
||||||
@@ -69,7 +86,7 @@ impl EventHandler {
|
|||||||
|
|
||||||
impl Drop for ClearOnDrop<'_> {
|
impl Drop for ClearOnDrop<'_> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
match self.0.inner.try_borrow_mut().as_deref_mut() {
|
match self.0.state.try_borrow_mut().as_deref_mut() {
|
||||||
Ok(data @ Some(_)) => {
|
Ok(data @ Some(_)) => {
|
||||||
*data = None;
|
*data = None;
|
||||||
},
|
},
|
||||||
@@ -101,6 +118,10 @@ impl EventHandler {
|
|||||||
// soundness.
|
// soundness.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn init(&self) {}
|
||||||
|
|
||||||
|
fn terminate(&self) {}
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
pub(crate) fn in_use(&self) -> bool {
|
pub(crate) fn in_use(&self) -> bool {
|
||||||
self.inner.try_borrow().is_err()
|
self.inner.try_borrow().is_err()
|
||||||
@@ -120,7 +141,7 @@ impl EventHandler {
|
|||||||
//
|
//
|
||||||
// If the handler unwinds, the `RefMut` will ensure that the
|
// If the handler unwinds, the `RefMut` will ensure that the
|
||||||
// handler is no longer borrowed.
|
// handler is no longer borrowed.
|
||||||
callback(*user_app);
|
callback(user_app);
|
||||||
},
|
},
|
||||||
Ok(None) => {
|
Ok(None) => {
|
||||||
// `NSApplication`, our app state and this handler are all
|
// `NSApplication`, our app state and this handler are all
|
||||||
|
|||||||
@@ -360,15 +360,18 @@ impl EventLoop {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_app<A: ApplicationHandler>(self, app: A) -> Result<(), EventLoopError> {
|
pub fn run<A: ApplicationHandler>(
|
||||||
x11_or_wayland!(match self; EventLoop(evlp) => evlp.run_app(app))
|
self,
|
||||||
|
init_closure: impl FnOnce(&dyn ActiveEventLoop) -> A,
|
||||||
|
) -> Result<(), EventLoopError> {
|
||||||
|
x11_or_wayland!(match self; EventLoop(evlp) => evlp.run(init_closure))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_app_on_demand<A: ApplicationHandler>(
|
pub fn run_on_demand<A: ApplicationHandler>(
|
||||||
&mut self,
|
&mut self,
|
||||||
app: A,
|
init_closure: impl FnOnce(&dyn ActiveEventLoop) -> A,
|
||||||
) -> Result<(), EventLoopError> {
|
) -> Result<(), EventLoopError> {
|
||||||
x11_or_wayland!(match self; EventLoop(evlp) => evlp.run_app_on_demand(app))
|
x11_or_wayland!(match self; EventLoop(evlp) => evlp.run_on_demand(init_closure))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pump_app_events<A: ApplicationHandler>(
|
pub fn pump_app_events<A: ApplicationHandler>(
|
||||||
|
|||||||
@@ -146,15 +146,21 @@ impl EventLoop {
|
|||||||
Ok(event_loop)
|
Ok(event_loop)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_app<A: ApplicationHandler>(mut self, app: A) -> Result<(), EventLoopError> {
|
pub fn run<A: ApplicationHandler>(
|
||||||
self.run_app_on_demand(app)
|
mut self,
|
||||||
|
init_closure: impl FnOnce(&dyn RootActiveEventLoop) -> A,
|
||||||
|
) -> Result<(), EventLoopError> {
|
||||||
|
self.run_on_demand(init_closure)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_app_on_demand<A: ApplicationHandler>(
|
pub fn run_on_demand<A: ApplicationHandler>(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut app: A,
|
init_closure: impl FnOnce(&dyn RootActiveEventLoop) -> A,
|
||||||
) -> Result<(), EventLoopError> {
|
) -> Result<(), EventLoopError> {
|
||||||
self.active_event_loop.clear_exit();
|
self.active_event_loop.clear_exit();
|
||||||
|
|
||||||
|
let mut app = init_closure(&self.active_event_loop);
|
||||||
|
|
||||||
let exit = loop {
|
let exit = loop {
|
||||||
match self.pump_app_events(None, &mut app) {
|
match self.pump_app_events(None, &mut app) {
|
||||||
PumpStatus::Exit(0) => {
|
PumpStatus::Exit(0) => {
|
||||||
@@ -198,8 +204,6 @@ impl EventLoop {
|
|||||||
if let Some(code) = self.exit_code() {
|
if let Some(code) = self.exit_code() {
|
||||||
self.loop_running = false;
|
self.loop_running = false;
|
||||||
|
|
||||||
app.exiting(&self.active_event_loop);
|
|
||||||
|
|
||||||
PumpStatus::Exit(code)
|
PumpStatus::Exit(code)
|
||||||
} else {
|
} else {
|
||||||
PumpStatus::Continue
|
PumpStatus::Continue
|
||||||
|
|||||||
@@ -373,15 +373,21 @@ impl EventLoop {
|
|||||||
&self.event_processor.target
|
&self.event_processor.target
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_app<A: ApplicationHandler>(mut self, app: A) -> Result<(), EventLoopError> {
|
pub fn run<A: ApplicationHandler>(
|
||||||
self.run_app_on_demand(app)
|
mut self,
|
||||||
|
init_closure: impl FnOnce(&dyn RootActiveEventLoop) -> A,
|
||||||
|
) -> Result<(), EventLoopError> {
|
||||||
|
self.run_on_demand(init_closure)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_app_on_demand<A: ApplicationHandler>(
|
pub fn run_on_demand<A: ApplicationHandler>(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut app: A,
|
init_closure: impl FnOnce(&dyn RootActiveEventLoop) -> A,
|
||||||
) -> Result<(), EventLoopError> {
|
) -> Result<(), EventLoopError> {
|
||||||
self.event_processor.target.clear_exit();
|
self.event_processor.target.clear_exit();
|
||||||
|
|
||||||
|
let mut app = init_closure(&self.event_processor.target);
|
||||||
|
|
||||||
let exit = loop {
|
let exit = loop {
|
||||||
match self.pump_app_events(None, &mut app) {
|
match self.pump_app_events(None, &mut app) {
|
||||||
PumpStatus::Exit(0) => {
|
PumpStatus::Exit(0) => {
|
||||||
@@ -429,8 +435,6 @@ impl EventLoop {
|
|||||||
if let Some(code) = self.exit_code() {
|
if let Some(code) = self.exit_code() {
|
||||||
self.loop_running = false;
|
self.loop_running = false;
|
||||||
|
|
||||||
app.exiting(self.window_target());
|
|
||||||
|
|
||||||
PumpStatus::Exit(code)
|
PumpStatus::Exit(code)
|
||||||
} else {
|
} else {
|
||||||
PumpStatus::Continue
|
PumpStatus::Continue
|
||||||
|
|||||||
@@ -483,7 +483,11 @@ impl EventLoop {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_app<A: ApplicationHandler>(mut self, mut app: A) -> Result<(), EventLoopError> {
|
pub fn run<A: ApplicationHandler>(
|
||||||
|
mut self,
|
||||||
|
init_closure: impl FnOnce(&dyn RootActiveEventLoop) -> A,
|
||||||
|
) -> Result<(), EventLoopError> {
|
||||||
|
let mut app = init_closure(&self.window_target);
|
||||||
let mut start_cause = StartCause::Init;
|
let mut start_cause = StartCause::Init;
|
||||||
loop {
|
loop {
|
||||||
app.new_events(&self.window_target, start_cause);
|
app.new_events(&self.window_target, start_cause);
|
||||||
@@ -654,8 +658,6 @@ impl EventLoop {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
app.exiting(&self.window_target);
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -96,7 +96,6 @@ fn handle_event<A: ApplicationHandler>(app: &mut A, target: &ActiveEventLoop, ev
|
|||||||
Event::Resumed => app.resumed(target),
|
Event::Resumed => app.resumed(target),
|
||||||
Event::CreateSurfaces => app.can_create_surfaces(target),
|
Event::CreateSurfaces => app.can_create_surfaces(target),
|
||||||
Event::AboutToWait => app.about_to_wait(target),
|
Event::AboutToWait => app.about_to_wait(target),
|
||||||
Event::LoopExiting => app.exiting(target),
|
|
||||||
Event::MemoryWarning => app.memory_warning(target),
|
Event::MemoryWarning => app.memory_warning(target),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -609,7 +609,7 @@ impl Shared {
|
|||||||
self.apply_control_flow();
|
self.apply_control_flow();
|
||||||
// We don't call `handle_loop_destroyed` here because we don't need to
|
// We don't call `handle_loop_destroyed` here because we don't need to
|
||||||
// perform cleanup when the Web browser is going to destroy the page.
|
// perform cleanup when the Web browser is going to destroy the page.
|
||||||
self.handle_event(Event::LoopExiting);
|
todo!("drop the application handler");
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle_event takes in events and either queues them or applies a callback
|
// handle_event takes in events and either queues them or applies a callback
|
||||||
@@ -713,7 +713,7 @@ impl Shared {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handle_loop_destroyed(&self) {
|
fn handle_loop_destroyed(&self) {
|
||||||
self.handle_event(Event::LoopExiting);
|
todo!("drop the application handler");
|
||||||
let all_canvases = std::mem::take(&mut *self.0.all_canvases.borrow_mut());
|
let all_canvases = std::mem::take(&mut *self.0.all_canvases.borrow_mut());
|
||||||
*self.0.page_transition_event_handle.borrow_mut() = None;
|
*self.0.page_transition_event_handle.borrow_mut() = None;
|
||||||
*self.0.on_mouse_move.borrow_mut() = None;
|
*self.0.on_mouse_move.borrow_mut() = None;
|
||||||
|
|||||||
@@ -220,15 +220,21 @@ impl EventLoop {
|
|||||||
&self.window_target
|
&self.window_target
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_app<A: ApplicationHandler>(mut self, app: A) -> Result<(), EventLoopError> {
|
pub fn run<A: ApplicationHandler>(
|
||||||
self.run_app_on_demand(app)
|
mut self,
|
||||||
|
init_closure: impl FnOnce(&dyn RootActiveEventLoop) -> A,
|
||||||
|
) -> Result<(), EventLoopError> {
|
||||||
|
self.run_on_demand(init_closure)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_app_on_demand<A: ApplicationHandler>(
|
pub fn run_on_demand<A: ApplicationHandler>(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut app: A,
|
init_closure: impl FnOnce(&dyn RootActiveEventLoop) -> A,
|
||||||
) -> Result<(), EventLoopError> {
|
) -> Result<(), EventLoopError> {
|
||||||
self.window_target.clear_exit();
|
self.window_target.clear_exit();
|
||||||
|
|
||||||
|
let mut app = init_closure(&self.window_target);
|
||||||
|
|
||||||
{
|
{
|
||||||
let runner = &self.window_target.runner_shared;
|
let runner = &self.window_target.runner_shared;
|
||||||
|
|
||||||
@@ -250,7 +256,6 @@ impl EventLoop {
|
|||||||
Event::Resumed => app.resumed(event_loop_windows_ref),
|
Event::Resumed => app.resumed(event_loop_windows_ref),
|
||||||
Event::CreateSurfaces => app.can_create_surfaces(event_loop_windows_ref),
|
Event::CreateSurfaces => app.can_create_surfaces(event_loop_windows_ref),
|
||||||
Event::AboutToWait => app.about_to_wait(event_loop_windows_ref),
|
Event::AboutToWait => app.about_to_wait(event_loop_windows_ref),
|
||||||
Event::LoopExiting => app.exiting(event_loop_windows_ref),
|
|
||||||
Event::MemoryWarning => app.memory_warning(event_loop_windows_ref),
|
Event::MemoryWarning => app.memory_warning(event_loop_windows_ref),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -317,7 +322,6 @@ impl EventLoop {
|
|||||||
Event::Resumed => app.resumed(event_loop_windows_ref),
|
Event::Resumed => app.resumed(event_loop_windows_ref),
|
||||||
Event::CreateSurfaces => app.can_create_surfaces(event_loop_windows_ref),
|
Event::CreateSurfaces => app.can_create_surfaces(event_loop_windows_ref),
|
||||||
Event::AboutToWait => app.about_to_wait(event_loop_windows_ref),
|
Event::AboutToWait => app.about_to_wait(event_loop_windows_ref),
|
||||||
Event::LoopExiting => app.exiting(event_loop_windows_ref),
|
|
||||||
Event::MemoryWarning => app.memory_warning(event_loop_windows_ref),
|
Event::MemoryWarning => app.memory_warning(event_loop_windows_ref),
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -348,8 +352,10 @@ impl EventLoop {
|
|||||||
PumpStatus::Continue
|
PumpStatus::Continue
|
||||||
};
|
};
|
||||||
|
|
||||||
// We wait until we've checked for an exit status before clearing the
|
// We wait until we've checked for an exit status before clearing the application callback,
|
||||||
// application callback, in case we need to dispatch a LoopExiting event
|
// in case any of the methods above ends up triggering an event.
|
||||||
|
//
|
||||||
|
// This drops the user's `ApplicationHandler`.
|
||||||
//
|
//
|
||||||
// # Safety
|
// # Safety
|
||||||
// This pairs up with our call to `runner.set_event_handler` and ensures
|
// This pairs up with our call to `runner.set_event_handler` and ensures
|
||||||
|
|||||||
@@ -248,9 +248,8 @@ impl EventLoopRunner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Dispatch control flow events (`NewEvents`, `AboutToWait`, and
|
/// Dispatch control flow events (`new_events`, `about_to_wait`) as necessary to bring the
|
||||||
/// `LoopExiting`) as necessary to bring the internal `RunnerState` to the
|
/// internal `RunnerState` to the new runner state.
|
||||||
/// new runner state.
|
|
||||||
///
|
///
|
||||||
/// The state transitions are defined as follows:
|
/// The state transitions are defined as follows:
|
||||||
///
|
///
|
||||||
@@ -294,7 +293,6 @@ impl EventLoopRunner {
|
|||||||
self.call_new_events(true);
|
self.call_new_events(true);
|
||||||
self.call_event_handler(Event::AboutToWait);
|
self.call_event_handler(Event::AboutToWait);
|
||||||
self.last_events_cleared.set(Instant::now());
|
self.last_events_cleared.set(Instant::now());
|
||||||
self.call_event_handler(Event::LoopExiting);
|
|
||||||
},
|
},
|
||||||
(_, Uninitialized) => panic!("cannot move state to Uninitialized"),
|
(_, Uninitialized) => panic!("cannot move state to Uninitialized"),
|
||||||
|
|
||||||
@@ -302,9 +300,7 @@ impl EventLoopRunner {
|
|||||||
(Idle, HandlingMainEvents) => {
|
(Idle, HandlingMainEvents) => {
|
||||||
self.call_new_events(false);
|
self.call_new_events(false);
|
||||||
},
|
},
|
||||||
(Idle, Destroyed) => {
|
(Idle, Destroyed) => {},
|
||||||
self.call_event_handler(Event::LoopExiting);
|
|
||||||
},
|
|
||||||
|
|
||||||
(HandlingMainEvents, Idle) => {
|
(HandlingMainEvents, Idle) => {
|
||||||
// This is always the last event we dispatch before waiting for new events
|
// This is always the last event we dispatch before waiting for new events
|
||||||
@@ -314,7 +310,6 @@ impl EventLoopRunner {
|
|||||||
(HandlingMainEvents, Destroyed) => {
|
(HandlingMainEvents, Destroyed) => {
|
||||||
self.call_event_handler(Event::AboutToWait);
|
self.call_event_handler(Event::AboutToWait);
|
||||||
self.last_events_cleared.set(Instant::now());
|
self.last_events_cleared.set(Instant::now());
|
||||||
self.call_event_handler(Event::LoopExiting);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
(Destroyed, _) => panic!("cannot move state from Destroyed"),
|
(Destroyed, _) => panic!("cannot move state from Destroyed"),
|
||||||
|
|||||||
Reference in New Issue
Block a user