Move ControlFlow to EventLoopWindowTarget

Fixes #3042.
This commit is contained in:
daxpedda 2023-09-07 08:25:04 +02:00 committed by GitHub
parent 8fdd81ecef
commit e648169861
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
60 changed files with 800 additions and 860 deletions

View file

@ -20,6 +20,8 @@ And please only add new entries to the top of this list, right below the `# Unre
- On Wayland, fix `TouchPhase::Canceled` being sent for moved events.
- Mark `startup_notify` unsafe functions as safe.
- Fix a bug where Wayland would be chosen on Linux even if the user specified `with_x11`. (#3058)
- **Breaking:** Moved `ControlFlow` to `EventLoopWindowTarget::set_control_flow()` and `EventLoopWindowTarget::control_flow()`.
- **Breaking:** Moved `ControlFlow::Exit` to `EventLoopWindowTarget::set_exit()` and `EventLoopWindowTarget::exiting()` and removed `ControlFlow::ExitWithCode(_)` entirely.
# 0.29.1-beta

View file

@ -43,14 +43,14 @@ fn main() {
let event_loop = EventLoop::new();
let window = WindowBuilder::new().build(&event_loop).unwrap();
event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;
event_loop.run(move |event, elwt| {
elwt.set_control_flow(ControlFlow::Wait);
match event {
Event::WindowEvent {
event: WindowEvent::CloseRequested,
window_id,
} if window_id == window.id() => *control_flow = ControlFlow::Exit,
} if window_id == window.id() => elwt.exit(),
_ => (),
}
});

View file

@ -46,14 +46,14 @@ fn main() -> Result<(), impl std::error::Error> {
println!("parent window: {parent_window:?})");
event_loop.run(move |event: Event<()>, event_loop, control_flow| {
*control_flow = ControlFlow::Wait;
event_loop.run(move |event: Event<()>, elwt| {
elwt.set_control_flow(ControlFlow::Wait);
if let Event::WindowEvent { event, window_id } = event {
match event {
WindowEvent::CloseRequested => {
windows.clear();
*control_flow = ControlFlow::Exit;
elwt.exit();
}
WindowEvent::CursorEntered { device_id: _ } => {
// On x11, println when the cursor entered in a window even if the child window is created
@ -70,7 +70,7 @@ fn main() -> Result<(), impl std::error::Error> {
},
..
} => {
spawn_child_window(&parent_window, event_loop, &mut windows);
spawn_child_window(&parent_window, elwt, &mut windows);
}
WindowEvent::RedrawRequested => {
if let Some(window) = windows.get(&window_id) {

View file

@ -9,7 +9,7 @@ use web_time as time;
use simple_logger::SimpleLogger;
use winit::{
event::{ElementState, Event, KeyEvent, WindowEvent},
event_loop::EventLoop,
event_loop::{ControlFlow, EventLoop},
keyboard::Key,
window::WindowBuilder,
};
@ -47,7 +47,7 @@ fn main() -> Result<(), impl std::error::Error> {
let mut wait_cancelled = false;
let mut close_requested = false;
event_loop.run(move |event, _, control_flow| {
event_loop.run(move |event, elwt| {
use winit::event::StartCause;
println!("{event:?}");
match event {
@ -104,20 +104,22 @@ fn main() -> Result<(), impl std::error::Error> {
}
match mode {
Mode::Wait => control_flow.set_wait(),
Mode::Wait => elwt.set_control_flow(ControlFlow::Wait),
Mode::WaitUntil => {
if !wait_cancelled {
control_flow.set_wait_until(time::Instant::now() + WAIT_TIME);
elwt.set_control_flow(ControlFlow::WaitUntil(
time::Instant::now() + WAIT_TIME,
));
}
}
Mode::Poll => {
thread::sleep(POLL_SLEEP_TIME);
control_flow.set_poll();
elwt.set_control_flow(ControlFlow::Poll);
}
};
if close_requested {
control_flow.set_exit();
elwt.exit();
}
}
_ => (),

View file

@ -3,7 +3,7 @@
use simple_logger::SimpleLogger;
use winit::{
event::{ElementState, Event, KeyEvent, WindowEvent},
event_loop::EventLoop,
event_loop::{ControlFlow, EventLoop},
window::{CursorIcon, WindowBuilder},
};
@ -19,8 +19,8 @@ fn main() -> Result<(), impl std::error::Error> {
let mut cursor_idx = 0;
event_loop.run(move |event, _, control_flow| {
control_flow.set_wait();
event_loop.run(move |event, elwt| {
elwt.set_control_flow(ControlFlow::Wait);
if let Event::WindowEvent { event, .. } = event {
match event {
@ -44,7 +44,7 @@ fn main() -> Result<(), impl std::error::Error> {
fill::fill_window(&window);
}
WindowEvent::CloseRequested => {
control_flow.set_exit();
elwt.exit();
}
_ => (),
}

View file

@ -3,7 +3,7 @@
use simple_logger::SimpleLogger;
use winit::{
event::{DeviceEvent, ElementState, Event, KeyEvent, WindowEvent},
event_loop::EventLoop,
event_loop::{ControlFlow, EventLoop},
keyboard::{Key, ModifiersState},
window::{CursorGrabMode, WindowBuilder},
};
@ -22,12 +22,12 @@ fn main() -> Result<(), impl std::error::Error> {
let mut modifiers = ModifiersState::default();
event_loop.run(move |event, _, control_flow| {
control_flow.set_wait();
event_loop.run(move |event, elwt| {
elwt.set_control_flow(ControlFlow::Wait);
match event {
Event::WindowEvent { event, .. } => match event {
WindowEvent::CloseRequested => control_flow.set_exit(),
WindowEvent::CloseRequested => elwt.exit(),
WindowEvent::KeyboardInput {
event:
KeyEvent {
@ -39,7 +39,7 @@ fn main() -> Result<(), impl std::error::Error> {
} => {
let result = match key {
Key::Escape => {
control_flow.set_exit();
elwt.exit();
Ok(())
}
Key::Character(ch) => match ch.to_lowercase().as_str() {

View file

@ -5,7 +5,7 @@ fn main() -> Result<(), impl std::error::Error> {
use simple_logger::SimpleLogger;
use winit::{
event::{Event, WindowEvent},
event_loop::EventLoopBuilder,
event_loop::{ControlFlow, EventLoopBuilder},
window::WindowBuilder,
};
@ -40,15 +40,15 @@ fn main() -> Result<(), impl std::error::Error> {
}
});
event_loop.run(move |event, _, control_flow| {
control_flow.set_wait();
event_loop.run(move |event, elwt| {
elwt.set_control_flow(ControlFlow::Wait);
match event {
Event::UserEvent(event) => println!("user event: {event:?}"),
Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
} => control_flow.set_exit(),
} => elwt.exit(),
Event::WindowEvent {
event: WindowEvent::RedrawRequested,
..

View file

@ -21,12 +21,12 @@ fn main() -> Result<(), impl std::error::Error> {
let mut switched = false;
let mut entered_id = window_2.id();
event_loop.run(move |event, _, control_flow| match event {
event_loop.run(move |event, elwt| match event {
Event::NewEvents(StartCause::Init) => {
eprintln!("Switch which window is to be dragged by pressing \"x\".")
}
Event::WindowEvent { event, window_id } => match event {
WindowEvent::CloseRequested => control_flow.set_exit(),
WindowEvent::CloseRequested => elwt.exit(),
WindowEvent::MouseInput {
state: ElementState::Pressed,
button: MouseButton::Left,

View file

@ -3,7 +3,7 @@
use simple_logger::SimpleLogger;
use winit::dpi::PhysicalSize;
use winit::event::{ElementState, Event, KeyEvent, WindowEvent};
use winit::event_loop::EventLoop;
use winit::event_loop::{ControlFlow, EventLoop};
use winit::keyboard::Key;
use winit::window::{Fullscreen, WindowBuilder};
@ -52,12 +52,12 @@ fn main() -> Result<(), impl std::error::Error> {
println!("- I\tToggle mIn size limit");
println!("- A\tToggle mAx size limit");
event_loop.run(move |event, elwt, control_flow| {
control_flow.set_wait();
event_loop.run(move |event, elwt| {
elwt.set_control_flow(ControlFlow::Wait);
if let Event::WindowEvent { event, .. } = event {
match event {
WindowEvent::CloseRequested => control_flow.set_exit(),
WindowEvent::CloseRequested => elwt.exit(),
WindowEvent::KeyboardInput {
event:
KeyEvent {
@ -67,7 +67,7 @@ fn main() -> Result<(), impl std::error::Error> {
},
..
} => match key {
Key::Escape => control_flow.set_exit(),
Key::Escape => elwt.exit(),
// WARNING: Consider using `key_without_modifers()` if available on your platform.
// See the `key_binding` example
Key::Character(ch) => match ch.to_lowercase().as_str() {

View file

@ -3,7 +3,7 @@
use simple_logger::SimpleLogger;
use winit::{
event::{ElementState, Event, KeyEvent, WindowEvent},
event_loop::EventLoop,
event_loop::{ControlFlow, EventLoop},
keyboard::Key,
window::WindowBuilder,
};
@ -22,8 +22,8 @@ fn main() -> Result<(), impl std::error::Error> {
let mut close_requested = false;
event_loop.run(move |event, _, control_flow| {
control_flow.set_wait();
event_loop.run(move |event, elwt| {
elwt.set_control_flow(ControlFlow::Wait);
if let Event::WindowEvent { event, .. } = event {
match event {
@ -66,7 +66,7 @@ fn main() -> Result<(), impl std::error::Error> {
// event loop (i.e. if it's a multi-window application), you need to
// drop the window. That closes it, and results in `Destroyed` being
// sent.
control_flow.set_exit();
elwt.exit();
}
}
Key::Character("n") => {

View file

@ -39,11 +39,11 @@ fn main() -> Result<(), impl std::error::Error> {
let mut cursor_position = PhysicalPosition::new(0.0, 0.0);
let mut ime_pos = PhysicalPosition::new(0.0, 0.0);
event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;
event_loop.run(move |event, elwt| {
elwt.set_control_flow(ControlFlow::Wait);
if let Event::WindowEvent { event, .. } = event {
match event {
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
WindowEvent::CloseRequested => elwt.exit(),
WindowEvent::CursorMoved { position, .. } => {
cursor_position = position;
}

View file

@ -31,12 +31,12 @@ fn main() -> Result<(), impl std::error::Error> {
let mut modifiers = ModifiersState::default();
event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;
event_loop.run(move |event, elwt| {
elwt.set_control_flow(ControlFlow::Wait);
if let Event::WindowEvent { event, .. } = event {
match event {
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
WindowEvent::CloseRequested => elwt.exit(),
WindowEvent::ModifiersChanged(new) => {
modifiers = new.state();
}

View file

@ -3,7 +3,7 @@
use simple_logger::SimpleLogger;
use winit::{
event::{Event, WindowEvent},
event_loop::EventLoop,
event_loop::{ControlFlow, EventLoop},
window::WindowBuilder,
};
@ -34,12 +34,12 @@ In both cases the example window should move like the content of a scroll area i
In other words, the deltas indicate the direction in which to move the content (in this case the window)."
);
event_loop.run(move |event, _, control_flow| {
control_flow.set_wait();
event_loop.run(move |event, elwt| {
elwt.set_control_flow(ControlFlow::Wait);
if let Event::WindowEvent { event, .. } = event {
match event {
WindowEvent::CloseRequested => control_flow.set_exit(),
WindowEvent::CloseRequested => elwt.exit(),
WindowEvent::MouseWheel { delta, .. } => match delta {
winit::event::MouseScrollDelta::LineDelta(x, y) => {
println!("mouse wheel Line Delta: ({x},{y})");

View file

@ -8,7 +8,7 @@ fn main() -> Result<(), impl std::error::Error> {
use winit::{
dpi::{PhysicalPosition, PhysicalSize, Position, Size},
event::{ElementState, Event, KeyEvent, WindowEvent},
event_loop::EventLoop,
event_loop::{ControlFlow, EventLoop},
keyboard::{Key, ModifiersState},
window::{CursorGrabMode, CursorIcon, Fullscreen, WindowBuilder, WindowLevel},
};
@ -173,10 +173,10 @@ fn main() -> Result<(), impl std::error::Error> {
}
});
}
event_loop.run(move |event, _event_loop, control_flow| {
event_loop.run(move |event, elwt| {
match !window_senders.is_empty() {
true => control_flow.set_wait(),
false => control_flow.set_exit(),
true => elwt.set_control_flow(ControlFlow::Wait),
false => elwt.exit(),
};
match event {
Event::WindowEvent { event, window_id } => match event {

View file

@ -5,7 +5,7 @@ use std::collections::HashMap;
use simple_logger::SimpleLogger;
use winit::{
event::{ElementState, Event, KeyEvent, WindowEvent},
event_loop::EventLoop,
event_loop::{ControlFlow, EventLoop},
keyboard::Key,
window::Window,
};
@ -26,8 +26,8 @@ fn main() -> Result<(), impl std::error::Error> {
println!("Press N to open a new window.");
event_loop.run(move |event, event_loop, control_flow| {
control_flow.set_wait();
event_loop.run(move |event, elwt| {
elwt.set_control_flow(ControlFlow::Wait);
if let Event::WindowEvent { event, window_id } = event {
match event {
@ -38,7 +38,7 @@ fn main() -> Result<(), impl std::error::Error> {
windows.remove(&window_id);
if windows.is_empty() {
control_flow.set_exit();
elwt.exit();
}
}
WindowEvent::KeyboardInput {
@ -51,7 +51,7 @@ fn main() -> Result<(), impl std::error::Error> {
is_synthetic: false,
..
} if matches!(c.as_ref(), "n" | "N") => {
let window = Window::new(event_loop).unwrap();
let window = Window::new(elwt).unwrap();
println!("Opened a new window: {:?}", window.id());
windows.insert(window.id(), window);
}

View file

@ -3,7 +3,7 @@
use simple_logger::SimpleLogger;
use winit::{
event::{ElementState, Event, WindowEvent},
event_loop::EventLoop,
event_loop::{ControlFlow, EventLoop},
window::WindowBuilder,
};
@ -19,14 +19,14 @@ fn main() -> Result<(), impl std::error::Error> {
.build(&event_loop)
.unwrap();
event_loop.run(move |event, _, control_flow| {
event_loop.run(move |event, elwt| {
println!("{event:?}");
control_flow.set_wait();
elwt.set_control_flow(ControlFlow::Wait);
if let Event::WindowEvent { event, .. } = event {
match event {
WindowEvent::CloseRequested => control_flow.set_exit(),
WindowEvent::CloseRequested => elwt.exit(),
WindowEvent::MouseInput {
state: ElementState::Released,
..

View file

@ -7,7 +7,7 @@ fn main() -> Result<(), impl std::error::Error> {
use simple_logger::SimpleLogger;
use winit::{
event::{Event, WindowEvent},
event_loop::EventLoop,
event_loop::{ControlFlow, EventLoop},
window::WindowBuilder,
};
@ -33,16 +33,16 @@ fn main() -> Result<(), impl std::error::Error> {
}
});
event_loop.run(move |event, _, control_flow| {
event_loop.run(move |event, elwt| {
println!("{event:?}");
control_flow.set_wait();
elwt.set_control_flow(ControlFlow::Wait);
match event {
Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
} => control_flow.set_exit(),
} => elwt.exit(),
Event::WindowEvent {
event: WindowEvent::RedrawRequested,
..

View file

@ -4,7 +4,7 @@ use simple_logger::SimpleLogger;
use winit::{
dpi::LogicalSize,
event::{ElementState, Event, KeyEvent, WindowEvent},
event_loop::EventLoop,
event_loop::{ControlFlow, EventLoop},
keyboard::KeyCode,
window::WindowBuilder,
};
@ -27,12 +27,12 @@ fn main() -> Result<(), impl std::error::Error> {
.build(&event_loop)
.unwrap();
event_loop.run(move |event, _, control_flow| {
control_flow.set_wait();
event_loop.run(move |event, elwt| {
elwt.set_control_flow(ControlFlow::Wait);
if let Event::WindowEvent { event, .. } = event {
match event {
WindowEvent::CloseRequested => control_flow.set_exit(),
WindowEvent::CloseRequested => elwt.exit(),
WindowEvent::KeyboardInput {
event:
KeyEvent {

View file

@ -10,7 +10,7 @@ mod example {
use std::rc::Rc;
use winit::event::{ElementState, Event, KeyEvent, WindowEvent};
use winit::event_loop::EventLoop;
use winit::event_loop::{ControlFlow, EventLoop};
use winit::keyboard::Key;
use winit::platform::startup_notify::{
EventLoopExtStartupNotify, WindowBuilderExtStartupNotify, WindowExtStartupNotify,
@ -32,7 +32,7 @@ mod example {
let mut counter = 0;
let mut create_first_window = false;
event_loop.run(move |event, elwt, flow| {
event_loop.run(move |event, elwt| {
match event {
Event::Resumed => create_first_window = true,
@ -61,7 +61,7 @@ mod example {
// Remove the window from the map.
windows.remove(&window_id);
if windows.is_empty() {
flow.set_exit();
elwt.exit();
return;
}
}
@ -103,7 +103,7 @@ mod example {
create_first_window = false;
}
flow.set_wait();
elwt.set_control_flow(ControlFlow::Wait);
})
}
}

View file

@ -27,12 +27,12 @@ fn main() -> Result<(), impl std::error::Error> {
println!(" (L) Light theme");
println!(" (D) Dark theme");
event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;
event_loop.run(move |event, elwt| {
elwt.set_control_flow(ControlFlow::Wait);
if let Event::WindowEvent { window_id, event } = event {
match event {
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
WindowEvent::CloseRequested => elwt.exit(),
WindowEvent::ThemeChanged(theme) if window_id == window.id() => {
println!("Theme is changed: {theme:?}")
}

View file

@ -9,7 +9,7 @@ use web_time::Instant;
use simple_logger::SimpleLogger;
use winit::{
event::{Event, StartCause, WindowEvent},
event_loop::EventLoop,
event_loop::{ControlFlow, EventLoop},
window::WindowBuilder,
};
@ -27,21 +27,21 @@ fn main() -> Result<(), impl std::error::Error> {
let timer_length = Duration::new(1, 0);
event_loop.run(move |event, _, control_flow| {
event_loop.run(move |event, elwt| {
println!("{event:?}");
match event {
Event::NewEvents(StartCause::Init) => {
control_flow.set_wait_until(Instant::now() + timer_length);
elwt.set_control_flow(ControlFlow::WaitUntil(Instant::now() + timer_length));
}
Event::NewEvents(StartCause::ResumeTimeReached { .. }) => {
control_flow.set_wait_until(Instant::now() + timer_length);
elwt.set_control_flow(ControlFlow::WaitUntil(Instant::now() + timer_length));
println!("\nTimer\n");
}
Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
} => control_flow.set_exit(),
} => elwt.exit(),
Event::WindowEvent {
event: WindowEvent::RedrawRequested,
..

View file

@ -19,12 +19,12 @@ fn main() -> Result<(), impl std::error::Error> {
println!("Only supported on macOS at the moment.");
event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;
event_loop.run(move |event, elwt| {
elwt.set_control_flow(ControlFlow::Wait);
if let Event::WindowEvent { event, .. } = event {
match event {
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
WindowEvent::CloseRequested => elwt.exit(),
WindowEvent::TouchpadMagnify { delta, .. } => {
if delta > 0.0 {
println!("Zoomed in {delta}");

View file

@ -3,7 +3,7 @@
use simple_logger::SimpleLogger;
use winit::{
event::{Event, WindowEvent},
event_loop::EventLoop,
event_loop::{ControlFlow, EventLoop},
window::WindowBuilder,
};
@ -22,13 +22,13 @@ fn main() -> Result<(), impl std::error::Error> {
window.set_title("A fantastic window!");
event_loop.run(move |event, _, control_flow| {
control_flow.set_wait();
event_loop.run(move |event, elwt| {
elwt.set_control_flow(ControlFlow::Wait);
println!("{event:?}");
if let Event::WindowEvent { event, .. } = event {
match event {
WindowEvent::CloseRequested => control_flow.set_exit(),
WindowEvent::CloseRequested => elwt.exit(),
WindowEvent::RedrawRequested => {
fill::fill_window(&window);
}

View file

@ -2,7 +2,7 @@
use winit::{
event::{ElementState, Event, KeyEvent, WindowEvent},
event_loop::EventLoop,
event_loop::{ControlFlow, EventLoop},
keyboard::KeyCode,
window::{Fullscreen, WindowBuilder},
};
@ -21,8 +21,8 @@ pub fn main() -> Result<(), impl std::error::Error> {
#[cfg(wasm_platform)]
let log_list = wasm::insert_canvas_and_create_log_list(&window);
event_loop.run(move |event, _, control_flow| {
control_flow.set_wait();
event_loop.run(move |event, elwt| {
elwt.set_control_flow(ControlFlow::Wait);
#[cfg(wasm_platform)]
wasm::log_event(&log_list, &event);
@ -31,7 +31,7 @@ pub fn main() -> Result<(), impl std::error::Error> {
Event::WindowEvent {
event: WindowEvent::CloseRequested,
window_id,
} if window_id == window.id() => control_flow.set_exit(),
} if window_id == window.id() => elwt.exit(),
Event::AboutToWait => {
window.request_redraw();
}

View file

@ -47,8 +47,8 @@ This example demonstrates the desired future functionality which will possibly b
// Render once with the size info we currently have
render_circle(&canvas, window.inner_size());
let _ = event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;
let _ = event_loop.run(move |event, elwt| {
elwt.set_control_flow(ControlFlow::Wait);
match event {
Event::WindowEvent {

View file

@ -3,7 +3,7 @@
use simple_logger::SimpleLogger;
use winit::{
event::{Event, WindowEvent},
event_loop::EventLoop,
event_loop::{ControlFlow, EventLoop},
window::WindowBuilder,
};
@ -20,13 +20,13 @@ fn main() -> Result<(), impl std::error::Error> {
.build(&event_loop)
.unwrap();
event_loop.run(move |event, _, control_flow| {
control_flow.set_wait();
event_loop.run(move |event, elwt| {
elwt.set_control_flow(ControlFlow::Wait);
println!("{event:?}");
match event {
Event::WindowEvent { event, window_id } if window_id == window.id() => match event {
WindowEvent::CloseRequested => control_flow.set_exit(),
WindowEvent::CloseRequested => elwt.exit(),
WindowEvent::RedrawRequested => {
// Notify the windowing system that we'll be presenting to the window.
window.pre_present_notify();

View file

@ -6,7 +6,7 @@ use simple_logger::SimpleLogger;
use winit::{
dpi::LogicalSize,
event::{ElementState, Event, KeyEvent, WindowEvent},
event_loop::{DeviceEvents, EventLoop},
event_loop::{ControlFlow, DeviceEvents, EventLoop},
keyboard::Key,
window::{WindowBuilder, WindowButtons},
};
@ -31,8 +31,8 @@ fn main() -> Result<(), impl std::error::Error> {
event_loop.listen_device_events(DeviceEvents::Always);
event_loop.run(move |event, _, control_flow| {
control_flow.set_wait();
event_loop.run(move |event, elwt| {
elwt.set_control_flow(ControlFlow::Wait);
if let Event::WindowEvent { window_id, event } = event {
match event {
@ -59,7 +59,7 @@ fn main() -> Result<(), impl std::error::Error> {
}
_ => (),
},
WindowEvent::CloseRequested if window_id == window.id() => control_flow.set_exit(),
WindowEvent::CloseRequested if window_id == window.id() => elwt.exit(),
WindowEvent::RedrawRequested => {
fill::fill_window(&window);
}

View file

@ -6,7 +6,7 @@ use simple_logger::SimpleLogger;
use winit::{
dpi::{LogicalSize, PhysicalSize},
event::{DeviceEvent, ElementState, Event, KeyEvent, RawKeyEvent, WindowEvent},
event_loop::{DeviceEvents, EventLoop},
event_loop::{ControlFlow, DeviceEvents, EventLoop},
keyboard::{Key, KeyCode},
window::{Fullscreen, WindowBuilder},
};
@ -38,8 +38,8 @@ fn main() -> Result<(), impl std::error::Error> {
event_loop.listen_device_events(DeviceEvents::Always);
event_loop.run(move |event, _, control_flow| {
control_flow.set_wait();
event_loop.run(move |event, elwt| {
elwt.set_control_flow(ControlFlow::Wait);
match event {
// This used to use the virtual key, but the new API
@ -115,7 +115,7 @@ fn main() -> Result<(), impl std::error::Error> {
window.set_minimized(minimized);
}
"q" => {
control_flow.set_exit();
elwt.exit();
}
"v" => {
visible = !visible;
@ -127,7 +127,7 @@ fn main() -> Result<(), impl std::error::Error> {
}
_ => (),
},
WindowEvent::CloseRequested if window_id == window.id() => control_flow.set_exit(),
WindowEvent::CloseRequested if window_id == window.id() => elwt.exit(),
WindowEvent::RedrawRequested => {
fill::fill_window(&window);
}

View file

@ -3,7 +3,7 @@
use simple_logger::SimpleLogger;
use winit::{
event::{ElementState, Event, KeyEvent, MouseButton, StartCause, WindowEvent},
event_loop::{ControlFlow, EventLoop},
event_loop::EventLoop,
keyboard::Key,
window::{CursorIcon, ResizeDirection, WindowBuilder},
};
@ -27,12 +27,12 @@ fn main() -> Result<(), impl std::error::Error> {
let mut border = false;
let mut cursor_location = None;
event_loop.run(move |event, _, control_flow| match event {
event_loop.run(move |event, elwt| match event {
Event::NewEvents(StartCause::Init) => {
eprintln!("Press 'B' to toggle borderless")
}
Event::WindowEvent { event, .. } => match event {
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
WindowEvent::CloseRequested => elwt.exit(),
WindowEvent::CursorMoved { position, .. } => {
if !window.is_decorated() {
let new_location =

View file

@ -5,7 +5,7 @@ use std::path::Path;
use simple_logger::SimpleLogger;
use winit::{
event::{Event, WindowEvent},
event_loop::EventLoop,
event_loop::{ControlFlow, EventLoop},
window::{Icon, WindowBuilder},
};
@ -33,12 +33,12 @@ fn main() -> Result<(), impl std::error::Error> {
.build(&event_loop)
.unwrap();
event_loop.run(move |event, _, control_flow| {
control_flow.set_wait();
event_loop.run(move |event, elwt| {
elwt.set_control_flow(ControlFlow::Wait);
if let Event::WindowEvent { event, .. } = event {
match event {
WindowEvent::CloseRequested => control_flow.set_exit(),
WindowEvent::CloseRequested => elwt.exit(),
WindowEvent::DroppedFile(path) => {
window.set_window_icon(Some(load_icon(&path)));
}

View file

@ -10,7 +10,7 @@ fn main() -> Result<(), impl std::error::Error> {
use winit::{
error::EventLoopError,
event::{Event, WindowEvent},
event_loop::EventLoop,
event_loop::{ControlFlow, EventLoop},
platform::run_ondemand::EventLoopExtRunOnDemand,
window::{Window, WindowBuilder, WindowId},
};
@ -30,8 +30,8 @@ fn main() -> Result<(), impl std::error::Error> {
fn run_app(event_loop: &mut EventLoop<()>, idx: usize) -> Result<(), EventLoopError> {
let mut app = App::default();
event_loop.run_ondemand(move |event, event_loop, control_flow| {
control_flow.set_wait();
event_loop.run_ondemand(move |event, elwt| {
elwt.set_control_flow(ControlFlow::Wait);
println!("Run {idx}: {:?}", event);
if let Some(window) = &app.window {
@ -60,7 +60,7 @@ fn main() -> Result<(), impl std::error::Error> {
} if id == window_id => {
println!("--------------------------------------------------------- Window {idx} Destroyed");
app.window_id = None;
control_flow.set_exit();
elwt.exit();
}
_ => (),
}
@ -68,7 +68,7 @@ fn main() -> Result<(), impl std::error::Error> {
let window = WindowBuilder::new()
.with_title("Fantastic window number one!")
.with_inner_size(winit::dpi::LogicalSize::new(128.0, 128.0))
.build(event_loop)
.build(elwt)
.unwrap();
app.window_id = Some(window.id());
app.window = Some(window);

View file

@ -7,7 +7,7 @@ use winit::platform::macos::{OptionAsAlt, WindowExtMacOS};
use winit::{
event::ElementState,
event::{Event, MouseButton, WindowEvent},
event_loop::EventLoop,
event_loop::{ControlFlow, EventLoop},
window::WindowBuilder,
};
@ -31,14 +31,14 @@ fn main() -> Result<(), impl std::error::Error> {
let mut option_as_alt = window.option_as_alt();
event_loop.run(move |event, _, control_flow| {
control_flow.set_wait();
event_loop.run(move |event, elwt| {
elwt.set_control_flow(ControlFlow::Wait);
match event {
Event::WindowEvent {
event: WindowEvent::CloseRequested,
window_id,
} if window_id == window.id() => control_flow.set_exit(),
} if window_id == window.id() => elwt.exit(),
Event::WindowEvent { event, .. } => match event {
WindowEvent::MouseInput {
state: ElementState::Pressed,

View file

@ -32,8 +32,8 @@ fn main() -> std::process::ExitCode {
'main: loop {
let timeout = Some(Duration::ZERO);
let status = event_loop.pump_events(timeout, |event, _, control_flow| {
*control_flow = ControlFlow::Wait;
let status = event_loop.pump_events(timeout, |event, elwt| {
elwt.set_control_flow(ControlFlow::Wait);
if let Event::WindowEvent { event, .. } = &event {
// Print only Window events to reduce noise
@ -44,7 +44,7 @@ fn main() -> std::process::ExitCode {
Event::WindowEvent {
event: WindowEvent::CloseRequested,
window_id,
} if window_id == window.id() => control_flow.set_exit(),
} if window_id == window.id() => elwt.exit(),
Event::AboutToWait => {
window.request_redraw();
}

View file

@ -3,7 +3,7 @@ use simple_logger::SimpleLogger;
use winit::{
dpi::LogicalSize,
event::{ElementState, Event, KeyEvent, WindowEvent},
event_loop::EventLoop,
event_loop::{ControlFlow, EventLoop},
keyboard::Key,
window::WindowBuilder,
};
@ -24,12 +24,12 @@ fn main() -> Result<(), impl std::error::Error> {
let mut has_increments = true;
event_loop.run(move |event, _, control_flow| {
control_flow.set_wait();
event_loop.run(move |event, elwt| {
elwt.set_control_flow(ControlFlow::Wait);
match event {
Event::WindowEvent { event, window_id } if window_id == window.id() => match event {
WindowEvent::CloseRequested => control_flow.set_exit(),
WindowEvent::CloseRequested => elwt.exit(),
WindowEvent::KeyboardInput {
event:
KeyEvent {

View file

@ -8,7 +8,7 @@ use simple_logger::SimpleLogger;
#[cfg(target_os = "macos")]
use winit::{
event::{ElementState, Event, KeyEvent, WindowEvent},
event_loop::EventLoop,
event_loop::{ControlFlow, EventLoop},
keyboard::Key,
platform::macos::{WindowBuilderExtMacOS, WindowExtMacOS},
window::{Window, WindowBuilder},
@ -30,8 +30,8 @@ fn main() -> Result<(), impl std::error::Error> {
println!("Press N to open a new window.");
event_loop.run(move |event, event_loop, control_flow| {
control_flow.set_wait();
event_loop.run(move |event, elwt| {
elwt.set_control_flow(ControlFlow::Wait);
if let Event::WindowEvent { event, window_id } = event {
match event {
@ -42,7 +42,7 @@ fn main() -> Result<(), impl std::error::Error> {
windows.remove(&window_id);
if windows.is_empty() {
control_flow.set_exit();
elwt.exit();
}
}
WindowEvent::Resized(_) => {
@ -64,7 +64,7 @@ fn main() -> Result<(), impl std::error::Error> {
let tabbing_id = windows.get(&window_id).unwrap().tabbing_identifier();
let window = WindowBuilder::new()
.with_tabbing_identifier(&tabbing_id)
.build(event_loop)
.build(elwt)
.unwrap();
println!("Added a new tab: {:?}", window.id());
windows.insert(window.id(), window);

View file

@ -10,7 +10,7 @@ mod imple {
use simple_logger::SimpleLogger;
use winit::{
event::{Event, WindowEvent},
event_loop::EventLoop,
event_loop::{ControlFlow, EventLoop},
platform::x11::WindowBuilderExtX11,
window::WindowBuilder,
};
@ -32,14 +32,14 @@ mod imple {
.build(&event_loop)
.unwrap();
event_loop.run(move |event, _, control_flow| {
control_flow.set_wait();
event_loop.run(move |event, elwt| {
elwt.set_control_flow(ControlFlow::Wait);
match event {
Event::WindowEvent {
event: WindowEvent::CloseRequested,
window_id,
} if window_id == window.id() => control_flow.set_exit(),
} if window_id == window.id() => elwt.exit(),
Event::AboutToWait => {
window.request_redraw();
}

View file

@ -7,25 +7,24 @@
//! approximate the basic ordering loop of [`EventLoop::run(...)`] like this:
//!
//! ```rust,ignore
//! let mut control_flow = ControlFlow::Poll;
//! let mut start_cause = StartCause::Init;
//!
//! while control_flow != ControlFlow::Exit {
//! event_handler(NewEvents(start_cause), ..., &mut control_flow);
//! while !elwt.exiting() {
//! event_handler(NewEvents(start_cause), elwt);
//!
//! for e in (window events, user events, device events) {
//! event_handler(e, ..., &mut control_flow);
//! event_handler(e, elwt);
//! }
//!
//! for w in (redraw windows) {
//! event_handler(RedrawRequested(w), ..., &mut control_flow);
//! event_handler(RedrawRequested(w), elwt);
//! }
//!
//! event_handler(AboutToWait, ..., &mut control_flow);
//! start_cause = wait_if_necessary(control_flow);
//! event_handler(AboutToWait, elwt);
//! start_cause = wait_if_necessary();
//! }
//!
//! event_handler(LoopExiting, ..., &mut control_flow);
//! event_handler(LoopExiting, elwt);
//! ```
//!
//! This leaves out timing details like [`ControlFlow::WaitUntil`] but hopefully

View file

@ -147,20 +147,12 @@ impl<T> fmt::Debug for EventLoopWindowTarget<T> {
}
}
/// Set by the user callback given to the [`EventLoop::run`] method.
/// Set through [`EventLoopWindowTarget::set_control_flow()`].
///
/// Indicates the desired behavior of the event loop after [`Event::AboutToWait`] is emitted.
///
/// Defaults to [`Poll`].
///
/// ## Persistency
///
/// Almost every change is persistent between multiple calls to the event loop closure within a
/// given run loop. The only exception to this is [`ExitWithCode`] which, once set, cannot be unset.
/// Changes are **not** persistent between multiple calls to `run_ondemand` - issuing a new call will
/// reset the control flow to [`Poll`].
///
/// [`ExitWithCode`]: Self::ExitWithCode
/// [`Poll`]: Self::Poll
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum ControlFlow {
@ -180,81 +172,22 @@ pub enum ControlFlow {
///
/// [`Poll`]: Self::Poll
WaitUntil(Instant),
/// Send a [`LoopExiting`] event and stop the event loop. This variant is *sticky* - once set,
/// `control_flow` cannot be changed from `ExitWithCode`, and any future attempts to do so will
/// result in the `control_flow` parameter being reset to `ExitWithCode`.
///
/// The contained number will be used as exit code. The [`Exit`] constant is a shortcut for this
/// with exit code 0.
///
/// ## Platform-specific
///
/// - **Android / iOS / Web:** The supplied exit code is unused.
/// - **Unix:** On most Unix-like platforms, only the 8 least significant bits will be used,
/// which can cause surprises with negative exit values (`-42` would end up as `214`). See
/// [`std::process::exit`].
///
/// [`LoopExiting`]: Event::LoopExiting
/// [`Exit`]: ControlFlow::Exit
ExitWithCode(i32),
}
impl ControlFlow {
/// Alias for [`ExitWithCode`]`(0)`.
///
/// [`ExitWithCode`]: Self::ExitWithCode
#[allow(non_upper_case_globals)]
pub const Exit: Self = Self::ExitWithCode(0);
/// Sets this to [`Poll`].
///
/// [`Poll`]: Self::Poll
pub fn set_poll(&mut self) {
*self = Self::Poll;
}
/// Sets this to [`Wait`].
///
/// [`Wait`]: Self::Wait
pub fn set_wait(&mut self) {
*self = Self::Wait;
}
/// Sets this to [`WaitUntil`]`(instant)`.
///
/// [`WaitUntil`]: Self::WaitUntil
pub fn set_wait_until(&mut self, instant: Instant) {
*self = Self::WaitUntil(instant);
}
/// Sets this to wait until a timeout has expired.
/// Creates a [`ControlFlow`] that waits until a timeout has expired.
///
/// In most cases, this is set to [`WaitUntil`]. However, if the timeout overflows, it is
/// instead set to [`Wait`].
///
/// [`WaitUntil`]: Self::WaitUntil
/// [`Wait`]: Self::Wait
pub fn set_wait_timeout(&mut self, timeout: Duration) {
pub fn wait_duration(timeout: Duration) -> Self {
match Instant::now().checked_add(timeout) {
Some(instant) => self.set_wait_until(instant),
None => self.set_wait(),
Some(instant) => Self::WaitUntil(instant),
None => Self::Wait,
}
}
/// Sets this to [`ExitWithCode`]`(code)`.
///
/// [`ExitWithCode`]: Self::ExitWithCode
pub fn set_exit_with_code(&mut self, code: i32) {
*self = Self::ExitWithCode(code);
}
/// Sets this to [`Exit`].
///
/// [`Exit`]: Self::Exit
pub fn set_exit(&mut self) {
*self = Self::Exit;
}
}
impl Default for ControlFlow {
@ -286,8 +219,7 @@ impl<T> EventLoop<T> {
/// Since the closure is `'static`, it must be a `move` closure if it needs to
/// access any data from the calling context.
///
/// See the [`ControlFlow`] docs for information on how changes to `&mut ControlFlow` impact the
/// event loop's behavior.
/// See the [`set_control_flow()`] docs on how to change the event loop's behavior.
///
/// ## Platform-specific
///
@ -306,12 +238,12 @@ impl<T> EventLoop<T> {
///
/// This function won't be available with `target_feature = "exception-handling"`.
///
/// [`ControlFlow`]: crate::event_loop::ControlFlow
/// [`set_control_flow()`]: EventLoopWindowTarget::set_control_flow
#[inline]
#[cfg(not(all(wasm_platform, target_feature = "exception-handling")))]
pub fn run<F>(self, event_handler: F) -> Result<(), EventLoopError>
where
F: FnMut(Event<T>, &EventLoopWindowTarget<T>, &mut ControlFlow),
F: FnMut(Event<T>, &EventLoopWindowTarget<T>),
{
self.event_loop.run(event_handler)
}
@ -377,6 +309,30 @@ impl<T> EventLoopWindowTarget<T> {
pub fn listen_device_events(&self, allowed: DeviceEvents) {
self.p.listen_device_events(allowed);
}
/// Sets the [`ControlFlow`].
pub fn set_control_flow(&self, control_flow: ControlFlow) {
self.p.set_control_flow(control_flow)
}
/// Gets the current [`ControlFlow`].
pub fn control_flow(&self) -> ControlFlow {
self.p.control_flow()
}
/// This exits the event loop.
///
/// See [`LoopExiting`](Event::LoopExiting).
pub fn exit(&self) {
self.p.exit()
}
/// Returns if the [`EventLoop`] is about to stop.
///
/// See [`exit()`](Self::exit).
pub fn exiting(&self) -> bool {
self.p.exiting()
}
}
unsafe impl<T> HasRawDisplayHandle for EventLoopWindowTarget<T> {

View file

@ -30,8 +30,7 @@
//!
//! You can retrieve events by calling [`EventLoop::run`][event_loop_run]. This function will
//! dispatch events for every [`Window`] that was created with that particular [`EventLoop`], and
//! will run until the `control_flow` argument given to the closure is set to
//! [`ControlFlow`]`::`[`ExitWithCode`] (which [`ControlFlow`]`::`[`Exit`] aliases to), at which
//! will run until [`exit()`] is used, at which
//! point [`Event`]`::`[`LoopExiting`] is emitted and the entire program terminates.
//!
//! Winit no longer uses a `EventLoop::poll_events() -> impl Iterator<Event>`-based event loop
@ -44,30 +43,29 @@
//! ```no_run
//! use winit::{
//! event::{Event, WindowEvent},
//! event_loop::EventLoop,
//! event_loop::{ControlFlow, EventLoop},
//! window::WindowBuilder,
//! };
//!
//! let event_loop = EventLoop::new().unwrap();
//! let window = WindowBuilder::new().build(&event_loop).unwrap();
//!
//! event_loop.run(move |event, _, control_flow| {
//! event_loop.run(move |event, elwt| {
//! // ControlFlow::Poll continuously runs the event loop, even if the OS hasn't
//! // dispatched any events. This is ideal for games and similar applications.
//! control_flow.set_poll();
//! elwt.set_control_flow(ControlFlow::Poll);
//!
//! // ControlFlow::Wait pauses the event loop if no events are available to process.
//! // This is ideal for non-game applications that only update in response to user
//! // input, and uses significantly less power/CPU time than ControlFlow::Poll.
//! control_flow.set_wait();
//!
//! elwt.set_control_flow(ControlFlow::Wait);
//! match event {
//! Event::WindowEvent {
//! event: WindowEvent::CloseRequested,
//! ..
//! } => {
//! println!("The close button was pressed; stopping");
//! control_flow.set_exit();
//! elwt.exit();
//! },
//! Event::AboutToWait => {
//! // Application update code.
@ -115,9 +113,7 @@
//! [`EventLoopExtPumpEvents::pump_events`]: ./platform/pump_events/trait.EventLoopExtPumpEvents.html#tymethod.pump_events
//! [`EventLoop::new()`]: event_loop::EventLoop::new
//! [event_loop_run]: event_loop::EventLoop::run
//! [`ControlFlow`]: event_loop::ControlFlow
//! [`Exit`]: event_loop::ControlFlow::Exit
//! [`ExitWithCode`]: event_loop::ControlFlow::ExitWithCode
//! [`exit()`]: event_loop::EventLoopWindowTarget::exit
//! [`Window`]: window::Window
//! [`WindowId`]: window::WindowId
//! [`WindowBuilder`]: window::WindowBuilder

View file

@ -2,7 +2,7 @@ use std::time::Duration;
use crate::{
event::Event,
event_loop::{ControlFlow, EventLoop, EventLoopWindowTarget},
event_loop::{EventLoop, EventLoopWindowTarget},
};
/// The return status for `pump_events`
@ -63,7 +63,7 @@ pub trait EventLoopExtPumpEvents {
///
/// 'main: loop {
/// let timeout = Some(Duration::ZERO);
/// let status = event_loop.pump_events(timeout, |event, _, control_flow| {
/// let status = event_loop.pump_events(timeout, |event, elwt| {
/// # if let Event::WindowEvent { event, .. } = &event {
/// # // Print only Window events to reduce noise
/// # println!("{event:?}");
@ -73,7 +73,7 @@ pub trait EventLoopExtPumpEvents {
/// Event::WindowEvent {
/// event: WindowEvent::CloseRequested,
/// window_id,
/// } if window_id == window.id() => control_flow.set_exit(),
/// } if window_id == window.id() => elwt.exit(),
/// Event::AboutToWait => {
/// window.request_redraw();
/// }
@ -174,7 +174,7 @@ pub trait EventLoopExtPumpEvents {
/// callback.
fn pump_events<F>(&mut self, timeout: Option<Duration>, event_handler: F) -> PumpStatus
where
F: FnMut(Event<Self::UserEvent>, &EventLoopWindowTarget<Self::UserEvent>, &mut ControlFlow);
F: FnMut(Event<Self::UserEvent>, &EventLoopWindowTarget<Self::UserEvent>);
}
impl<T> EventLoopExtPumpEvents for EventLoop<T> {
@ -182,7 +182,7 @@ impl<T> EventLoopExtPumpEvents for EventLoop<T> {
fn pump_events<F>(&mut self, timeout: Option<Duration>, event_handler: F) -> PumpStatus
where
F: FnMut(Event<Self::UserEvent>, &EventLoopWindowTarget<Self::UserEvent>, &mut ControlFlow),
F: FnMut(Event<Self::UserEvent>, &EventLoopWindowTarget<Self::UserEvent>),
{
self.event_loop.pump_events(timeout, event_handler)
}

View file

@ -1,7 +1,7 @@
use crate::{
error::EventLoopError,
event::Event,
event_loop::{ControlFlow, EventLoop, EventLoopWindowTarget},
event_loop::{EventLoop, EventLoopWindowTarget},
};
#[cfg(doc)]
@ -17,7 +17,7 @@ pub trait EventLoopExtRunOnDemand {
///
/// 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
/// consuming the `EventLoop` (by setting the `control_flow` to [`ControlFlow::Exit`]) and
/// consuming the `EventLoop` (by using [`exit()`]) and
/// so the event loop can be re-run after it has exit.
///
/// It's expected that each run of the loop will be for orthogonal instantiations of your
@ -32,8 +32,7 @@ pub trait EventLoopExtRunOnDemand {
/// `NewEvents(Init)` and `Resumed` event (even on platforms that have no suspend/resume
/// lifecycle) - which can be used to consistently initialize application state.
///
/// See the [`ControlFlow`] docs for information on how changes to `&mut ControlFlow` impact the
/// event loop's behavior.
/// See the [`set_control_flow()`] docs on how to change the event loop's behavior.
///
/// # Caveats
/// - This extension isn't available on all platforms, since it's not always possible to
@ -57,9 +56,12 @@ pub trait EventLoopExtRunOnDemand {
/// polled to ask for new events. Events are delivered via callbacks based
/// on an event loop that is internal to the browser itself.
/// - **iOS:** It's not possible to stop and start an `NSApplication` repeatedly on iOS.
///
/// [`exit()`]: EventLoopWindowTarget::exit
/// [`set_control_flow()`]: EventLoopWindowTarget::set_control_flow
fn run_ondemand<F>(&mut self, event_handler: F) -> Result<(), EventLoopError>
where
F: FnMut(Event<Self::UserEvent>, &EventLoopWindowTarget<Self::UserEvent>, &mut ControlFlow);
F: FnMut(Event<Self::UserEvent>, &EventLoopWindowTarget<Self::UserEvent>);
}
impl<T> EventLoopExtRunOnDemand for EventLoop<T> {
@ -67,7 +69,7 @@ impl<T> EventLoopExtRunOnDemand for EventLoop<T> {
fn run_ondemand<F>(&mut self, event_handler: F) -> Result<(), EventLoopError>
where
F: FnMut(Event<Self::UserEvent>, &EventLoopWindowTarget<Self::UserEvent>, &mut ControlFlow),
F: FnMut(Event<Self::UserEvent>, &EventLoopWindowTarget<Self::UserEvent>),
{
self.event_loop.run_ondemand(event_handler)
}

View file

@ -28,7 +28,6 @@
//! [`padding`]: https://developer.mozilla.org/en-US/docs/Web/CSS/padding
use crate::event::Event;
use crate::event_loop::ControlFlow;
use crate::event_loop::EventLoop;
use crate::event_loop::EventLoopWindowTarget;
use crate::window::{Window, WindowBuilder};
@ -122,8 +121,7 @@ pub trait EventLoopExtWebSys {
/// event loop when switching between tabs on a single page application.
fn spawn<F>(self, event_handler: F)
where
F: 'static
+ FnMut(Event<Self::UserEvent>, &EventLoopWindowTarget<Self::UserEvent>, &mut ControlFlow);
F: 'static + FnMut(Event<Self::UserEvent>, &EventLoopWindowTarget<Self::UserEvent>);
}
impl<T> EventLoopExtWebSys for EventLoop<T> {
@ -131,8 +129,7 @@ impl<T> EventLoopExtWebSys for EventLoop<T> {
fn spawn<F>(self, event_handler: F)
where
F: 'static
+ FnMut(Event<Self::UserEvent>, &EventLoopWindowTarget<Self::UserEvent>, &mut ControlFlow),
F: 'static + FnMut(Event<Self::UserEvent>, &EventLoopWindowTarget<Self::UserEvent>),
{
self.event_loop.spawn(event_handler)
}

View file

@ -1,6 +1,7 @@
#![cfg(android_platform)]
use std::{
cell::Cell,
collections::VecDeque,
hash::Hash,
sync::{
@ -147,7 +148,6 @@ pub struct EventLoop<T: 'static> {
loop_running: bool, // Dispatched `NewEvents<Init>`
running: bool,
pending_redraw: bool,
control_flow: ControlFlow,
cause: StartCause,
ignore_volume_keys: bool,
combining_accent: Option<char>,
@ -168,23 +168,6 @@ impl Default for PlatformSpecificEventLoopAttributes {
}
}
fn sticky_exit_callback<T, F>(
evt: event::Event<T>,
target: &RootELW<T>,
control_flow: &mut ControlFlow,
callback: &mut F,
) where
F: FnMut(event::Event<T>, &RootELW<T>, &mut ControlFlow),
{
// make ControlFlow::ExitWithCode sticky by providing a dummy
// control flow reference if it is already ExitWithCode.
if let ControlFlow::ExitWithCode(code) = *control_flow {
callback(evt, target, &mut ControlFlow::ExitWithCode(code))
} else {
callback(evt, target, control_flow)
}
}
impl<T: 'static> EventLoop<T> {
pub(crate) fn new(
attributes: &PlatformSpecificEventLoopAttributes,
@ -199,6 +182,8 @@ impl<T: 'static> EventLoop<T> {
window_target: event_loop::EventLoopWindowTarget {
p: EventLoopWindowTarget {
app: android_app.clone(),
control_flow: Cell::new(ControlFlow::default()),
exit: Cell::new(false),
redraw_requester: RedrawRequester::new(
&redraw_flag,
android_app.create_waker(),
@ -213,7 +198,6 @@ impl<T: 'static> EventLoop<T> {
loop_running: false,
running: false,
pending_redraw: false,
control_flow: Default::default(),
cause: StartCause::Init,
ignore_volume_keys: attributes.ignore_volume_keys,
combining_accent: None,
@ -222,41 +206,25 @@ impl<T: 'static> EventLoop<T> {
fn single_iteration<F>(&mut self, main_event: Option<MainEvent<'_>>, callback: &mut F)
where
F: FnMut(event::Event<T>, &RootELW<T>, &mut ControlFlow),
F: FnMut(event::Event<T>, &RootELW<T>),
{
trace!("Mainloop iteration");
let cause = self.cause;
let mut control_flow = self.control_flow;
let mut pending_redraw = self.pending_redraw;
let mut resized = false;
sticky_exit_callback(
event::Event::NewEvents(cause),
self.window_target(),
&mut control_flow,
callback,
);
callback(event::Event::NewEvents(cause), self.window_target());
if let Some(event) = main_event {
trace!("Handling main event {:?}", event);
match event {
MainEvent::InitWindow { .. } => {
sticky_exit_callback(
event::Event::Resumed,
self.window_target(),
&mut control_flow,
callback,
);
callback(event::Event::Resumed, self.window_target());
}
MainEvent::TerminateWindow { .. } => {
sticky_exit_callback(
event::Event::Suspended,
self.window_target(),
&mut control_flow,
callback,
);
callback(event::Event::Suspended, self.window_target());
}
MainEvent::WindowResized { .. } => resized = true,
MainEvent::RedrawNeeded { .. } => pending_redraw = true,
@ -265,26 +233,22 @@ impl<T: 'static> EventLoop<T> {
}
MainEvent::GainedFocus => {
*HAS_FOCUS.write().unwrap() = true;
sticky_exit_callback(
callback(
event::Event::WindowEvent {
window_id: window::WindowId(WindowId),
event: event::WindowEvent::Focused(true),
},
self.window_target(),
&mut control_flow,
callback,
);
}
MainEvent::LostFocus => {
*HAS_FOCUS.write().unwrap() = false;
sticky_exit_callback(
callback(
event::Event::WindowEvent {
window_id: window::WindowId(WindowId),
event: event::WindowEvent::Focused(false),
},
self.window_target(),
&mut control_flow,
callback,
);
}
MainEvent::ConfigChanged { .. } => {
@ -304,12 +268,7 @@ impl<T: 'static> EventLoop<T> {
scale_factor,
},
};
sticky_exit_callback(
event,
self.window_target(),
&mut control_flow,
callback,
);
callback(event, self.window_target());
}
}
MainEvent::LowMemory => {
@ -363,9 +322,8 @@ impl<T: 'static> EventLoop<T> {
// Process input events
match android_app.input_events_iter() {
Ok(mut input_iter) => loop {
let read_event = input_iter.next(|event| {
self.handle_input_event(&android_app, event, &mut control_flow, callback)
});
let read_event =
input_iter.next(|event| self.handle_input_event(&android_app, event, callback));
if !read_event {
break;
@ -379,12 +337,7 @@ impl<T: 'static> EventLoop<T> {
// Empty the user event buffer
{
while let Ok(event) = self.user_events_receiver.try_recv() {
sticky_exit_callback(
crate::event::Event::UserEvent(event),
self.window_target(),
&mut control_flow,
callback,
);
callback(crate::event::Event::UserEvent(event), self.window_target());
}
}
@ -401,7 +354,7 @@ impl<T: 'static> EventLoop<T> {
window_id: window::WindowId(WindowId),
event: event::WindowEvent::Resized(size),
};
sticky_exit_callback(event, self.window_target(), &mut control_flow, callback);
callback(event, self.window_target());
}
pending_redraw |= self.redraw_flag.get_and_reset();
@ -411,19 +364,13 @@ impl<T: 'static> EventLoop<T> {
window_id: window::WindowId(WindowId),
event: event::WindowEvent::RedrawRequested,
};
sticky_exit_callback(event, self.window_target(), &mut control_flow, callback);
callback(event, self.window_target());
}
}
// This is always the last event we dispatch before poll again
sticky_exit_callback(
event::Event::AboutToWait,
self.window_target(),
&mut control_flow,
callback,
);
callback(event::Event::AboutToWait, self.window_target());
self.control_flow = control_flow;
self.pending_redraw = pending_redraw;
}
@ -431,11 +378,10 @@ impl<T: 'static> EventLoop<T> {
&mut self,
android_app: &AndroidApp,
event: &InputEvent<'_>,
control_flow: &mut ControlFlow,
callback: &mut F,
) -> InputStatus
where
F: FnMut(event::Event<T>, &RootELW<T>, &mut ControlFlow),
F: FnMut(event::Event<T>, &RootELW<T>),
{
let mut input_status = InputStatus::Handled;
match event {
@ -483,7 +429,7 @@ impl<T: 'static> EventLoop<T> {
force: None,
}),
};
sticky_exit_callback(event, self.window_target(), control_flow, callback);
callback(event, self.window_target());
}
}
}
@ -526,7 +472,7 @@ impl<T: 'static> EventLoop<T> {
is_synthetic: false,
},
};
sticky_exit_callback(event, self.window_target(), control_flow, callback);
callback(event, self.window_target());
}
}
}
@ -540,14 +486,14 @@ impl<T: 'static> EventLoop<T> {
pub fn run<F>(mut self, event_handler: F) -> Result<(), EventLoopError>
where
F: FnMut(event::Event<T>, &event_loop::EventLoopWindowTarget<T>, &mut ControlFlow),
F: FnMut(event::Event<T>, &event_loop::EventLoopWindowTarget<T>),
{
self.run_ondemand(event_handler)
}
pub fn run_ondemand<F>(&mut self, mut event_handler: F) -> Result<(), EventLoopError>
where
F: FnMut(event::Event<T>, &event_loop::EventLoopWindowTarget<T>, &mut ControlFlow),
F: FnMut(event::Event<T>, &event_loop::EventLoopWindowTarget<T>),
{
if self.loop_running {
return Err(EventLoopError::AlreadyRunning);
@ -570,7 +516,7 @@ impl<T: 'static> EventLoop<T> {
pub fn pump_events<F>(&mut self, timeout: Option<Duration>, mut callback: F) -> PumpStatus
where
F: FnMut(event::Event<T>, &RootELW<T>, &mut ControlFlow),
F: FnMut(event::Event<T>, &RootELW<T>),
{
if !self.loop_running {
self.loop_running = true;
@ -580,7 +526,7 @@ impl<T: 'static> EventLoop<T> {
// than once
self.pending_redraw = false;
self.cause = StartCause::Init;
self.control_flow = ControlFlow::Poll;
self.set_control_flow(ControlFlow::default());
// run the initial loop iteration
self.single_iteration(None, &mut callback);
@ -588,21 +534,15 @@ impl<T: 'static> EventLoop<T> {
// Consider the possibility that the `StartCause::Init` iteration could
// request to Exit
if !matches!(self.control_flow, ControlFlow::ExitWithCode(_)) {
if !self.exiting() {
self.poll_events_with_timeout(timeout, &mut callback);
}
if let ControlFlow::ExitWithCode(code) = self.control_flow {
if self.exiting() {
self.loop_running = false;
let mut dummy = self.control_flow;
sticky_exit_callback(
event::Event::LoopExiting,
self.window_target(),
&mut dummy,
&mut callback,
);
callback(event::Event::LoopExiting, self.window_target());
PumpStatus::Exit(code)
PumpStatus::Exit(0)
} else {
PumpStatus::Continue
}
@ -610,7 +550,7 @@ impl<T: 'static> EventLoop<T> {
fn poll_events_with_timeout<F>(&mut self, mut timeout: Option<Duration>, mut callback: F)
where
F: FnMut(event::Event<T>, &RootELW<T>, &mut ControlFlow),
F: FnMut(event::Event<T>, &RootELW<T>),
{
let start = Instant::now();
@ -621,14 +561,12 @@ impl<T: 'static> EventLoop<T> {
// If we already have work to do then we don't want to block on the next poll
Some(Duration::ZERO)
} else {
let control_flow_timeout = match self.control_flow {
let control_flow_timeout = match self.control_flow() {
ControlFlow::Wait => None,
ControlFlow::Poll => Some(Duration::ZERO),
ControlFlow::WaitUntil(wait_deadline) => {
Some(wait_deadline.saturating_duration_since(start))
}
// `ExitWithCode()` will be reset to `Poll` before polling
ControlFlow::ExitWithCode(_code) => unreachable!(),
};
min_timeout(control_flow_timeout, timeout)
@ -663,7 +601,7 @@ impl<T: 'static> EventLoop<T> {
}
}
self.cause = match self.control_flow {
self.cause = match self.control_flow() {
ControlFlow::Poll => StartCause::Poll,
ControlFlow::Wait => StartCause::WaitCancelled {
start,
@ -682,8 +620,6 @@ impl<T: 'static> EventLoop<T> {
}
}
}
// `ExitWithCode()` will be reset to `Poll` before polling
ControlFlow::ExitWithCode(_code) => unreachable!(),
};
self.single_iteration(main_event, &mut callback);
@ -700,6 +636,18 @@ impl<T: 'static> EventLoop<T> {
waker: self.android_app.create_waker(),
}
}
fn set_control_flow(&self, control_flow: ControlFlow) {
self.window_target.p.set_control_flow(control_flow)
}
fn control_flow(&self) -> ControlFlow {
self.window_target.p.control_flow()
}
fn exiting(&self) -> bool {
self.window_target.p.exiting()
}
}
pub struct EventLoopProxy<T: 'static> {
@ -728,6 +676,8 @@ impl<T> EventLoopProxy<T> {
pub struct EventLoopWindowTarget<T: 'static> {
app: AndroidApp,
control_flow: Cell<ControlFlow>,
exit: Cell<bool>,
redraw_requester: RedrawRequester,
_marker: std::marker::PhantomData<T>,
}
@ -749,6 +699,22 @@ impl<T: 'static> EventLoopWindowTarget<T> {
pub fn raw_display_handle(&self) -> RawDisplayHandle {
RawDisplayHandle::Android(AndroidDisplayHandle::empty())
}
pub(crate) fn set_control_flow(&self, control_flow: ControlFlow) {
self.control_flow.set(control_flow)
}
pub(crate) fn control_flow(&self) -> ControlFlow {
self.control_flow.get()
}
pub(crate) fn exit(&self) {
self.exit.set(true)
}
pub(crate) fn exiting(&self) -> bool {
self.exit.get()
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]

View file

@ -121,7 +121,7 @@ enum AppStateImpl {
Terminated,
}
struct AppState {
pub(crate) struct AppState {
// This should never be `None`, except for briefly during a state transition.
app_state: Option<AppStateImpl>,
control_flow: ControlFlow,
@ -129,7 +129,7 @@ struct AppState {
}
impl AppState {
fn get_mut(_mtm: MainThreadMarker) -> RefMut<'static, AppState> {
pub(crate) fn get_mut(_mtm: MainThreadMarker) -> RefMut<'static, AppState> {
// basically everything in UIKit requires the main thread, so it's pointless to use the
// std::sync APIs.
// must be mut because plain `static` requires `Sync`
@ -290,7 +290,6 @@ impl AppState {
};
(waiting_event_handler, event)
}
(ControlFlow::ExitWithCode(_), _) => bug!("unexpected `ControlFlow` `Exit`"),
s => bug!("`EventHandler` unexpectedly woke up {:?}", s),
};
@ -443,12 +442,6 @@ impl AppState {
});
self.waker.start()
}
(_, ControlFlow::ExitWithCode(_)) => {
// https://developer.apple.com/library/archive/qa/qa1561/_index.html
// it is not possible to quit an iOS app gracefully and programatically
warn!("`ControlFlow::Exit` ignored on iOS");
self.control_flow = old
}
}
}
@ -458,6 +451,14 @@ impl AppState {
s => bug!("`LoopExiting` happened while not processing events {:?}", s),
}
}
pub(crate) fn set_control_flow(&mut self, control_flow: ControlFlow) {
self.control_flow = control_flow;
}
pub(crate) fn control_flow(&self) -> ControlFlow {
self.control_flow
}
}
pub(crate) fn set_key_window(mtm: MainThreadMarker, window: &Id<WinitUIWindow>) {
@ -602,7 +603,6 @@ pub(crate) fn handle_nonuser_events<I: IntoIterator<Item = EventWrapper>>(
processing_redraws,
} => (event_handler, active_control_flow, processing_redraws),
};
let mut control_flow = this.control_flow;
drop(this);
for wrapper in events {
@ -616,10 +616,10 @@ pub(crate) fn handle_nonuser_events<I: IntoIterator<Item = EventWrapper>>(
event
);
}
event_handler.handle_nonuser_event(event, &mut control_flow)
event_handler.handle_nonuser_event(event)
}
EventWrapper::ScaleFactorChanged(event) => {
handle_hidpi_proxy(&mut event_handler, control_flow, event)
handle_hidpi_proxy(&mut event_handler, event)
}
}
}
@ -657,7 +657,6 @@ pub(crate) fn handle_nonuser_events<I: IntoIterator<Item = EventWrapper>>(
active_control_flow,
}
});
this.control_flow = control_flow;
break;
}
drop(this);
@ -673,10 +672,10 @@ pub(crate) fn handle_nonuser_events<I: IntoIterator<Item = EventWrapper>>(
event
);
}
event_handler.handle_nonuser_event(event, &mut control_flow)
event_handler.handle_nonuser_event(event)
}
EventWrapper::ScaleFactorChanged(event) => {
handle_hidpi_proxy(&mut event_handler, control_flow, event)
handle_hidpi_proxy(&mut event_handler, event)
}
}
}
@ -685,7 +684,6 @@ pub(crate) fn handle_nonuser_events<I: IntoIterator<Item = EventWrapper>>(
fn handle_user_events(mtm: MainThreadMarker) {
let mut this = AppState::get_mut(mtm);
let mut control_flow = this.control_flow;
let (mut event_handler, active_control_flow, processing_redraws) =
match this.try_user_callback_transition() {
UserCallbackTransitionResult::ReentrancyPrevented { .. } => {
@ -702,7 +700,7 @@ fn handle_user_events(mtm: MainThreadMarker) {
}
drop(this);
event_handler.handle_user_events(&mut control_flow);
event_handler.handle_user_events();
loop {
let mut this = AppState::get_mut(mtm);
@ -726,22 +724,19 @@ fn handle_user_events(mtm: MainThreadMarker) {
queued_gpu_redraws,
active_control_flow,
});
this.control_flow = control_flow;
break;
}
drop(this);
for wrapper in queued_events {
match wrapper {
EventWrapper::StaticEvent(event) => {
event_handler.handle_nonuser_event(event, &mut control_flow)
}
EventWrapper::StaticEvent(event) => event_handler.handle_nonuser_event(event),
EventWrapper::ScaleFactorChanged(event) => {
handle_hidpi_proxy(&mut event_handler, control_flow, event)
handle_hidpi_proxy(&mut event_handler, event)
}
}
}
event_handler.handle_user_events(&mut control_flow);
event_handler.handle_user_events();
}
}
@ -782,17 +777,12 @@ pub fn handle_events_cleared(mtm: MainThreadMarker) {
pub fn terminated(mtm: MainThreadMarker) {
let mut this = AppState::get_mut(mtm);
let mut event_handler = this.terminated_transition();
let mut control_flow = this.control_flow;
drop(this);
event_handler.handle_nonuser_event(Event::LoopExiting, &mut control_flow)
event_handler.handle_nonuser_event(Event::LoopExiting)
}
fn handle_hidpi_proxy(
event_handler: &mut Box<dyn EventHandler>,
mut control_flow: ControlFlow,
event: ScaleFactorChanged,
) {
fn handle_hidpi_proxy(event_handler: &mut Box<dyn EventHandler>, event: ScaleFactorChanged) {
let ScaleFactorChanged {
suggested_size,
scale_factor,
@ -806,7 +796,7 @@ fn handle_hidpi_proxy(
inner_size_writer: InnerSizeWriter::new(Arc::downgrade(&new_inner_size)),
},
};
event_handler.handle_nonuser_event(event, &mut control_flow);
event_handler.handle_nonuser_event(event);
let (view, screen_frame) = get_view_and_screen_frame(&window);
let physical_size = *new_inner_size.lock().unwrap();
drop(new_inner_size);

View file

@ -28,8 +28,11 @@ use crate::{
platform::ios::Idiom,
};
use super::uikit::{UIApplication, UIApplicationMain, UIDevice, UIScreen};
use super::{app_state, monitor, view, MonitorHandle};
use super::{
app_state::AppState,
uikit::{UIApplication, UIApplicationMain, UIDevice, UIScreen},
};
#[derive(Debug)]
pub struct EventLoopWindowTarget<T: 'static> {
@ -52,6 +55,24 @@ impl<T: 'static> EventLoopWindowTarget<T> {
pub fn raw_display_handle(&self) -> RawDisplayHandle {
RawDisplayHandle::UiKit(UiKitDisplayHandle::empty())
}
pub(crate) fn set_control_flow(&self, control_flow: ControlFlow) {
AppState::get_mut(self.mtm).set_control_flow(control_flow)
}
pub(crate) fn control_flow(&self) -> ControlFlow {
AppState::get_mut(self.mtm).control_flow()
}
pub(crate) fn exit(&self) {
// https://developer.apple.com/library/archive/qa/qa1561/_index.html
// it is not possible to quit an iOS app gracefully and programatically
warn!("`ControlFlow::Exit` ignored on iOS");
}
pub(crate) fn exiting(&self) -> bool {
false
}
}
pub struct EventLoop<T: 'static> {
@ -102,7 +123,7 @@ impl<T: 'static> EventLoop<T> {
pub fn run<F>(self, event_handler: F) -> !
where
F: FnMut(Event<T>, &RootEventLoopWindowTarget<T>, &mut ControlFlow),
F: FnMut(Event<T>, &RootEventLoopWindowTarget<T>),
{
unsafe {
let application = UIApplication::shared(self.mtm);
@ -114,7 +135,7 @@ impl<T: 'static> EventLoop<T> {
);
let event_handler = std::mem::transmute::<
Box<dyn FnMut(Event<T>, &RootEventLoopWindowTarget<T>, &mut ControlFlow)>,
Box<dyn FnMut(Event<T>, &RootEventLoopWindowTarget<T>)>,
Box<EventHandlerCallback<T>>,
>(Box::new(event_handler));
@ -314,12 +335,11 @@ fn setup_control_flow_observers() {
#[derive(Debug)]
pub enum Never {}
type EventHandlerCallback<T> =
dyn FnMut(Event<T>, &RootEventLoopWindowTarget<T>, &mut ControlFlow) + 'static;
type EventHandlerCallback<T> = dyn FnMut(Event<T>, &RootEventLoopWindowTarget<T>) + 'static;
pub trait EventHandler: Debug {
fn handle_nonuser_event(&mut self, event: Event<Never>, control_flow: &mut ControlFlow);
fn handle_user_events(&mut self, control_flow: &mut ControlFlow);
fn handle_nonuser_event(&mut self, event: Event<Never>);
fn handle_user_events(&mut self);
}
struct EventLoopHandler<T: 'static> {
@ -337,17 +357,13 @@ impl<T: 'static> Debug for EventLoopHandler<T> {
}
impl<T: 'static> EventHandler for EventLoopHandler<T> {
fn handle_nonuser_event(&mut self, event: Event<Never>, control_flow: &mut ControlFlow) {
(self.f)(
event.map_nonuser_event().unwrap(),
&self.event_loop,
control_flow,
);
fn handle_nonuser_event(&mut self, event: Event<Never>) {
(self.f)(event.map_nonuser_event().unwrap(), &self.event_loop);
}
fn handle_user_events(&mut self, control_flow: &mut ControlFlow) {
fn handle_user_events(&mut self) {
for event in self.receiver.try_iter() {
(self.f)(Event::UserEvent(event), &self.event_loop, control_flow);
(self.f)(Event::UserEvent(event), &self.event_loop);
}
}
}

View file

@ -19,7 +19,7 @@ use crate::platform::x11::XlibErrorHook;
use crate::{
dpi::{PhysicalPosition, PhysicalSize, Position, Size},
error::{EventLoopError, ExternalError, NotSupportedError, OsError as RootOsError},
event::{Event, KeyEvent},
event::KeyEvent,
event_loop::{
AsyncRequestSerial, ControlFlow, DeviceEvents, EventLoopClosed,
EventLoopWindowTarget as RootELW,
@ -767,21 +767,21 @@ impl<T: 'static> EventLoop<T> {
pub fn run<F>(mut self, callback: F) -> Result<(), EventLoopError>
where
F: FnMut(crate::event::Event<T>, &RootELW<T>, &mut ControlFlow),
F: FnMut(crate::event::Event<T>, &RootELW<T>),
{
self.run_ondemand(callback)
}
pub fn run_ondemand<F>(&mut self, callback: F) -> Result<(), EventLoopError>
where
F: FnMut(crate::event::Event<T>, &RootELW<T>, &mut ControlFlow),
F: FnMut(crate::event::Event<T>, &RootELW<T>),
{
x11_or_wayland!(match self; EventLoop(evlp) => evlp.run_ondemand(callback))
}
pub fn pump_events<F>(&mut self, timeout: Option<Duration>, callback: F) -> PumpStatus
where
F: FnMut(crate::event::Event<T>, &RootELW<T>, &mut ControlFlow),
F: FnMut(crate::event::Event<T>, &RootELW<T>),
{
x11_or_wayland!(match self; EventLoop(evlp) => evlp.pump_events(timeout, callback))
}
@ -845,22 +845,29 @@ impl<T> EventLoopWindowTarget<T> {
pub fn raw_display_handle(&self) -> raw_window_handle::RawDisplayHandle {
x11_or_wayland!(match self; Self(evlp) => evlp.raw_display_handle())
}
}
fn sticky_exit_callback<T, F>(
evt: Event<T>,
target: &RootELW<T>,
control_flow: &mut ControlFlow,
callback: &mut F,
) where
F: FnMut(Event<T>, &RootELW<T>, &mut ControlFlow),
{
// make ControlFlow::ExitWithCode sticky by providing a dummy
// control flow reference if it is already ExitWithCode.
if let ControlFlow::ExitWithCode(code) = *control_flow {
callback(evt, target, &mut ControlFlow::ExitWithCode(code))
} else {
callback(evt, target, control_flow)
pub(crate) fn set_control_flow(&self, control_flow: ControlFlow) {
x11_or_wayland!(match self; Self(evlp) => evlp.set_control_flow(control_flow))
}
pub(crate) fn control_flow(&self) -> ControlFlow {
x11_or_wayland!(match self; Self(evlp) => evlp.control_flow())
}
pub(crate) fn exit(&self) {
x11_or_wayland!(match self; Self(evlp) => evlp.exit())
}
pub(crate) fn exiting(&self) -> bool {
x11_or_wayland!(match self; Self(evlp) => evlp.exiting())
}
fn set_exit_code(&self, code: i32) {
x11_or_wayland!(match self; Self(evlp) => evlp.set_exit_code(code))
}
fn exit_code(&self) -> Option<i32> {
x11_or_wayland!(match self; Self(evlp) => evlp.exit_code())
}
}

View file

@ -1,6 +1,6 @@
//! The event-loop routines.
use std::cell::RefCell;
use std::cell::{Cell, RefCell};
use std::io::Result as IOResult;
use std::marker::PhantomData;
use std::mem;
@ -24,7 +24,6 @@ use crate::event_loop::{
};
use crate::platform::pump_events::PumpStatus;
use crate::platform_impl::platform::min_timeout;
use crate::platform_impl::platform::sticky_exit_callback;
use crate::platform_impl::{EventLoopWindowTarget as PlatformEventLoopWindowTarget, OsError};
mod proxy;
@ -44,9 +43,6 @@ pub struct EventLoop<T: 'static> {
/// Has `run` or `run_ondemand` been called or a call to `pump_events` that starts the loop
loop_running: bool,
/// The application's latest control_flow state
control_flow: ControlFlow,
buffer_sink: EventSink,
compositor_updates: Vec<WindowCompositorUpdate>,
window_ids: Vec<WindowId>,
@ -168,13 +164,14 @@ impl<T: 'static> EventLoop<T> {
wayland_dispatcher: wayland_dispatcher.clone(),
event_loop_awakener,
queue_handle,
control_flow: Cell::new(ControlFlow::default()),
exit: Cell::new(None),
state: RefCell::new(winit_state),
_marker: PhantomData,
};
let event_loop = Self {
loop_running: false,
control_flow: ControlFlow::default(),
compositor_updates: Vec::new(),
buffer_sink: EventSink::default(),
window_ids: Vec::new(),
@ -194,7 +191,7 @@ impl<T: 'static> EventLoop<T> {
pub fn run_ondemand<F>(&mut self, mut event_handler: F) -> Result<(), EventLoopError>
where
F: FnMut(Event<T>, &RootEventLoopWindowTarget<T>, &mut ControlFlow),
F: FnMut(Event<T>, &RootEventLoopWindowTarget<T>),
{
if self.loop_running {
return Err(EventLoopError::AlreadyRunning);
@ -225,7 +222,7 @@ impl<T: 'static> EventLoop<T> {
pub fn pump_events<F>(&mut self, timeout: Option<Duration>, mut callback: F) -> PumpStatus
where
F: FnMut(Event<T>, &RootEventLoopWindowTarget<T>, &mut ControlFlow),
F: FnMut(Event<T>, &RootEventLoopWindowTarget<T>),
{
if !self.loop_running {
self.loop_running = true;
@ -233,7 +230,7 @@ impl<T: 'static> EventLoop<T> {
// Reset the internal state for the loop as we start running to
// ensure consistent behaviour in case the loop runs and exits more
// than once.
self.control_flow = ControlFlow::Poll;
self.set_control_flow(ControlFlow::Poll);
// Run the initial loop iteration.
self.single_iteration(&mut callback, StartCause::Init);
@ -241,19 +238,13 @@ impl<T: 'static> EventLoop<T> {
// Consider the possibility that the `StartCause::Init` iteration could
// request to Exit.
if !matches!(self.control_flow, ControlFlow::ExitWithCode(_)) {
if !self.exiting() {
self.poll_events_with_timeout(timeout, &mut callback);
}
if let ControlFlow::ExitWithCode(code) = self.control_flow {
if let Some(code) = self.exit_code() {
self.loop_running = false;
let mut dummy = self.control_flow;
sticky_exit_callback(
Event::LoopExiting,
self.window_target(),
&mut dummy,
&mut callback,
);
callback(Event::LoopExiting, self.window_target());
PumpStatus::Exit(code)
} else {
@ -263,7 +254,7 @@ impl<T: 'static> EventLoop<T> {
pub fn poll_events_with_timeout<F>(&mut self, mut timeout: Option<Duration>, mut callback: F)
where
F: FnMut(Event<T>, &RootEventLoopWindowTarget<T>, &mut ControlFlow),
F: FnMut(Event<T>, &RootEventLoopWindowTarget<T>),
{
let cause = loop {
let start = Instant::now();
@ -299,7 +290,7 @@ impl<T: 'static> EventLoop<T> {
}
Err(error) => {
error!("Error dispatching wayland queue: {}", error);
self.control_flow = ControlFlow::ExitWithCode(1);
self.set_exit_code(1);
return;
}
}
@ -308,17 +299,12 @@ impl<T: 'static> EventLoop<T> {
timeout = if instant_wakeup {
Some(Duration::ZERO)
} else {
let control_flow_timeout = match self.control_flow {
let control_flow_timeout = match self.control_flow() {
ControlFlow::Wait => None,
ControlFlow::Poll => Some(Duration::ZERO),
ControlFlow::WaitUntil(wait_deadline) => {
Some(wait_deadline.saturating_duration_since(start))
}
// This function shouldn't have to handle any requests to exit
// the application (there should be no need to poll for events
// if the application has requested to exit) so we consider
// it a bug in the backend if we ever see `ExitWithCode` here.
ControlFlow::ExitWithCode(_code) => unreachable!(),
};
min_timeout(control_flow_timeout, timeout)
};
@ -336,13 +322,13 @@ impl<T: 'static> EventLoop<T> {
// with an API to do that via some event.
// Still, we set the exit code to the error's OS error code, or to 1 if not possible.
let exit_code = error.raw_os_error().unwrap_or(1);
self.control_flow = ControlFlow::ExitWithCode(exit_code);
self.set_exit_code(exit_code);
return;
}
// NB: `StartCause::Init` is handled as a special case and doesn't need
// to be considered here
let cause = match self.control_flow {
let cause = match self.control_flow() {
ControlFlow::Poll => StartCause::Poll,
ControlFlow::Wait => StartCause::WaitCancelled {
start,
@ -361,11 +347,6 @@ impl<T: 'static> EventLoop<T> {
}
}
}
// This function shouldn't have to handle any requests to exit
// the application (there should be no need to poll for events
// if the application has requested to exit) so we consider
// it a bug in the backend if we ever see `ExitWithCode` here.
ControlFlow::ExitWithCode(_code) => unreachable!(),
};
// Reduce spurious wake-ups.
@ -380,14 +361,12 @@ impl<T: 'static> EventLoop<T> {
self.single_iteration(&mut callback, cause);
}
fn single_iteration<F>(&mut self, mut callback: &mut F, cause: StartCause)
fn single_iteration<F>(&mut self, callback: &mut F, cause: StartCause)
where
F: FnMut(Event<T>, &RootEventLoopWindowTarget<T>, &mut ControlFlow),
F: FnMut(Event<T>, &RootEventLoopWindowTarget<T>),
{
// NOTE currently just indented to simplify the diff
let mut control_flow = self.control_flow;
// We retain these grow-only scratch buffers as part of the EventLoop
// for the sake of avoiding lots of reallocs. We take them here to avoid
// trying to mutably borrow `self` more than once and we swap them back
@ -396,33 +375,18 @@ impl<T: 'static> EventLoop<T> {
let mut buffer_sink = std::mem::take(&mut self.buffer_sink);
let mut window_ids = std::mem::take(&mut self.window_ids);
sticky_exit_callback(
Event::NewEvents(cause),
&self.window_target,
&mut control_flow,
callback,
);
callback(Event::NewEvents(cause), &self.window_target);
// NB: For consistency all platforms must emit a 'resumed' event even though Wayland
// applications don't themselves have a formal suspend/resume lifecycle.
if cause == StartCause::Init {
sticky_exit_callback(
Event::Resumed,
&self.window_target,
&mut control_flow,
callback,
);
callback(Event::Resumed, &self.window_target);
}
// Handle pending user events. We don't need back buffer, since we can't dispatch
// user events indirectly via callback to the user.
for user_event in self.pending_user_events.borrow_mut().drain(..) {
sticky_exit_callback(
Event::UserEvent(user_event),
&self.window_target,
&mut control_flow,
&mut callback,
);
callback(Event::UserEvent(user_event), &self.window_target);
}
// Drain the pending compositor updates.
@ -445,7 +409,7 @@ impl<T: 'static> EventLoop<T> {
let old_physical_size = physical_size;
let new_inner_size = Arc::new(Mutex::new(physical_size));
sticky_exit_callback(
callback(
Event::WindowEvent {
window_id: crate::window::WindowId(window_id),
event: WindowEvent::ScaleFactorChanged {
@ -456,8 +420,6 @@ impl<T: 'static> EventLoop<T> {
},
},
&self.window_target,
&mut control_flow,
&mut callback,
);
let physical_size = *new_inner_size.lock().unwrap();
@ -499,26 +461,22 @@ impl<T: 'static> EventLoop<T> {
physical_size
});
sticky_exit_callback(
callback(
Event::WindowEvent {
window_id: crate::window::WindowId(window_id),
event: WindowEvent::Resized(physical_size),
},
&self.window_target,
&mut control_flow,
&mut callback,
);
}
if compositor_update.close_window {
sticky_exit_callback(
callback(
Event::WindowEvent {
window_id: crate::window::WindowId(window_id),
event: WindowEvent::CloseRequested,
},
&self.window_target,
&mut control_flow,
&mut callback,
);
}
}
@ -529,7 +487,7 @@ impl<T: 'static> EventLoop<T> {
});
for event in buffer_sink.drain() {
let event = event.map_nonuser_event().unwrap();
sticky_exit_callback(event, &self.window_target, &mut control_flow, &mut callback);
callback(event, &self.window_target);
}
// Handle non-synthetic events.
@ -538,7 +496,7 @@ impl<T: 'static> EventLoop<T> {
});
for event in buffer_sink.drain() {
let event = event.map_nonuser_event().unwrap();
sticky_exit_callback(event, &self.window_target, &mut control_flow, &mut callback);
callback(event, &self.window_target);
}
// Collect the window ids
@ -581,14 +539,12 @@ impl<T: 'static> EventLoop<T> {
});
if request_redraw {
sticky_exit_callback(
callback(
Event::WindowEvent {
window_id: crate::window::WindowId(window_id),
event: WindowEvent::RedrawRequested,
},
&self.window_target,
&mut control_flow,
&mut callback,
);
}
}
@ -599,14 +555,8 @@ impl<T: 'static> EventLoop<T> {
});
// This is always the last event we dispatch before poll again
sticky_exit_callback(
Event::AboutToWait,
&self.window_target,
&mut control_flow,
&mut callback,
);
callback(Event::AboutToWait, &self.window_target);
self.control_flow = control_flow;
std::mem::swap(&mut self.compositor_updates, &mut compositor_updates);
std::mem::swap(&mut self.buffer_sink, &mut buffer_sink);
std::mem::swap(&mut self.window_ids, &mut window_ids);
@ -660,6 +610,26 @@ impl<T: 'static> EventLoop<T> {
))))
})
}
fn set_control_flow(&self, control_flow: ControlFlow) {
self.window_target.p.set_control_flow(control_flow)
}
fn control_flow(&self) -> ControlFlow {
self.window_target.p.control_flow()
}
fn exiting(&self) -> bool {
self.window_target.p.exiting()
}
fn set_exit_code(&self, code: i32) {
self.window_target.p.set_exit_code(code)
}
fn exit_code(&self) -> Option<i32> {
self.window_target.p.exit_code()
}
}
pub struct EventLoopWindowTarget<T> {
@ -669,6 +639,12 @@ pub struct EventLoopWindowTarget<T> {
/// The main queue used by the event loop.
pub queue_handle: QueueHandle<WinitState>,
/// The application's latest control_flow state
pub(crate) control_flow: Cell<ControlFlow>,
/// The application's exit state.
pub(crate) exit: Cell<Option<i32>>,
// TODO remove that RefCell once we can pass `&mut` in `Window::new`.
/// Winit state.
pub state: RefCell<WinitState>,

View file

@ -4,6 +4,7 @@ use sctk::reexports::client::Proxy;
use sctk::output::OutputData;
use crate::dpi::{PhysicalPosition, PhysicalSize};
use crate::event_loop::ControlFlow;
use crate::platform_impl::platform::VideoMode as PlatformVideoMode;
use super::event_loop::EventLoopWindowTarget;
@ -23,6 +24,30 @@ impl<T> EventLoopWindowTarget<T> {
// There's no primary monitor on Wayland.
None
}
pub(crate) fn set_control_flow(&self, control_flow: ControlFlow) {
self.control_flow.set(control_flow)
}
pub(crate) fn control_flow(&self) -> ControlFlow {
self.control_flow.get()
}
pub(crate) fn exit(&self) {
self.exit.set(Some(0))
}
pub(crate) fn exiting(&self) -> bool {
self.exit.get().is_some()
}
pub(crate) fn set_exit_code(&self, code: i32) {
self.exit.set(Some(code))
}
pub(crate) fn exit_code(&self) -> Option<i32> {
self.exit.get()
}
}
#[derive(Clone, Debug)]

View file

@ -66,14 +66,14 @@ use self::{
event_processor::EventProcessor,
ime::{Ime, ImeCreationError, ImeReceiver, ImeRequest, ImeSender},
};
use super::{common::xkb_state::KbdState, OsError};
use super::{common::xkb_state::KbdState, ControlFlow, OsError};
use crate::{
error::{EventLoopError, OsError as RootOsError},
event::{Event, StartCause, WindowEvent},
event_loop::{ControlFlow, DeviceEvents, EventLoopClosed, EventLoopWindowTarget as RootELW},
event_loop::{DeviceEvents, EventLoopClosed, EventLoopWindowTarget as RootELW},
platform::pump_events::PumpStatus,
platform_impl::{
platform::{min_timeout, sticky_exit_callback, WindowId},
platform::{min_timeout, WindowId},
PlatformSpecificWindowBuilderAttributes,
},
window::WindowAttributes,
@ -148,6 +148,8 @@ pub struct EventLoopWindowTarget<T> {
wm_delete_window: xproto::Atom,
net_wm_ping: xproto::Atom,
ime_sender: ImeSender,
control_flow: Cell<ControlFlow>,
exit: Cell<Option<i32>>,
root: xproto::Window,
ime: RefCell<Ime>,
windows: RefCell<HashMap<WindowId, Weak<UnownedWindow>>>,
@ -159,7 +161,6 @@ pub struct EventLoopWindowTarget<T> {
pub struct EventLoop<T: 'static> {
loop_running: bool,
control_flow: ControlFlow,
event_loop: Loop<'static, EventLoopState>,
waker: calloop::ping::Ping,
event_processor: EventProcessor<T>,
@ -303,6 +304,8 @@ impl<T: 'static> EventLoop<T> {
let window_target = EventLoopWindowTarget {
ime,
root,
control_flow: Cell::new(ControlFlow::default()),
exit: Cell::new(None),
windows: Default::default(),
_marker: ::std::marker::PhantomData,
ime_sender,
@ -368,7 +371,6 @@ impl<T: 'static> EventLoop<T> {
EventLoop {
loop_running: false,
control_flow: ControlFlow::default(),
event_loop,
waker,
event_processor,
@ -398,7 +400,7 @@ impl<T: 'static> EventLoop<T> {
pub fn run_ondemand<F>(&mut self, mut event_handler: F) -> Result<(), EventLoopError>
where
F: FnMut(Event<T>, &RootELW<T>, &mut ControlFlow),
F: FnMut(Event<T>, &RootELW<T>),
{
if self.loop_running {
return Err(EventLoopError::AlreadyRunning);
@ -432,7 +434,7 @@ impl<T: 'static> EventLoop<T> {
pub fn pump_events<F>(&mut self, timeout: Option<Duration>, mut callback: F) -> PumpStatus
where
F: FnMut(Event<T>, &RootELW<T>, &mut ControlFlow),
F: FnMut(Event<T>, &RootELW<T>),
{
if !self.loop_running {
self.loop_running = true;
@ -440,7 +442,7 @@ impl<T: 'static> EventLoop<T> {
// Reset the internal state for the loop as we start running to
// ensure consistent behaviour in case the loop runs and exits more
// than once.
self.control_flow = ControlFlow::Poll;
self.set_control_flow(ControlFlow::Poll);
// run the initial loop iteration
self.single_iteration(&mut callback, StartCause::Init);
@ -448,19 +450,13 @@ impl<T: 'static> EventLoop<T> {
// Consider the possibility that the `StartCause::Init` iteration could
// request to Exit.
if !matches!(self.control_flow, ControlFlow::ExitWithCode(_)) {
if !self.exiting() {
self.poll_events_with_timeout(timeout, &mut callback);
}
if let ControlFlow::ExitWithCode(code) = self.control_flow {
if let Some(code) = self.exit_code() {
self.loop_running = false;
let mut dummy = self.control_flow;
sticky_exit_callback(
Event::LoopExiting,
self.window_target(),
&mut dummy,
&mut callback,
);
callback(Event::LoopExiting, self.window_target());
PumpStatus::Exit(code)
} else {
@ -476,7 +472,7 @@ impl<T: 'static> EventLoop<T> {
pub fn poll_events_with_timeout<F>(&mut self, mut timeout: Option<Duration>, mut callback: F)
where
F: FnMut(Event<T>, &RootELW<T>, &mut ControlFlow),
F: FnMut(Event<T>, &RootELW<T>),
{
let start = Instant::now();
@ -486,17 +482,12 @@ impl<T: 'static> EventLoop<T> {
// If we already have work to do then we don't want to block on the next poll.
Some(Duration::ZERO)
} else {
let control_flow_timeout = match self.control_flow {
let control_flow_timeout = match self.control_flow() {
ControlFlow::Wait => None,
ControlFlow::Poll => Some(Duration::ZERO),
ControlFlow::WaitUntil(wait_deadline) => {
Some(wait_deadline.saturating_duration_since(start))
}
// This function shouldn't have to handle any requests to exit
// the application (there should be no need to poll for events
// if the application has requested to exit) so we consider
// it a bug in the backend if we ever see `ExitWithCode` here.
ControlFlow::ExitWithCode(_code) => unreachable!(),
};
min_timeout(control_flow_timeout, timeout)
@ -510,7 +501,7 @@ impl<T: 'static> EventLoop<T> {
{
log::error!("Failed to poll for events: {error:?}");
let exit_code = error.raw_os_error().unwrap_or(1);
self.control_flow = ControlFlow::ExitWithCode(exit_code);
self.set_exit_code(exit_code);
return;
}
@ -528,7 +519,7 @@ impl<T: 'static> EventLoop<T> {
// NB: `StartCause::Init` is handled as a special case and doesn't need
// to be considered here
let cause = match self.control_flow {
let cause = match self.control_flow() {
ControlFlow::Poll => StartCause::Poll,
ControlFlow::Wait => StartCause::WaitCancelled {
start,
@ -547,11 +538,6 @@ impl<T: 'static> EventLoop<T> {
}
}
}
// This function shouldn't have to handle any requests to exit
// the application (there should be no need to poll for events
// if the application has requested to exit) so we consider
// it a bug in the backend if we ever see `ExitWithCode` here.
ControlFlow::ExitWithCode(_code) => unreachable!(),
};
self.single_iteration(&mut callback, cause);
@ -559,30 +545,18 @@ impl<T: 'static> EventLoop<T> {
fn single_iteration<F>(&mut self, callback: &mut F, cause: StartCause)
where
F: FnMut(Event<T>, &RootELW<T>, &mut ControlFlow),
F: FnMut(Event<T>, &RootELW<T>),
{
let mut control_flow = self.control_flow;
sticky_exit_callback(
crate::event::Event::NewEvents(cause),
&self.target,
&mut control_flow,
callback,
);
callback(crate::event::Event::NewEvents(cause), &self.target);
// NB: For consistency all platforms must emit a 'resumed' event even though X11
// applications don't themselves have a formal suspend/resume lifecycle.
if cause == StartCause::Init {
sticky_exit_callback(
crate::event::Event::Resumed,
&self.target,
&mut control_flow,
callback,
);
callback(crate::event::Event::Resumed, &self.target);
}
// Process all pending events
self.drain_events(callback, &mut control_flow);
self.drain_events(callback);
// Empty activation tokens.
while let Ok((window_id, serial)) = self.activation_receiver.try_recv() {
@ -593,7 +567,7 @@ impl<T: 'static> EventLoop<T> {
});
match token {
Some(Ok(token)) => sticky_exit_callback(
Some(Ok(token)) => callback(
crate::event::Event::WindowEvent {
window_id: crate::window::WindowId(window_id),
event: crate::event::WindowEvent::ActivationTokenDone {
@ -602,8 +576,6 @@ impl<T: 'static> EventLoop<T> {
},
},
&self.target,
&mut control_flow,
callback,
),
Some(Err(e)) => {
log::error!("Failed to get activation token: {}", e);
@ -615,12 +587,7 @@ impl<T: 'static> EventLoop<T> {
// Empty the user event buffer
{
while let Ok(event) = self.user_receiver.try_recv() {
sticky_exit_callback(
crate::event::Event::UserEvent(event),
&self.target,
&mut control_flow,
callback,
);
callback(crate::event::Event::UserEvent(event), &self.target);
}
}
@ -634,34 +601,25 @@ impl<T: 'static> EventLoop<T> {
for window_id in windows {
let window_id = crate::window::WindowId(window_id);
sticky_exit_callback(
callback(
Event::WindowEvent {
window_id,
event: WindowEvent::RedrawRequested,
},
&self.target,
&mut control_flow,
callback,
);
}
}
// This is always the last event we dispatch before poll again
{
sticky_exit_callback(
crate::event::Event::AboutToWait,
&self.target,
&mut control_flow,
callback,
);
callback(crate::event::Event::AboutToWait, &self.target);
}
self.control_flow = control_flow;
}
fn drain_events<F>(&mut self, callback: &mut F, control_flow: &mut ControlFlow)
fn drain_events<F>(&mut self, callback: &mut F)
where
F: FnMut(Event<T>, &RootELW<T>, &mut ControlFlow),
F: FnMut(Event<T>, &RootELW<T>),
{
let target = &self.target;
let mut xev = MaybeUninit::uninit();
@ -670,25 +628,38 @@ impl<T: 'static> EventLoop<T> {
while unsafe { self.event_processor.poll_one_event(xev.as_mut_ptr()) } {
let mut xev = unsafe { xev.assume_init() };
self.event_processor.process_event(&mut xev, |event| {
sticky_exit_callback(
event,
target,
control_flow,
&mut |event, window_target, control_flow| {
if let Event::WindowEvent {
window_id: crate::window::WindowId(wid),
event: WindowEvent::RedrawRequested,
} = event
{
wt.redraw_sender.send(wid).unwrap();
} else {
callback(event, window_target, control_flow);
}
},
);
if let Event::WindowEvent {
window_id: crate::window::WindowId(wid),
event: WindowEvent::RedrawRequested,
} = event
{
wt.redraw_sender.send(wid).unwrap();
} else {
callback(event, target);
}
});
}
}
fn set_control_flow(&self, control_flow: ControlFlow) {
self.target.p.set_control_flow(control_flow)
}
fn control_flow(&self) -> ControlFlow {
self.target.p.control_flow()
}
fn exiting(&self) -> bool {
self.target.p.exiting()
}
fn set_exit_code(&self, code: i32) {
self.target.p.set_exit_code(code)
}
fn exit_code(&self) -> Option<i32> {
self.target.p.exit_code()
}
}
pub(crate) fn get_xtarget<T>(target: &RootELW<T>) -> &EventLoopWindowTarget<T> {
@ -743,6 +714,30 @@ impl<T> EventLoopWindowTarget<T> {
display_handle.screen = self.xconn.default_screen_index() as c_int;
RawDisplayHandle::Xlib(display_handle)
}
pub(crate) fn set_control_flow(&self, control_flow: ControlFlow) {
self.control_flow.set(control_flow)
}
pub(crate) fn control_flow(&self) -> ControlFlow {
self.control_flow.get()
}
pub(crate) fn exit(&self) {
self.exit.set(Some(0))
}
pub(crate) fn exiting(&self) -> bool {
self.exit.get().is_some()
}
pub(crate) fn set_exit_code(&self, code: i32) {
self.exit.set(Some(code))
}
pub(crate) fn exit_code(&self) -> Option<i32> {
self.exit.get()
}
}
impl<T: 'static> EventLoopProxy<T> {

View file

@ -56,7 +56,7 @@ declare_class!(
fn will_terminate(&self, _sender: Option<&AnyObject>) {
trace_scope!("applicationWillTerminate:");
// TODO: Notify every window that it will be destroyed, like done in iOS?
AppState::exit();
AppState::internal_exit();
}
}
);

View file

@ -40,11 +40,11 @@ impl<Never> Event<Never> {
pub trait EventHandler: Debug {
// Not sure probably it should accept Event<'static, Never>
fn handle_nonuser_event(&mut self, event: Event<Never>, control_flow: &mut ControlFlow);
fn handle_user_events(&mut self, control_flow: &mut ControlFlow);
fn handle_nonuser_event(&mut self, event: Event<Never>);
fn handle_user_events(&mut self);
}
pub(crate) type Callback<T> = RefCell<dyn FnMut(Event<T>, &RootWindowTarget<T>, &mut ControlFlow)>;
pub(crate) type Callback<T> = RefCell<dyn FnMut(Event<T>, &RootWindowTarget<T>)>;
struct EventLoopHandler<T: 'static> {
callback: Weak<Callback<T>>,
@ -55,10 +55,7 @@ struct EventLoopHandler<T: 'static> {
impl<T> EventLoopHandler<T> {
fn with_callback<F>(&mut self, f: F)
where
F: FnOnce(
&mut EventLoopHandler<T>,
RefMut<'_, dyn FnMut(Event<T>, &RootWindowTarget<T>, &mut ControlFlow)>,
),
F: FnOnce(&mut EventLoopHandler<T>, RefMut<'_, dyn FnMut(Event<T>, &RootWindowTarget<T>)>),
{
// The `NSApp` and our `HANDLER` are global state and so it's possible that
// we could get a delegate callback after the application has exit an
@ -85,28 +82,16 @@ impl<T> Debug for EventLoopHandler<T> {
}
impl<T> EventHandler for EventLoopHandler<T> {
fn handle_nonuser_event(&mut self, event: Event<Never>, control_flow: &mut ControlFlow) {
fn handle_nonuser_event(&mut self, event: Event<Never>) {
self.with_callback(|this, mut callback| {
if let ControlFlow::ExitWithCode(code) = *control_flow {
// XXX: why isn't event dispatching simply skipped after control_flow = ExitWithCode?
let dummy = &mut ControlFlow::ExitWithCode(code);
(callback)(event.userify(), &this.window_target, dummy);
} else {
(callback)(event.userify(), &this.window_target, control_flow);
}
(callback)(event.userify(), &this.window_target);
});
}
fn handle_user_events(&mut self, control_flow: &mut ControlFlow) {
fn handle_user_events(&mut self) {
self.with_callback(|this, mut callback| {
for event in this.receiver.try_iter() {
if let ControlFlow::ExitWithCode(code) = *control_flow {
// XXX: why isn't event dispatching simply skipped after control_flow = ExitWithCode?
let dummy = &mut ControlFlow::ExitWithCode(code);
(callback)(Event::UserEvent(event), &this.window_target, dummy);
} else {
(callback)(Event::UserEvent(event), &this.window_target, control_flow);
}
(callback)(Event::UserEvent(event), &this.window_target);
}
});
}
@ -132,6 +117,7 @@ struct Handler {
running: AtomicBool,
in_callback: AtomicBool,
control_flow: Mutex<ControlFlow>,
exit: AtomicBool,
start_time: Mutex<Option<Instant>>,
callback: Mutex<Option<Box<dyn EventHandler>>>,
pending_events: Mutex<VecDeque<EventWrapper>>,
@ -189,13 +175,6 @@ impl Handler {
self.running.store(true, Ordering::Relaxed);
}
fn should_exit(&self) -> bool {
matches!(
*self.control_flow.lock().unwrap(),
ControlFlow::ExitWithCode(_)
)
}
/// Clears the `running` state and resets the `control_flow` state when an `EventLoop` exits
///
/// Since an `EventLoop` may be run more than once we need make sure to reset the
@ -206,7 +185,7 @@ impl Handler {
///
/// # Caveat
/// This is only intended to be called from the main thread
fn exit(&self) {
fn internal_exit(&self) {
// Relaxed ordering because we don't actually have multiple threads involved, we just want
// interiour mutability
//
@ -227,6 +206,14 @@ impl Handler {
self.set_wait_timeout(None);
}
pub fn exit(&self) {
self.exit.store(true, Ordering::Relaxed)
}
pub fn exiting(&self) -> bool {
self.exit.load(Ordering::Relaxed)
}
pub fn request_stop_app_on_launch(&self) {
// Relaxed ordering because we don't actually have multiple threads involved, we just want
// interior mutability
@ -287,6 +274,10 @@ impl Handler {
self.stop_app_on_redraw.load(Ordering::Relaxed)
}
fn set_control_flow(&self, new_control_flow: ControlFlow) {
*self.control_flow.lock().unwrap() = new_control_flow
}
fn control_flow(&self) -> ControlFlow {
*self.control_flow.lock().unwrap()
}
@ -321,13 +312,13 @@ impl Handler {
fn handle_nonuser_event(&self, event: Event<Never>) {
if let Some(ref mut callback) = *self.callback.lock().unwrap() {
callback.handle_nonuser_event(event, &mut self.control_flow.lock().unwrap())
callback.handle_nonuser_event(event)
}
}
fn handle_user_events(&self) {
if let Some(ref mut callback) = *self.callback.lock().unwrap() {
callback.handle_user_events(&mut self.control_flow.lock().unwrap());
callback.handle_user_events();
}
}
@ -347,7 +338,7 @@ impl Handler {
},
};
callback.handle_nonuser_event(event, &mut self.control_flow.lock().unwrap());
callback.handle_nonuser_event(event);
let physical_size = *new_inner_size.lock().unwrap();
drop(new_inner_size);
@ -418,21 +409,28 @@ impl AppState {
HANDLER.set_stop_app_on_redraw_requested(stop_on_redraw);
}
pub fn set_control_flow(control_flow: ControlFlow) {
HANDLER.set_control_flow(control_flow)
}
pub fn control_flow() -> ControlFlow {
HANDLER.control_flow()
}
pub fn exit() -> i32 {
pub fn internal_exit() {
HANDLER.set_in_callback(true);
HANDLER.handle_nonuser_event(Event::LoopExiting);
HANDLER.set_in_callback(false);
HANDLER.exit();
HANDLER.internal_exit();
Self::clear_callback();
if let ControlFlow::ExitWithCode(code) = HANDLER.control_flow() {
code
} else {
0
}
}
pub fn exit() {
HANDLER.exit()
}
pub fn exiting() -> bool {
HANDLER.exiting()
}
pub fn dispatch_init_events() {
@ -528,7 +526,6 @@ impl AppState {
}
}
}
ControlFlow::ExitWithCode(_) => StartCause::Poll, //panic!("unexpected `ControlFlow::Exit`"),
};
HANDLER.set_in_callback(true);
HANDLER.handle_nonuser_event(Event::NewEvents(cause));
@ -643,7 +640,7 @@ impl AppState {
HANDLER.handle_nonuser_event(Event::AboutToWait);
HANDLER.set_in_callback(false);
if HANDLER.should_exit() {
if HANDLER.exiting() {
Self::stop();
}
@ -654,7 +651,7 @@ impl AppState {
let wait_timeout = HANDLER.wait_timeout(); // configured by pump_events
let app_timeout = match HANDLER.control_flow() {
ControlFlow::Wait => None,
ControlFlow::Poll | ControlFlow::ExitWithCode(_) => Some(Instant::now()),
ControlFlow::Poll => Some(Instant::now()),
ControlFlow::WaitUntil(instant) => Some(instant),
};
HANDLER

View file

@ -93,6 +93,22 @@ impl<T: 'static> EventLoopWindowTarget<T> {
pub fn raw_display_handle(&self) -> RawDisplayHandle {
RawDisplayHandle::AppKit(AppKitDisplayHandle::empty())
}
pub(crate) fn set_control_flow(&self, control_flow: ControlFlow) {
AppState::set_control_flow(control_flow)
}
pub(crate) fn control_flow(&self) -> ControlFlow {
AppState::control_flow()
}
pub(crate) fn exit(&self) {
AppState::exit()
}
pub(crate) fn exiting(&self) -> bool {
AppState::exiting()
}
}
impl<T> EventLoopWindowTarget<T> {
@ -213,7 +229,7 @@ impl<T> EventLoop<T> {
pub fn run<F>(mut self, callback: F) -> Result<(), EventLoopError>
where
F: FnMut(Event<T>, &RootWindowTarget<T>, &mut ControlFlow),
F: FnMut(Event<T>, &RootWindowTarget<T>),
{
self.run_ondemand(callback)
}
@ -224,7 +240,7 @@ impl<T> EventLoop<T> {
// redundant wake ups.
pub fn run_ondemand<F>(&mut self, callback: F) -> Result<(), EventLoopError>
where
F: FnMut(Event<T>, &RootWindowTarget<T>, &mut ControlFlow),
F: FnMut(Event<T>, &RootWindowTarget<T>),
{
if AppState::is_running() {
return Err(EventLoopError::AlreadyRunning);
@ -241,14 +257,14 @@ impl<T> EventLoop<T> {
let callback = unsafe {
mem::transmute::<
Rc<RefCell<dyn FnMut(Event<T>, &RootWindowTarget<T>, &mut ControlFlow)>>,
Rc<RefCell<dyn FnMut(Event<T>, &RootWindowTarget<T>, &mut ControlFlow)>>,
Rc<RefCell<dyn FnMut(Event<T>, &RootWindowTarget<T>)>>,
Rc<RefCell<dyn FnMut(Event<T>, &RootWindowTarget<T>)>>,
>(Rc::new(RefCell::new(callback)))
};
self._callback = Some(Rc::clone(&callback));
let exit_code = autoreleasepool(|_| {
autoreleasepool(|_| {
// A bit of juggling with the callback references to make sure
// that `self.callback` is the only owner of the callback.
let weak_cb: Weak<_> = Rc::downgrade(&callback);
@ -288,7 +304,7 @@ impl<T> EventLoop<T> {
resume_unwind(panic);
}
AppState::exit()
AppState::internal_exit()
}));
// # Safety
@ -298,22 +314,17 @@ impl<T> EventLoop<T> {
drop(self._callback.take());
AppState::clear_callback();
match catch_result {
Ok(exit_code) => exit_code,
Err(payload) => resume_unwind(payload),
if let Err(payload) = catch_result {
resume_unwind(payload)
}
});
if exit_code == 0 {
Ok(())
} else {
Err(EventLoopError::ExitFailure(exit_code))
}
Ok(())
}
pub fn pump_events<F>(&mut self, timeout: Option<Duration>, callback: F) -> PumpStatus
where
F: FnMut(Event<T>, &RootWindowTarget<T>, &mut ControlFlow),
F: FnMut(Event<T>, &RootWindowTarget<T>),
{
// # Safety
// We are erasing the lifetime of the application callback here so that we
@ -326,8 +337,8 @@ impl<T> EventLoop<T> {
let callback = unsafe {
mem::transmute::<
Rc<RefCell<dyn FnMut(Event<T>, &RootWindowTarget<T>, &mut ControlFlow)>>,
Rc<RefCell<dyn FnMut(Event<T>, &RootWindowTarget<T>, &mut ControlFlow)>>,
Rc<RefCell<dyn FnMut(Event<T>, &RootWindowTarget<T>)>>,
Rc<RefCell<dyn FnMut(Event<T>, &RootWindowTarget<T>)>>,
>(Rc::new(RefCell::new(callback)))
};
@ -407,9 +418,9 @@ impl<T> EventLoop<T> {
resume_unwind(panic);
}
if let ControlFlow::ExitWithCode(code) = AppState::control_flow() {
AppState::exit();
PumpStatus::Exit(code)
if AppState::exiting() {
AppState::internal_exit();
PumpStatus::Exit(0)
} else {
PumpStatus::Continue
}

View file

@ -1,4 +1,5 @@
use std::{
cell::Cell,
collections::VecDeque,
marker::PhantomData,
mem, slice,
@ -301,6 +302,8 @@ impl<T: 'static> EventLoop<T> {
windows: Vec::new(),
window_target: event_loop::EventLoopWindowTarget {
p: EventLoopWindowTarget {
control_flow: Cell::new(ControlFlow::default()),
exit: Cell::new(false),
creates: Mutex::new(VecDeque::new()),
redraws: Arc::new(Mutex::new(VecDeque::new())),
destroys: Arc::new(Mutex::new(VecDeque::new())),
@ -458,40 +461,20 @@ impl<T: 'static> EventLoop<T> {
pub fn run<F>(mut self, mut event_handler_inner: F) -> Result<(), EventLoopError>
where
F: FnMut(event::Event<T>, &event_loop::EventLoopWindowTarget<T>, &mut ControlFlow),
F: FnMut(event::Event<T>, &event_loop::EventLoopWindowTarget<T>),
{
// Wrapper for event handler function that prevents ExitWithCode from being unset.
let mut event_handler =
move |event: event::Event<T>,
window_target: &event_loop::EventLoopWindowTarget<T>,
control_flow: &mut ControlFlow| {
if let ControlFlow::ExitWithCode(code) = control_flow {
event_handler_inner(
event,
window_target,
&mut ControlFlow::ExitWithCode(*code),
);
} else {
event_handler_inner(event, window_target, control_flow);
}
move |event: event::Event<T>, window_target: &event_loop::EventLoopWindowTarget<T>| {
event_handler_inner(event, window_target);
};
let mut control_flow = ControlFlow::default();
let mut start_cause = StartCause::Init;
let code = loop {
event_handler(
event::Event::NewEvents(start_cause),
&self.window_target,
&mut control_flow,
);
loop {
event_handler(event::Event::NewEvents(start_cause), &self.window_target);
if start_cause == StartCause::Init {
event_handler(
event::Event::Resumed,
&self.window_target,
&mut control_flow,
);
event_handler(event::Event::Resumed, &self.window_target);
}
// Handle window creates.
@ -516,7 +499,6 @@ impl<T: 'static> EventLoop<T> {
event: event::WindowEvent::Resized((properties.w, properties.h).into()),
},
&self.window_target,
&mut control_flow,
);
// Send resize event on create to indicate first position.
@ -526,7 +508,6 @@ impl<T: 'static> EventLoop<T> {
event: event::WindowEvent::Moved((properties.x, properties.y).into()),
},
&self.window_target,
&mut control_flow,
);
}
@ -541,7 +522,6 @@ impl<T: 'static> EventLoop<T> {
event: event::WindowEvent::Destroyed,
},
&self.window_target,
&mut control_flow,
);
self.windows
@ -572,7 +552,7 @@ impl<T: 'static> EventLoop<T> {
window_id,
orbital_event.to_option(),
event_state,
|event| event_handler(event, &self.window_target, &mut control_flow),
|event| event_handler(event, &self.window_target),
);
}
@ -599,11 +579,7 @@ impl<T: 'static> EventLoop<T> {
}
while let Ok(event) = self.user_events_receiver.try_recv() {
event_handler(
event::Event::UserEvent(event),
&self.window_target,
&mut control_flow,
);
event_handler(event::Event::UserEvent(event), &self.window_target);
}
// To avoid deadlocks the redraws lock is not held during event processing.
@ -617,24 +593,22 @@ impl<T: 'static> EventLoop<T> {
event: event::WindowEvent::RedrawRequested,
},
&self.window_target,
&mut control_flow,
);
}
event_handler(
event::Event::AboutToWait,
&self.window_target,
&mut control_flow,
);
event_handler(event::Event::AboutToWait, &self.window_target);
let requested_resume = match control_flow {
if self.window_target.p.exiting() {
break;
}
let requested_resume = match self.window_target.p.control_flow() {
ControlFlow::Poll => {
start_cause = StartCause::Poll;
continue;
}
ControlFlow::Wait => None,
ControlFlow::WaitUntil(instant) => Some(instant),
ControlFlow::ExitWithCode(code) => break code,
};
// Re-using wake socket caused extra wake events before because there were leftover
@ -690,19 +664,11 @@ impl<T: 'static> EventLoop<T> {
};
}
}
};
event_handler(
event::Event::LoopExiting,
&self.window_target,
&mut control_flow,
);
if code == 0 {
Ok(())
} else {
Err(EventLoopError::ExitFailure(code))
}
event_handler(event::Event::LoopExiting, &self.window_target);
Ok(())
}
pub fn window_target(&self) -> &event_loop::EventLoopWindowTarget<T> {
@ -746,6 +712,8 @@ impl<T> Clone for EventLoopProxy<T> {
impl<T> Unpin for EventLoopProxy<T> {}
pub struct EventLoopWindowTarget<T: 'static> {
control_flow: Cell<ControlFlow>,
exit: Cell<bool>,
pub(super) creates: Mutex<VecDeque<Arc<RedoxSocket>>>,
pub(super) redraws: Arc<Mutex<VecDeque<WindowId>>>,
pub(super) destroys: Arc<Mutex<VecDeque<WindowId>>>,
@ -771,4 +739,20 @@ impl<T: 'static> EventLoopWindowTarget<T> {
pub fn raw_display_handle(&self) -> RawDisplayHandle {
RawDisplayHandle::Orbital(OrbitalDisplayHandle::empty())
}
pub fn set_control_flow(&self, control_flow: ControlFlow) {
self.control_flow.set(control_flow)
}
pub fn control_flow(&self) -> ControlFlow {
self.control_flow.get()
}
pub(crate) fn exit(&self) {
self.exit.set(true);
}
pub(crate) fn exiting(&self) -> bool {
self.exit.get()
}
}

View file

@ -3,7 +3,7 @@ use std::sync::mpsc::{self, Receiver, Sender};
use crate::error::EventLoopError;
use crate::event::Event;
use crate::event_loop::{ControlFlow, EventLoopWindowTarget as RootEventLoopWindowTarget};
use crate::event_loop::EventLoopWindowTarget as RootEventLoopWindowTarget;
use super::{backend, device, window};
@ -39,7 +39,7 @@ impl<T> EventLoop<T> {
pub fn run<F>(self, mut event_handler: F) -> !
where
F: FnMut(Event<T>, &RootEventLoopWindowTarget<T>, &mut ControlFlow),
F: FnMut(Event<T>, &RootEventLoopWindowTarget<T>),
{
let target = RootEventLoopWindowTarget {
p: self.elw.p.clone(),
@ -47,7 +47,7 @@ impl<T> EventLoop<T> {
};
// SAFETY: Don't use `move` to make sure we leak the `event_handler` and `target`.
let handler: Box<dyn FnMut(Event<()>, _)> = Box::new(|event, flow| {
let handler: Box<dyn FnMut(Event<()>)> = Box::new(|event| {
let event = match event.map_nonuser_event() {
Ok(event) => event,
Err(Event::UserEvent(())) => Event::UserEvent(
@ -57,7 +57,7 @@ impl<T> EventLoop<T> {
),
Err(_) => unreachable!(),
};
event_handler(event, &target, flow)
event_handler(event, &target)
});
// SAFETY: The `transmute` is necessary because `run()` requires `'static`. This is safe
// because this function will never return and all resources not cleaned up by the point we
@ -76,7 +76,7 @@ impl<T> EventLoop<T> {
pub fn spawn<F>(self, mut event_handler: F)
where
F: 'static + FnMut(Event<T>, &RootEventLoopWindowTarget<T>, &mut ControlFlow),
F: 'static + FnMut(Event<T>, &RootEventLoopWindowTarget<T>),
{
let target = RootEventLoopWindowTarget {
p: self.elw.p.clone(),
@ -84,7 +84,7 @@ impl<T> EventLoop<T> {
};
self.elw.p.run(
Box::new(move |event, flow| {
Box::new(move |event| {
let event = match event.map_nonuser_event() {
Ok(event) => event,
Err(Event::UserEvent(())) => Event::UserEvent(
@ -94,7 +94,7 @@ impl<T> EventLoop<T> {
),
Err(_) => unreachable!(),
};
event_handler(event, &target, flow)
event_handler(event, &target)
}),
true,
);

View file

@ -24,7 +24,7 @@ use web_time::{Duration, Instant};
pub struct Shared(Rc<Execution>);
pub(super) type EventHandler = dyn FnMut(Event<()>, &mut ControlFlow);
pub(super) type EventHandler = dyn FnMut(Event<()>);
impl Clone for Shared {
fn clone(&self) -> Self {
@ -35,6 +35,8 @@ impl Clone for Shared {
type OnEventHandle<T> = RefCell<Option<EventListenerHandle<dyn FnMut(T)>>>;
pub struct Execution {
control_flow: Cell<ControlFlow>,
exit: Cell<bool>,
runner: RefCell<RunnerEnum>,
suspended: Cell<bool>,
event_loop_recreation: Cell<bool>,
@ -108,16 +110,9 @@ impl Runner {
})
}
fn handle_single_event(
&mut self,
runner: &Shared,
event: impl Into<EventWrapper>,
control: &mut ControlFlow,
) {
let is_closed = matches!(*control, ControlFlow::ExitWithCode(_));
fn handle_single_event(&mut self, runner: &Shared, event: impl Into<EventWrapper>) {
match event.into() {
EventWrapper::Event(event) => (self.event_handler)(event, control),
EventWrapper::Event(event) => (self.event_handler)(event),
EventWrapper::ScaleChange {
canvas,
size,
@ -126,18 +121,13 @@ impl Runner {
if let Some(canvas) = canvas.upgrade() {
canvas.borrow().handle_scale_change(
runner,
|event| (self.event_handler)(event, control),
|event| (self.event_handler)(event),
size,
scale,
)
}
}
}
// Maintain closed state, even if the callback changes it
if is_closed {
*control = ControlFlow::Exit;
}
}
}
@ -149,6 +139,8 @@ impl Shared {
let document = window.document().expect("Failed to obtain document");
Shared(Rc::new(Execution {
control_flow: Cell::new(ControlFlow::default()),
exit: Cell::new(false),
runner: RefCell::new(RunnerEnum::Pending),
suspended: Cell::new(false),
event_loop_recreation: Cell::new(false),
@ -549,19 +541,16 @@ impl Shared {
// Process the destroy-pending windows. This should only be called from
// `run_until_cleared`, somewhere between emitting `NewEvents` and `AboutToWait`.
fn process_destroy_pending_windows(&self, control: &mut ControlFlow) {
fn process_destroy_pending_windows(&self) {
while let Some(id) = self.0.destroy_pending.borrow_mut().pop_front() {
self.0
.all_canvases
.borrow_mut()
.retain(|&(item_id, _)| item_id != id);
self.handle_event(
Event::WindowEvent {
window_id: id,
event: crate::event::WindowEvent::Destroyed,
},
control,
);
self.handle_event(Event::WindowEvent {
window_id: id,
event: crate::event::WindowEvent::Destroyed,
});
self.0.redraw_pending.borrow_mut().remove(&id);
}
}
@ -571,52 +560,48 @@ impl Shared {
//
// This will also process any events that have been queued or that are queued during processing
fn run_until_cleared<E: Into<EventWrapper>>(&self, events: impl Iterator<Item = E>) {
let mut control = self.current_control_flow();
for event in events {
self.handle_event(event.into(), &mut control);
self.handle_event(event.into());
}
self.process_destroy_pending_windows(&mut control);
self.process_destroy_pending_windows();
// Collect all of the redraw events to avoid double-locking the RefCell
let redraw_events: Vec<WindowId> = self.0.redraw_pending.borrow_mut().drain().collect();
for window_id in redraw_events {
self.handle_event(
Event::WindowEvent {
window_id,
event: WindowEvent::RedrawRequested,
},
&mut control,
);
self.handle_event(Event::WindowEvent {
window_id,
event: WindowEvent::RedrawRequested,
});
}
self.handle_event(Event::AboutToWait, &mut control);
self.handle_event(Event::AboutToWait);
self.apply_control_flow(control);
self.apply_control_flow();
// If the event loop is closed, it has been closed this iteration and now the closing
// event should be emitted
if self.is_closed() {
self.handle_loop_destroyed(&mut control);
self.handle_loop_destroyed();
}
}
fn handle_unload(&self) {
self.apply_control_flow(ControlFlow::Exit);
let mut control = self.current_control_flow();
self.exit();
self.apply_control_flow();
// 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.
self.handle_event(Event::LoopExiting, &mut control);
self.handle_event(Event::LoopExiting);
}
// handle_event takes in events and either queues them or applies a callback
//
// It should only ever be called from `run_until_cleared`.
fn handle_event(&self, event: impl Into<EventWrapper>, control: &mut ControlFlow) {
fn handle_event(&self, event: impl Into<EventWrapper>) {
if self.is_closed() {
*control = ControlFlow::Exit;
self.exit();
}
match *self.0.runner.borrow_mut() {
RunnerEnum::Running(ref mut runner) => {
runner.handle_single_event(self, event, control);
runner.handle_single_event(self, event);
}
// If an event is being handled without a runner somehow, add it to the event queue so
// it will eventually be processed
@ -625,7 +610,7 @@ impl Shared {
RunnerEnum::Destroyed => return,
}
let is_closed = matches!(*control, ControlFlow::ExitWithCode(_));
let is_closed = self.exiting();
// Don't take events out of the queue if the loop is closed or the runner doesn't exist
// If the runner doesn't exist and this method recurses, it will recurse infinitely
@ -634,50 +619,53 @@ impl Shared {
// Make sure not to let the borrow_mut live during the next handle_event
let event = { self.0.events.borrow_mut().pop_front() };
if let Some(event) = event {
self.handle_event(event, control);
self.handle_event(event);
}
}
}
// Apply the new ControlFlow that has been selected by the user
// Start any necessary timeouts etc
fn apply_control_flow(&self, control_flow: ControlFlow) {
let new_state = match control_flow {
ControlFlow::Poll => {
let cloned = self.clone();
State::Poll {
request: backend::Schedule::new(
self.window().clone(),
move || cloned.poll(),
None,
),
fn apply_control_flow(&self) {
let new_state = if self.exiting() {
State::Exit
} else {
match self.control_flow() {
ControlFlow::Poll => {
let cloned = self.clone();
State::Poll {
request: backend::Schedule::new(
self.window().clone(),
move || cloned.poll(),
None,
),
}
}
ControlFlow::Wait => State::Wait {
start: Instant::now(),
},
ControlFlow::WaitUntil(end) => {
let start = Instant::now();
let delay = if end <= start {
Duration::from_millis(0)
} else {
end - start
};
let cloned = self.clone();
State::WaitUntil {
start,
end,
timeout: backend::Schedule::new(
self.window().clone(),
move || cloned.resume_time_reached(start, end),
Some(delay),
),
}
}
}
ControlFlow::Wait => State::Wait {
start: Instant::now(),
},
ControlFlow::WaitUntil(end) => {
let start = Instant::now();
let delay = if end <= start {
Duration::from_millis(0)
} else {
end - start
};
let cloned = self.clone();
State::WaitUntil {
start,
end,
timeout: backend::Schedule::new(
self.window().clone(),
move || cloned.resume_time_reached(start, end),
Some(delay),
),
}
}
ControlFlow::ExitWithCode(_) => State::Exit,
};
if let RunnerEnum::Running(ref mut runner) = *self.0.runner.borrow_mut() {
@ -685,8 +673,8 @@ impl Shared {
}
}
fn handle_loop_destroyed(&self, control: &mut ControlFlow) {
self.handle_event(Event::LoopExiting, control);
fn handle_loop_destroyed(&self) {
self.handle_event(Event::LoopExiting);
let all_canvases = std::mem::take(&mut *self.0.all_canvases.borrow_mut());
*self.0.page_transition_event_handle.borrow_mut() = None;
*self.0.on_mouse_move.borrow_mut() = None;
@ -725,7 +713,7 @@ impl Shared {
// Check if the event loop is currently closed
fn is_closed(&self) -> bool {
match self.0.runner.try_borrow().as_ref().map(Deref::deref) {
Ok(RunnerEnum::Running(runner)) => runner.state.is_exit(),
Ok(RunnerEnum::Running(runner)) => runner.state.exiting(),
// The event loop is not closed since it is not initialized.
Ok(RunnerEnum::Pending) => false,
// The event loop is closed since it has been destroyed.
@ -736,15 +724,6 @@ impl Shared {
}
}
// Get the current control flow state
fn current_control_flow(&self) -> ControlFlow {
match *self.0.runner.borrow() {
RunnerEnum::Running(ref runner) => runner.state.control_flow(),
RunnerEnum::Pending => ControlFlow::Poll,
RunnerEnum::Destroyed => ControlFlow::Exit,
}
}
pub fn listen_device_events(&self, allowed: DeviceEvents) {
self.0.device_events.set(allowed)
}
@ -774,6 +753,22 @@ impl Shared {
pub fn event_loop_recreation(&self, allow: bool) {
self.0.event_loop_recreation.set(allow)
}
pub(crate) fn control_flow(&self) -> ControlFlow {
self.0.control_flow.get()
}
pub(crate) fn set_control_flow(&self, control_flow: ControlFlow) {
self.0.control_flow.set(control_flow)
}
pub(crate) fn exit(&self) {
self.0.exit.set(true)
}
pub(crate) fn exiting(&self) -> bool {
self.0.exit.get()
}
}
pub(crate) enum EventWrapper {

View file

@ -1,5 +1,4 @@
use super::backend;
use crate::event_loop::ControlFlow;
use web_time::Instant;
@ -21,17 +20,7 @@ pub enum State {
}
impl State {
pub fn is_exit(&self) -> bool {
pub fn exiting(&self) -> bool {
matches!(self, State::Exit)
}
pub fn control_flow(&self) -> ControlFlow {
match self {
State::Init => ControlFlow::Poll,
State::WaitUntil { end, .. } => ControlFlow::WaitUntil(*end),
State::Wait { .. } => ControlFlow::Wait,
State::Poll { .. } => ControlFlow::Poll,
State::Exit => ControlFlow::Exit,
}
}
}

View file

@ -19,7 +19,7 @@ use super::{
use crate::event::{
DeviceId as RootDeviceId, ElementState, Event, KeyEvent, Touch, TouchPhase, WindowEvent,
};
use crate::event_loop::DeviceEvents;
use crate::event_loop::{ControlFlow, DeviceEvents};
use crate::keyboard::ModifiersState;
use crate::window::{Theme, WindowId as RootWindowId};
@ -678,4 +678,20 @@ impl<T> EventLoopWindowTarget<T> {
pub fn listen_device_events(&self, allowed: DeviceEvents) {
self.runner.listen_device_events(allowed)
}
pub(crate) fn set_control_flow(&self, control_flow: ControlFlow) {
self.runner.set_control_flow(control_flow)
}
pub(crate) fn control_flow(&self) -> ControlFlow {
self.runner.control_flow()
}
pub(crate) fn exit(&self) {
self.runner.exit()
}
pub(crate) fn exiting(&self) -> bool {
self.runner.exiting()
}
}

View file

@ -250,14 +250,14 @@ impl<T: 'static> EventLoop<T> {
pub fn run<F>(mut self, event_handler: F) -> Result<(), EventLoopError>
where
F: FnMut(Event<T>, &RootELW<T>, &mut ControlFlow),
F: FnMut(Event<T>, &RootELW<T>),
{
self.run_ondemand(event_handler)
}
pub fn run_ondemand<F>(&mut self, mut event_handler: F) -> Result<(), EventLoopError>
where
F: FnMut(Event<T>, &RootELW<T>, &mut ControlFlow),
F: FnMut(Event<T>, &RootELW<T>),
{
{
let runner = &self.window_target.p.runner_shared;
@ -270,18 +270,20 @@ impl<T: 'static> EventLoop<T> {
// We make sure to call runner.clear_event_handler() before
// returning
unsafe {
runner.set_event_handler(move |event, control_flow| {
event_handler(event, event_loop_windows_ref, control_flow)
});
runner.set_event_handler(move |event| event_handler(event, event_loop_windows_ref));
}
}
let exit_code = loop {
if let ControlFlow::ExitWithCode(code) = self.wait_and_dispatch_message(None) {
self.wait_and_dispatch_message(None);
if let Some(code) = self.exit_code() {
break code;
}
if let ControlFlow::ExitWithCode(code) = self.dispatch_peeked_messages() {
self.dispatch_peeked_messages();
if let Some(code) = self.exit_code() {
break code;
}
};
@ -303,7 +305,7 @@ impl<T: 'static> EventLoop<T> {
pub fn pump_events<F>(&mut self, timeout: Option<Duration>, mut event_handler: F) -> PumpStatus
where
F: FnMut(Event<T>, &RootELW<T>, &mut ControlFlow),
F: FnMut(Event<T>, &RootELW<T>),
{
{
let runner = &self.window_target.p.runner_shared;
@ -317,23 +319,20 @@ impl<T: 'static> EventLoop<T> {
// to leave the runner in an unsound state with an associated
// event handler.
unsafe {
runner.set_event_handler(move |event, control_flow| {
event_handler(event, event_loop_windows_ref, control_flow)
});
runner.set_event_handler(move |event| event_handler(event, event_loop_windows_ref));
runner.wakeup();
}
}
if !matches!(
self.wait_and_dispatch_message(timeout),
ControlFlow::ExitWithCode(_)
) {
self.wait_and_dispatch_message(timeout);
if self.exit_code().is_none() {
self.dispatch_peeked_messages();
}
let runner = &self.window_target.p.runner_shared;
let status = if let ControlFlow::ExitWithCode(code) = runner.control_flow() {
let status = if let Some(code) = runner.exit_code() {
runner.loop_destroyed();
// Immediately reset the internal state for the loop to allow
@ -357,7 +356,7 @@ impl<T: 'static> EventLoop<T> {
}
/// Wait for one message and dispatch it, optionally with a timeout
fn wait_and_dispatch_message(&mut self, timeout: Option<Duration>) -> ControlFlow {
fn wait_and_dispatch_message(&mut self, timeout: Option<Duration>) {
let start = Instant::now();
let runner = &self.window_target.p.runner_shared;
@ -368,7 +367,6 @@ impl<T: 'static> EventLoop<T> {
ControlFlow::WaitUntil(wait_deadline) => {
Some(wait_deadline.saturating_duration_since(start))
}
ControlFlow::ExitWithCode(_code) => unreachable!(),
};
let timeout = min_timeout(control_flow_timeout, timeout);
@ -432,8 +430,7 @@ impl<T: 'static> EventLoop<T> {
match msg_status {
None => {} // No MSG to dispatch
Some(PumpStatus::Exit(code)) => {
runner.set_exit_control_flow(code);
return runner.control_flow();
runner.set_exit_code(code);
}
Some(PumpStatus::Continue) => {
unsafe {
@ -454,12 +451,10 @@ impl<T: 'static> EventLoop<T> {
}
}
}
runner.control_flow()
}
/// Dispatch all queued messages via `PeekMessageW`
fn dispatch_peeked_messages(&mut self) -> ControlFlow {
fn dispatch_peeked_messages(&mut self) {
let runner = &self.window_target.p.runner_shared;
// We generally want to continue dispatching all pending messages
@ -476,8 +471,6 @@ impl<T: 'static> EventLoop<T> {
// is the simplest way avoid unitialized memory in Rust
let mut msg = unsafe { mem::zeroed() };
let mut control_flow = runner.control_flow();
loop {
unsafe {
if PeekMessageW(&mut msg, 0, 0, 0, PM_REMOVE) == false.into() {
@ -500,8 +493,7 @@ impl<T: 'static> EventLoop<T> {
panic::resume_unwind(payload);
}
control_flow = runner.control_flow();
if let ControlFlow::ExitWithCode(_code) = control_flow {
if let Some(_code) = runner.exit_code() {
break;
}
@ -509,8 +501,6 @@ impl<T: 'static> EventLoop<T> {
break;
}
}
control_flow
}
pub fn create_proxy(&self) -> EventLoopProxy<T> {
@ -519,6 +509,10 @@ impl<T: 'static> EventLoop<T> {
event_send: self.thread_msg_sender.clone(),
}
}
fn exit_code(&self) -> Option<i32> {
self.window_target.p.exit_code()
}
}
impl<T> EventLoopWindowTarget<T> {
@ -547,6 +541,26 @@ impl<T> EventLoopWindowTarget<T> {
pub fn listen_device_events(&self, allowed: DeviceEvents) {
raw_input::register_all_mice_and_keyboards_for_raw_input(self.thread_msg_target, allowed);
}
pub(crate) fn set_control_flow(&self, control_flow: ControlFlow) {
self.runner_shared.set_control_flow(control_flow)
}
pub(crate) fn control_flow(&self) -> ControlFlow {
self.runner_shared.control_flow()
}
pub(crate) fn exit(&self) {
self.runner_shared.set_exit_code(0)
}
pub(crate) fn exiting(&self) -> bool {
self.runner_shared.exit_code().is_some()
}
fn exit_code(&self) -> Option<i32> {
self.runner_shared.exit_code()
}
}
/// Returns the id of the main thread.

View file

@ -13,7 +13,6 @@ use windows_sys::Win32::Foundation::HWND;
use crate::{
dpi::PhysicalSize,
event::{Event, InnerSizeWriter, StartCause, WindowEvent},
event_loop::ControlFlow,
platform_impl::platform::{
event_loop::{WindowData, GWL_USERDATA},
get_window_long,
@ -21,9 +20,11 @@ use crate::{
window::WindowId,
};
use super::ControlFlow;
pub(crate) type EventLoopRunnerShared<T> = Rc<EventLoopRunner<T>>;
type EventHandler<T> = Cell<Option<Box<dyn FnMut(Event<T>, &mut ControlFlow)>>>;
type EventHandler<T> = Cell<Option<Box<dyn FnMut(Event<T>)>>>;
pub(crate) struct EventLoopRunner<T: 'static> {
// The event loop's win32 handles
@ -35,6 +36,7 @@ pub(crate) struct EventLoopRunner<T: 'static> {
pub(super) interrupt_msg_dispatch: Cell<bool>,
control_flow: Cell<ControlFlow>,
exit: Cell<Option<i32>>,
runner_state: Cell<RunnerState>,
last_events_cleared: Cell<Instant>,
event_handler: EventHandler<T>,
@ -70,7 +72,8 @@ impl<T> EventLoopRunner<T> {
thread_msg_target,
interrupt_msg_dispatch: Cell::new(false),
runner_state: Cell::new(RunnerState::Uninitialized),
control_flow: Cell::new(ControlFlow::Poll),
control_flow: Cell::new(ControlFlow::default()),
exit: Cell::new(None),
panic_error: Cell::new(None),
last_events_cleared: Cell::new(Instant::now()),
event_handler: Cell::new(None),
@ -91,11 +94,11 @@ impl<T> EventLoopRunner<T> {
/// undefined behaviour.
pub(crate) unsafe fn set_event_handler<F>(&self, f: F)
where
F: FnMut(Event<T>, &mut ControlFlow),
F: FnMut(Event<T>),
{
let old_event_handler = self.event_handler.replace(mem::transmute::<
Option<Box<dyn FnMut(Event<T>, &mut ControlFlow)>>,
Option<Box<dyn FnMut(Event<T>, &mut ControlFlow)>>,
Option<Box<dyn FnMut(Event<T>)>>,
Option<Box<dyn FnMut(Event<T>)>>,
>(Some(Box::new(f))));
assert!(old_event_handler.is_none());
}
@ -111,6 +114,7 @@ impl<T> EventLoopRunner<T> {
runner_state,
panic_error,
control_flow,
exit,
last_events_cleared: _,
event_handler,
event_buffer: _,
@ -118,7 +122,8 @@ impl<T> EventLoopRunner<T> {
interrupt_msg_dispatch.set(false);
runner_state.set(RunnerState::Uninitialized);
panic_error.set(None);
control_flow.set(ControlFlow::Poll);
control_flow.set(ControlFlow::default());
exit.set(None);
event_handler.set(None);
}
}
@ -141,14 +146,22 @@ impl<T> EventLoopRunner<T> {
self.runner_state.get()
}
pub fn set_exit_control_flow(&self, code: i32) {
self.control_flow.set(ControlFlow::ExitWithCode(code))
pub fn set_control_flow(&self, control_flow: ControlFlow) {
self.control_flow.set(control_flow)
}
pub fn control_flow(&self) -> ControlFlow {
self.control_flow.get()
}
pub fn set_exit_code(&self, code: i32) {
self.exit.set(Some(code))
}
pub fn exit_code(&self) -> Option<i32> {
self.exit.get()
}
pub fn should_buffer(&self) -> bool {
let handler = self.event_handler.take();
let should_buffer = handler.is_none();
@ -226,18 +239,12 @@ impl<T> EventLoopRunner<T> {
fn call_event_handler(&self, event: Event<T>) {
self.catch_unwind(|| {
let mut control_flow = self.control_flow.take();
let mut event_handler = self.event_handler.take()
.expect("either event handler is re-entrant (likely), or no event handler is registered (very unlikely)");
if let ControlFlow::ExitWithCode(code) = control_flow {
event_handler(event, &mut ControlFlow::ExitWithCode(code));
} else {
event_handler(event, &mut control_flow);
}
event_handler(event);
assert!(self.event_handler.replace(Some(event_handler)).is_none());
self.control_flow.set(control_flow);
});
}
@ -332,16 +339,14 @@ impl<T> EventLoopRunner<T> {
}
fn call_new_events(&self, init: bool) {
let start_cause = match (init, self.control_flow()) {
(true, _) => StartCause::Init,
(false, ControlFlow::Poll) => StartCause::Poll,
(false, ControlFlow::ExitWithCode(_)) | (false, ControlFlow::Wait) => {
StartCause::WaitCancelled {
requested_resume: None,
start: self.last_events_cleared.get(),
}
}
(false, ControlFlow::WaitUntil(requested_resume)) => {
let start_cause = match (init, self.control_flow(), self.exit.get()) {
(true, _, _) => StartCause::Init,
(false, ControlFlow::Poll, None) => StartCause::Poll,
(false, _, Some(_)) | (false, ControlFlow::Wait, None) => StartCause::WaitCancelled {
requested_resume: None,
start: self.last_events_cleared.get(),
},
(false, ControlFlow::WaitUntil(requested_resume), None) => {
if Instant::now() < requested_resume {
StartCause::WaitCancelled {
requested_resume: Some(requested_resume),

View file

@ -40,21 +40,21 @@ pub use raw_window_handle;
/// ```no_run
/// use winit::{
/// event::{Event, WindowEvent},
/// event_loop::EventLoop,
/// event_loop::{ControlFlow, EventLoop},
/// window::Window,
/// };
///
/// let mut event_loop = EventLoop::new().unwrap();
/// let window = Window::new(&event_loop).unwrap();
///
/// event_loop.run(move |event, _, control_flow| {
/// control_flow.set_wait();
/// event_loop.run(move |event, elwt| {
/// elwt.set_control_flow(ControlFlow::Wait);
///
/// match event {
/// Event::WindowEvent {
/// event: WindowEvent::CloseRequested,
/// ..
/// } => control_flow.set_exit(),
/// } => elwt.exit(),
/// _ => (),
/// }
/// });