parent
8fdd81ecef
commit
e648169861
60 changed files with 800 additions and 860 deletions
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
_ => (),
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
..
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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") => {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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})");
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
..
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
..
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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:?}")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
..
|
||||
|
|
|
|||
|
|
@ -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}");
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 =
|
||||
|
|
|
|||
|
|
@ -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)));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
15
src/event.rs
15
src/event.rs
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
18
src/lib.rs
18
src/lib.rs
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
/// _ => (),
|
||||
/// }
|
||||
/// });
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue