2023-12-26 01:22:10 +01:00
|
|
|
use super::super::main_thread::MainThreadMarker;
|
2023-06-14 10:26:26 +02:00
|
|
|
use super::super::DeviceId;
|
2023-06-14 09:43:53 +02:00
|
|
|
use super::backend;
|
|
|
|
|
use super::state::State;
|
|
|
|
|
use crate::dpi::PhysicalSize;
|
2023-06-14 10:26:26 +02:00
|
|
|
use crate::event::{
|
|
|
|
|
DeviceEvent, DeviceId as RootDeviceId, ElementState, Event, RawKeyEvent, StartCause,
|
2023-07-10 02:02:38 +02:00
|
|
|
WindowEvent,
|
2023-06-14 10:26:26 +02:00
|
|
|
};
|
|
|
|
|
use crate::event_loop::{ControlFlow, DeviceEvents};
|
2023-09-08 18:39:23 +02:00
|
|
|
use crate::platform::web::PollStrategy;
|
2023-06-14 10:26:26 +02:00
|
|
|
use crate::platform_impl::platform::backend::EventListenerHandle;
|
2023-10-16 15:50:22 +02:00
|
|
|
use crate::platform_impl::platform::r#async::{DispatchRunner, Waker, WakerSpawner};
|
|
|
|
|
use crate::platform_impl::platform::window::Inner;
|
2019-09-23 09:14:26 -04:00
|
|
|
use crate::window::WindowId;
|
2019-06-25 03:15:34 +02:00
|
|
|
|
2024-06-12 00:02:26 +02:00
|
|
|
use js_sys::Function;
|
2023-06-14 10:26:26 +02:00
|
|
|
use std::cell::{Cell, RefCell};
|
2019-09-23 09:14:26 -04:00
|
|
|
use std::collections::{HashSet, VecDeque};
|
2020-01-25 19:04:03 -05:00
|
|
|
use std::iter;
|
2024-06-12 00:02:26 +02:00
|
|
|
use std::num::NonZeroUsize;
|
2020-09-22 06:19:00 +08:00
|
|
|
use std::ops::Deref;
|
2020-09-21 06:42:07 +08:00
|
|
|
use std::rc::{Rc, Weak};
|
2024-06-12 00:02:26 +02:00
|
|
|
use wasm_bindgen::prelude::{wasm_bindgen, Closure};
|
|
|
|
|
use wasm_bindgen::JsCast;
|
2023-07-11 00:11:06 +02:00
|
|
|
use web_sys::{Document, KeyboardEvent, PageTransitionEvent, PointerEvent, WheelEvent};
|
2023-06-01 17:22:28 +02:00
|
|
|
use web_time::{Duration, Instant};
|
2019-06-25 03:15:34 +02:00
|
|
|
|
2023-09-03 02:26:53 +02:00
|
|
|
pub struct Shared(Rc<Execution>);
|
2019-06-25 03:15:34 +02:00
|
|
|
|
2023-09-07 08:25:04 +02:00
|
|
|
pub(super) type EventHandler = dyn FnMut(Event<()>);
|
2022-11-23 13:07:58 +01:00
|
|
|
|
2023-09-03 02:26:53 +02:00
|
|
|
impl Clone for Shared {
|
2019-06-25 03:15:34 +02:00
|
|
|
fn clone(&self) -> Self {
|
|
|
|
|
Shared(self.0.clone())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-14 10:26:26 +02:00
|
|
|
type OnEventHandle<T> = RefCell<Option<EventListenerHandle<dyn FnMut(T)>>>;
|
|
|
|
|
|
2023-09-03 02:26:53 +02:00
|
|
|
pub struct Execution {
|
2023-12-26 01:22:10 +01:00
|
|
|
main_thread: MainThreadMarker,
|
2023-10-16 15:50:22 +02:00
|
|
|
proxy_spawner: WakerSpawner<Weak<Self>>,
|
2023-09-07 08:25:04 +02:00
|
|
|
control_flow: Cell<ControlFlow>,
|
2023-09-08 18:39:23 +02:00
|
|
|
poll_strategy: Cell<PollStrategy>,
|
2023-09-07 08:25:04 +02:00
|
|
|
exit: Cell<bool>,
|
2023-09-03 02:26:53 +02:00
|
|
|
runner: RefCell<RunnerEnum>,
|
2023-07-10 02:02:38 +02:00
|
|
|
suspended: Cell<bool>,
|
2023-06-25 12:03:22 +02:00
|
|
|
event_loop_recreation: Cell<bool>,
|
2023-09-03 02:26:53 +02:00
|
|
|
events: RefCell<VecDeque<EventWrapper>>,
|
2019-09-19 18:40:18 -04:00
|
|
|
id: RefCell<u32>,
|
2023-06-05 02:44:54 +02:00
|
|
|
window: web_sys::Window,
|
2023-07-11 00:11:06 +02:00
|
|
|
document: Document,
|
2023-10-16 15:50:22 +02:00
|
|
|
#[allow(clippy::type_complexity)]
|
|
|
|
|
all_canvases: RefCell<Vec<(WindowId, Weak<RefCell<backend::Canvas>>, DispatchRunner<Inner>)>>,
|
2019-09-23 09:14:26 -04:00
|
|
|
redraw_pending: RefCell<HashSet<WindowId>>,
|
2020-09-21 06:42:07 +08:00
|
|
|
destroy_pending: RefCell<VecDeque<WindowId>>,
|
2023-06-28 12:54:21 +02:00
|
|
|
page_transition_event_handle: RefCell<Option<backend::PageTransitionEventHandle>>,
|
2023-06-14 10:26:26 +02:00
|
|
|
device_events: Cell<DeviceEvents>,
|
|
|
|
|
on_mouse_move: OnEventHandle<PointerEvent>,
|
|
|
|
|
on_wheel: OnEventHandle<WheelEvent>,
|
|
|
|
|
on_mouse_press: OnEventHandle<PointerEvent>,
|
|
|
|
|
on_mouse_release: OnEventHandle<PointerEvent>,
|
|
|
|
|
on_key_press: OnEventHandle<KeyboardEvent>,
|
|
|
|
|
on_key_release: OnEventHandle<KeyboardEvent>,
|
2023-07-10 02:02:38 +02:00
|
|
|
on_visibility_change: OnEventHandle<web_sys::Event>,
|
2020-09-21 06:42:07 +08:00
|
|
|
}
|
|
|
|
|
|
2023-09-03 02:26:53 +02:00
|
|
|
enum RunnerEnum {
|
2020-09-21 06:42:07 +08:00
|
|
|
/// The `EventLoop` is created but not being run.
|
|
|
|
|
Pending,
|
|
|
|
|
/// The `EventLoop` is being run.
|
2023-09-03 02:26:53 +02:00
|
|
|
Running(Runner),
|
2024-02-23 14:37:21 +04:00
|
|
|
/// The `EventLoop` is exited after being started with `EventLoop::run_app`. Since
|
|
|
|
|
/// `EventLoop::run_app` takes ownership of the `EventLoop`, we can be certain
|
2020-09-21 06:42:07 +08:00
|
|
|
/// that this event loop will never be run again.
|
|
|
|
|
Destroyed,
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-03 02:26:53 +02:00
|
|
|
impl RunnerEnum {
|
|
|
|
|
fn maybe_runner(&self) -> Option<&Runner> {
|
2020-09-21 06:42:07 +08:00
|
|
|
match self {
|
|
|
|
|
RunnerEnum::Running(runner) => Some(runner),
|
|
|
|
|
_ => None,
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
|
|
|
|
|
2023-09-03 02:26:53 +02:00
|
|
|
struct Runner {
|
2019-06-25 03:15:34 +02:00
|
|
|
state: State,
|
2023-09-03 02:26:53 +02:00
|
|
|
event_handler: Box<EventHandler>,
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
|
|
|
|
|
2023-09-03 02:26:53 +02:00
|
|
|
impl Runner {
|
|
|
|
|
pub fn new(event_handler: Box<EventHandler>) -> Self {
|
2019-06-25 03:15:34 +02:00
|
|
|
Runner { state: State::Init, event_handler }
|
|
|
|
|
}
|
2020-08-30 21:15:44 +08:00
|
|
|
|
2022-07-15 14:02:12 -02:30
|
|
|
/// Returns the corresponding `StartCause` for the current `state`, or `None`
|
2020-08-30 21:15:44 +08:00
|
|
|
/// when in `Exit` state.
|
|
|
|
|
fn maybe_start_cause(&self) -> Option<StartCause> {
|
|
|
|
|
Some(match self.state {
|
|
|
|
|
State::Init => StartCause::Init,
|
|
|
|
|
State::Poll { .. } => StartCause::Poll,
|
|
|
|
|
State::Wait { start } => StartCause::WaitCancelled { start, requested_resume: None },
|
|
|
|
|
State::WaitUntil { start, end, .. } => {
|
|
|
|
|
StartCause::WaitCancelled { start, requested_resume: Some(end) }
|
|
|
|
|
},
|
|
|
|
|
State::Exit => return None,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-07 08:25:04 +02:00
|
|
|
fn handle_single_event(&mut self, runner: &Shared, event: impl Into<EventWrapper>) {
|
2023-06-14 09:43:53 +02:00
|
|
|
match event.into() {
|
2023-09-07 08:25:04 +02:00
|
|
|
EventWrapper::Event(event) => (self.event_handler)(event),
|
2023-06-14 09:43:53 +02:00
|
|
|
EventWrapper::ScaleChange { canvas, size, scale } => {
|
|
|
|
|
if let Some(canvas) = canvas.upgrade() {
|
|
|
|
|
canvas.borrow().handle_scale_change(
|
|
|
|
|
runner,
|
2023-09-07 08:25:04 +02:00
|
|
|
|event| (self.event_handler)(event),
|
2023-06-14 09:43:53 +02:00
|
|
|
size,
|
|
|
|
|
scale,
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
}
|
2020-08-30 21:15:44 +08:00
|
|
|
}
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
|
|
|
|
|
2023-09-03 02:26:53 +02:00
|
|
|
impl Shared {
|
2019-06-25 03:15:34 +02:00
|
|
|
pub fn new() -> Self {
|
2023-12-26 01:22:10 +01:00
|
|
|
let main_thread = MainThreadMarker::new().expect("only callable from inside the `Window`");
|
2023-07-11 00:11:06 +02:00
|
|
|
#[allow(clippy::disallowed_methods)]
|
|
|
|
|
let window = web_sys::window().expect("only callable from inside the `Window`");
|
|
|
|
|
#[allow(clippy::disallowed_methods)]
|
|
|
|
|
let document = window.document().expect("Failed to obtain document");
|
|
|
|
|
|
2023-10-16 15:50:22 +02:00
|
|
|
Shared(Rc::<Execution>::new_cyclic(|weak| {
|
2024-06-12 00:02:26 +02:00
|
|
|
let proxy_spawner =
|
|
|
|
|
WakerSpawner::new(main_thread, weak.clone(), |runner, count, local| {
|
|
|
|
|
if let Some(runner) = runner.upgrade() {
|
|
|
|
|
Shared(runner).send_user_events(count, local)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.expect("`EventLoop` has to be created in the main thread");
|
2023-10-16 15:50:22 +02:00
|
|
|
|
|
|
|
|
Execution {
|
2023-12-26 01:22:10 +01:00
|
|
|
main_thread,
|
2023-10-16 15:50:22 +02:00
|
|
|
proxy_spawner,
|
|
|
|
|
control_flow: Cell::new(ControlFlow::default()),
|
|
|
|
|
poll_strategy: Cell::new(PollStrategy::default()),
|
|
|
|
|
exit: Cell::new(false),
|
|
|
|
|
runner: RefCell::new(RunnerEnum::Pending),
|
|
|
|
|
suspended: Cell::new(false),
|
|
|
|
|
event_loop_recreation: Cell::new(false),
|
|
|
|
|
events: RefCell::new(VecDeque::new()),
|
|
|
|
|
window,
|
|
|
|
|
document,
|
|
|
|
|
id: RefCell::new(0),
|
|
|
|
|
all_canvases: RefCell::new(Vec::new()),
|
|
|
|
|
redraw_pending: RefCell::new(HashSet::new()),
|
|
|
|
|
destroy_pending: RefCell::new(VecDeque::new()),
|
|
|
|
|
page_transition_event_handle: RefCell::new(None),
|
|
|
|
|
device_events: Cell::default(),
|
|
|
|
|
on_mouse_move: RefCell::new(None),
|
|
|
|
|
on_wheel: RefCell::new(None),
|
|
|
|
|
on_mouse_press: RefCell::new(None),
|
|
|
|
|
on_mouse_release: RefCell::new(None),
|
|
|
|
|
on_key_press: RefCell::new(None),
|
|
|
|
|
on_key_release: RefCell::new(None),
|
|
|
|
|
on_visibility_change: RefCell::new(None),
|
|
|
|
|
}
|
2019-06-25 03:15:34 +02:00
|
|
|
}))
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-26 01:22:10 +01:00
|
|
|
pub fn main_thread(&self) -> MainThreadMarker {
|
|
|
|
|
self.0.main_thread
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-05 02:44:54 +02:00
|
|
|
pub fn window(&self) -> &web_sys::Window {
|
|
|
|
|
&self.0.window
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-11 00:11:06 +02:00
|
|
|
pub fn document(&self) -> &Document {
|
|
|
|
|
&self.0.document
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-16 15:50:22 +02:00
|
|
|
pub fn add_canvas(
|
|
|
|
|
&self,
|
|
|
|
|
id: WindowId,
|
|
|
|
|
canvas: Weak<RefCell<backend::Canvas>>,
|
|
|
|
|
runner: DispatchRunner<Inner>,
|
|
|
|
|
) {
|
|
|
|
|
self.0.all_canvases.borrow_mut().push((id, canvas, runner));
|
2020-09-21 06:42:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn notify_destroy_window(&self, id: WindowId) {
|
|
|
|
|
self.0.destroy_pending.borrow_mut().push_back(id);
|
2020-08-30 21:15:44 +08:00
|
|
|
}
|
|
|
|
|
|
2019-06-25 03:15:34 +02:00
|
|
|
// Set the event callback to use for the event loop runner
|
|
|
|
|
// This the event callback is a fairly thin layer over the user-provided callback that closes
|
2024-01-31 17:29:59 +04:00
|
|
|
// over a RootActiveEventLoop reference
|
2023-09-03 02:26:53 +02:00
|
|
|
pub fn set_listener(&self, event_handler: Box<EventHandler>) {
|
2020-09-21 06:42:07 +08:00
|
|
|
{
|
|
|
|
|
let mut runner = self.0.runner.borrow_mut();
|
|
|
|
|
assert!(matches!(*runner, RunnerEnum::Pending));
|
|
|
|
|
*runner = RunnerEnum::Running(Runner::new(event_handler));
|
|
|
|
|
}
|
2020-01-25 19:04:03 -05:00
|
|
|
self.init();
|
2019-09-11 11:47:03 -04:00
|
|
|
|
2023-06-28 12:54:21 +02:00
|
|
|
*self.0.page_transition_event_handle.borrow_mut() = Some(backend::on_page_transition(
|
2023-08-28 19:18:10 +02:00
|
|
|
self.window().clone(),
|
2023-06-28 12:54:21 +02:00
|
|
|
{
|
|
|
|
|
let runner = self.clone();
|
|
|
|
|
move |event: PageTransitionEvent| {
|
|
|
|
|
if event.persisted() {
|
2023-07-10 02:02:38 +02:00
|
|
|
runner.0.suspended.set(false);
|
2023-06-28 12:54:21 +02:00
|
|
|
runner.send_event(Event::Resumed);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
let runner = self.clone();
|
|
|
|
|
move |event: PageTransitionEvent| {
|
2023-07-10 02:02:38 +02:00
|
|
|
runner.0.suspended.set(true);
|
2023-06-28 12:54:21 +02:00
|
|
|
if event.persisted() {
|
|
|
|
|
runner.send_event(Event::Suspended);
|
|
|
|
|
} else {
|
|
|
|
|
runner.handle_unload();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
));
|
2023-06-14 10:26:26 +02:00
|
|
|
|
|
|
|
|
let runner = self.clone();
|
|
|
|
|
let window = self.window().clone();
|
|
|
|
|
*self.0.on_mouse_move.borrow_mut() = Some(EventListenerHandle::new(
|
2023-08-28 19:18:10 +02:00
|
|
|
self.window().clone(),
|
2023-06-14 10:26:26 +02:00
|
|
|
"pointermove",
|
|
|
|
|
Closure::new(move |event: PointerEvent| {
|
|
|
|
|
if !runner.device_events() {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let pointer_type = event.pointer_type();
|
|
|
|
|
|
|
|
|
|
if pointer_type != "mouse" {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// chorded button event
|
|
|
|
|
let device_id = RootDeviceId(DeviceId(event.pointer_id()));
|
|
|
|
|
|
|
|
|
|
if let Some(button) = backend::event::mouse_button(&event) {
|
|
|
|
|
debug_assert_eq!(
|
|
|
|
|
pointer_type, "mouse",
|
|
|
|
|
"expect pointer type of a chorded button event to be a mouse"
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
let state = if backend::event::mouse_buttons(&event).contains(button.into()) {
|
|
|
|
|
ElementState::Pressed
|
|
|
|
|
} else {
|
|
|
|
|
ElementState::Released
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
runner.send_event(Event::DeviceEvent {
|
|
|
|
|
device_id,
|
|
|
|
|
event: DeviceEvent::Button { button: button.to_id(), state },
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// pointer move event
|
|
|
|
|
let mut delta = backend::event::MouseDelta::init(&window, &event);
|
|
|
|
|
runner.send_events(backend::event::pointer_move_event(event).flat_map(|event| {
|
|
|
|
|
let delta = delta.delta(&event).to_physical(backend::scale_factor(&window));
|
|
|
|
|
|
|
|
|
|
let x_motion = (delta.x != 0.0).then_some(Event::DeviceEvent {
|
|
|
|
|
device_id,
|
|
|
|
|
event: DeviceEvent::Motion { axis: 0, value: delta.x },
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
let y_motion = (delta.y != 0.0).then_some(Event::DeviceEvent {
|
|
|
|
|
device_id,
|
|
|
|
|
event: DeviceEvent::Motion { axis: 1, value: delta.y },
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
x_motion.into_iter().chain(y_motion).chain(iter::once(Event::DeviceEvent {
|
|
|
|
|
device_id,
|
|
|
|
|
event: DeviceEvent::MouseMotion { delta: (delta.x, delta.y) },
|
|
|
|
|
}))
|
|
|
|
|
}));
|
|
|
|
|
}),
|
|
|
|
|
));
|
|
|
|
|
let runner = self.clone();
|
|
|
|
|
let window = self.window().clone();
|
|
|
|
|
*self.0.on_wheel.borrow_mut() = Some(EventListenerHandle::new(
|
2023-08-28 19:18:10 +02:00
|
|
|
self.window().clone(),
|
2023-06-14 10:26:26 +02:00
|
|
|
"wheel",
|
|
|
|
|
Closure::new(move |event: WheelEvent| {
|
|
|
|
|
if !runner.device_events() {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if let Some(delta) = backend::event::mouse_scroll_delta(&window, &event) {
|
|
|
|
|
runner.send_event(Event::DeviceEvent {
|
|
|
|
|
device_id: RootDeviceId(DeviceId(0)),
|
|
|
|
|
event: DeviceEvent::MouseWheel { delta },
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}),
|
|
|
|
|
));
|
|
|
|
|
let runner = self.clone();
|
|
|
|
|
*self.0.on_mouse_press.borrow_mut() = Some(EventListenerHandle::new(
|
2023-08-28 19:18:10 +02:00
|
|
|
self.window().clone(),
|
2023-06-14 10:26:26 +02:00
|
|
|
"pointerdown",
|
|
|
|
|
Closure::new(move |event: PointerEvent| {
|
|
|
|
|
if !runner.device_events() {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if event.pointer_type() != "mouse" {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let button = backend::event::mouse_button(&event).expect("no mouse button pressed");
|
|
|
|
|
runner.send_event(Event::DeviceEvent {
|
|
|
|
|
device_id: RootDeviceId(DeviceId(event.pointer_id())),
|
|
|
|
|
event: DeviceEvent::Button {
|
|
|
|
|
button: button.to_id(),
|
|
|
|
|
state: ElementState::Pressed,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}),
|
|
|
|
|
));
|
|
|
|
|
let runner = self.clone();
|
|
|
|
|
*self.0.on_mouse_release.borrow_mut() = Some(EventListenerHandle::new(
|
2023-08-28 19:18:10 +02:00
|
|
|
self.window().clone(),
|
2023-06-14 10:26:26 +02:00
|
|
|
"pointerup",
|
|
|
|
|
Closure::new(move |event: PointerEvent| {
|
|
|
|
|
if !runner.device_events() {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if event.pointer_type() != "mouse" {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let button = backend::event::mouse_button(&event).expect("no mouse button pressed");
|
|
|
|
|
runner.send_event(Event::DeviceEvent {
|
|
|
|
|
device_id: RootDeviceId(DeviceId(event.pointer_id())),
|
|
|
|
|
event: DeviceEvent::Button {
|
|
|
|
|
button: button.to_id(),
|
|
|
|
|
state: ElementState::Released,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}),
|
|
|
|
|
));
|
|
|
|
|
let runner = self.clone();
|
|
|
|
|
*self.0.on_key_press.borrow_mut() = Some(EventListenerHandle::new(
|
2023-08-28 19:18:10 +02:00
|
|
|
self.window().clone(),
|
2023-06-14 10:26:26 +02:00
|
|
|
"keydown",
|
|
|
|
|
Closure::new(move |event: KeyboardEvent| {
|
|
|
|
|
if !runner.device_events() {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
runner.send_event(Event::DeviceEvent {
|
|
|
|
|
device_id: RootDeviceId(unsafe { DeviceId::dummy() }),
|
|
|
|
|
event: DeviceEvent::Key(RawKeyEvent {
|
|
|
|
|
physical_key: backend::event::key_code(&event),
|
|
|
|
|
state: ElementState::Pressed,
|
|
|
|
|
}),
|
|
|
|
|
});
|
|
|
|
|
}),
|
|
|
|
|
));
|
|
|
|
|
let runner = self.clone();
|
|
|
|
|
*self.0.on_key_release.borrow_mut() = Some(EventListenerHandle::new(
|
2023-08-28 19:18:10 +02:00
|
|
|
self.window().clone(),
|
2023-06-14 10:26:26 +02:00
|
|
|
"keyup",
|
|
|
|
|
Closure::new(move |event: KeyboardEvent| {
|
|
|
|
|
if !runner.device_events() {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
runner.send_event(Event::DeviceEvent {
|
|
|
|
|
device_id: RootDeviceId(unsafe { DeviceId::dummy() }),
|
|
|
|
|
event: DeviceEvent::Key(RawKeyEvent {
|
|
|
|
|
physical_key: backend::event::key_code(&event),
|
|
|
|
|
state: ElementState::Released,
|
|
|
|
|
}),
|
|
|
|
|
});
|
|
|
|
|
}),
|
|
|
|
|
));
|
2023-07-10 02:02:38 +02:00
|
|
|
let runner = self.clone();
|
|
|
|
|
*self.0.on_visibility_change.borrow_mut() = Some(EventListenerHandle::new(
|
|
|
|
|
// Safari <14 doesn't support the `visibilitychange` event on `Window`.
|
2023-08-28 19:18:10 +02:00
|
|
|
self.document().clone(),
|
2023-07-10 02:02:38 +02:00
|
|
|
"visibilitychange",
|
|
|
|
|
Closure::new(move |_| {
|
|
|
|
|
if !runner.0.suspended.get() {
|
2023-10-16 15:50:22 +02:00
|
|
|
for (id, canvas, _) in &*runner.0.all_canvases.borrow() {
|
2023-07-10 02:02:38 +02:00
|
|
|
if let Some(canvas) = canvas.upgrade() {
|
2023-07-11 00:11:06 +02:00
|
|
|
let is_visible = backend::is_visible(runner.document());
|
2023-07-10 23:55:43 +02:00
|
|
|
// only fire if:
|
|
|
|
|
// - not visible and intersects
|
|
|
|
|
// - not visible and we don't know if it intersects yet
|
|
|
|
|
// - visible and intersects
|
|
|
|
|
if let (false, Some(true) | None) | (true, Some(true)) =
|
|
|
|
|
(is_visible, canvas.borrow().is_intersecting)
|
|
|
|
|
{
|
2023-07-10 02:02:38 +02:00
|
|
|
runner.send_event(Event::WindowEvent {
|
|
|
|
|
window_id: *id,
|
2023-07-10 23:55:43 +02:00
|
|
|
event: WindowEvent::Occluded(!is_visible),
|
2023-07-10 02:02:38 +02:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}),
|
|
|
|
|
));
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
|
|
|
|
|
2019-09-19 18:40:18 -04:00
|
|
|
// Generate a strictly increasing ID
|
|
|
|
|
// This is used to differentiate windows when handling events
|
|
|
|
|
pub fn generate_id(&self) -> u32 {
|
|
|
|
|
let mut id = self.0.id.borrow_mut();
|
|
|
|
|
*id += 1;
|
|
|
|
|
|
|
|
|
|
*id
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-23 09:14:26 -04:00
|
|
|
pub fn request_redraw(&self, id: WindowId) {
|
|
|
|
|
self.0.redraw_pending.borrow_mut().insert(id);
|
2023-09-03 02:26:53 +02:00
|
|
|
self.send_events::<EventWrapper>(iter::empty());
|
2019-09-23 09:14:26 -04:00
|
|
|
}
|
|
|
|
|
|
2020-01-25 19:04:03 -05:00
|
|
|
pub fn init(&self) {
|
2022-07-26 14:03:12 +01:00
|
|
|
// NB: For consistency all platforms must emit a 'resumed' event even though web
|
|
|
|
|
// applications don't themselves have a formal suspend/resume lifecycle.
|
|
|
|
|
self.run_until_cleared([Event::NewEvents(StartCause::Init), Event::Resumed].into_iter());
|
2020-01-25 19:04:03 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Run the polling logic for the Poll ControlFlow, which involves clearing the queue
|
|
|
|
|
pub fn poll(&self) {
|
|
|
|
|
let start_cause = Event::NewEvents(StartCause::Poll);
|
|
|
|
|
self.run_until_cleared(iter::once(start_cause));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Run the logic for waking from a WaitUntil, which involves clearing the queue
|
|
|
|
|
// Generally there shouldn't be events built up when this is called
|
|
|
|
|
pub fn resume_time_reached(&self, start: Instant, requested_resume: Instant) {
|
|
|
|
|
let start_cause =
|
|
|
|
|
Event::NewEvents(StartCause::ResumeTimeReached { start, requested_resume });
|
|
|
|
|
self.run_until_cleared(iter::once(start_cause));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add an event to the event loop runner, from the user or an event handler
|
2019-06-25 03:15:34 +02:00
|
|
|
//
|
|
|
|
|
// It will determine if the event should be immediately sent to the user or buffered for later
|
2023-09-03 02:26:53 +02:00
|
|
|
pub(crate) fn send_event<E: Into<EventWrapper>>(&self, event: E) {
|
2020-01-25 19:04:03 -05:00
|
|
|
self.send_events(iter::once(event));
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-12 00:02:26 +02:00
|
|
|
// Add a series of user events to the event loop runner
|
|
|
|
|
//
|
|
|
|
|
// This will schedule the event loop to wake up instead of waking it up immediately if its not
|
|
|
|
|
// running.
|
|
|
|
|
pub(crate) fn send_user_events(&self, count: NonZeroUsize, local: bool) {
|
|
|
|
|
// If the event loop is closed, it should discard any new events
|
|
|
|
|
if self.is_closed() {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if local {
|
|
|
|
|
// If the loop is not running and triggered locally, queue on next microtick.
|
|
|
|
|
if let Ok(RunnerEnum::Running(_)) =
|
|
|
|
|
self.0.runner.try_borrow().as_ref().map(Deref::deref)
|
|
|
|
|
{
|
|
|
|
|
#[wasm_bindgen]
|
|
|
|
|
extern "C" {
|
|
|
|
|
#[wasm_bindgen(js_name = queueMicrotask)]
|
|
|
|
|
fn queue_microtask(task: Function);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
queue_microtask(
|
|
|
|
|
Closure::once_into_js({
|
|
|
|
|
let this = Rc::downgrade(&self.0);
|
|
|
|
|
move || {
|
|
|
|
|
if let Some(shared) = this.upgrade() {
|
|
|
|
|
Shared(shared).send_events(
|
|
|
|
|
iter::repeat(Event::UserEvent(())).take(count.get()),
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.unchecked_into(),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self.send_events(iter::repeat(Event::UserEvent(())).take(count.get()))
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-25 19:04:03 -05:00
|
|
|
// Add a series of events to the event loop runner
|
|
|
|
|
//
|
|
|
|
|
// It will determine if the event should be immediately sent to the user or buffered for later
|
2023-09-03 02:26:53 +02:00
|
|
|
pub(crate) fn send_events<E: Into<EventWrapper>>(&self, events: impl IntoIterator<Item = E>) {
|
2019-06-25 03:15:34 +02:00
|
|
|
// If the event loop is closed, it should discard any new events
|
2019-06-25 18:07:47 +02:00
|
|
|
if self.is_closed() {
|
2019-06-25 03:15:34 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2020-01-25 19:04:03 -05:00
|
|
|
// If we can run the event processing right now, or need to queue this and wait for later
|
|
|
|
|
let mut process_immediately = true;
|
2020-09-22 06:19:00 +08:00
|
|
|
match self.0.runner.try_borrow().as_ref().map(Deref::deref) {
|
2024-06-12 00:02:26 +02:00
|
|
|
// If the runner is attached but not running, we always wake it up.
|
|
|
|
|
Ok(RunnerEnum::Running(_)) => (),
|
2020-09-22 06:19:00 +08:00
|
|
|
Ok(RunnerEnum::Pending) => {
|
2020-09-21 06:42:07 +08:00
|
|
|
// The runner still hasn't been attached: queue this event and wait for it to be
|
2020-01-25 19:04:03 -05:00
|
|
|
process_immediately = false;
|
2019-06-25 03:15:34 +02:00
|
|
|
},
|
2020-09-22 06:19:00 +08:00
|
|
|
// Some other code is mutating the runner, which most likely means
|
|
|
|
|
// the event loop is running and busy. So we queue this event for
|
|
|
|
|
// it to be processed later.
|
|
|
|
|
Err(_) => {
|
|
|
|
|
process_immediately = false;
|
|
|
|
|
},
|
2020-09-21 06:42:07 +08:00
|
|
|
// This is unreachable since `self.is_closed() == true`.
|
2020-09-22 06:19:00 +08:00
|
|
|
Ok(RunnerEnum::Destroyed) => unreachable!(),
|
2020-01-25 19:04:03 -05:00
|
|
|
}
|
|
|
|
|
if !process_immediately {
|
|
|
|
|
// Queue these events to look at later
|
2023-06-14 09:43:53 +02:00
|
|
|
self.0.events.borrow_mut().extend(events.into_iter().map(Into::into));
|
2020-01-25 19:04:03 -05:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// At this point, we know this is a fresh set of events
|
|
|
|
|
// Now we determine why new events are incoming, and handle the events
|
2020-09-21 06:42:07 +08:00
|
|
|
let start_cause = match (self.0.runner.borrow().maybe_runner())
|
2020-08-30 21:15:44 +08:00
|
|
|
.unwrap_or_else(|| {
|
|
|
|
|
unreachable!("The runner cannot process events when it is not attached")
|
|
|
|
|
})
|
|
|
|
|
.maybe_start_cause()
|
|
|
|
|
{
|
|
|
|
|
Some(c) => c,
|
|
|
|
|
// If we're in the exit state, don't do event processing
|
|
|
|
|
None => return,
|
2019-06-25 03:15:34 +02:00
|
|
|
};
|
2020-01-25 19:04:03 -05:00
|
|
|
// Take the start event, then the events provided to this function, and run an iteration of
|
|
|
|
|
// the event loop
|
|
|
|
|
let start_event = Event::NewEvents(start_cause);
|
2023-06-14 09:43:53 +02:00
|
|
|
let events =
|
|
|
|
|
iter::once(EventWrapper::from(start_event)).chain(events.into_iter().map(Into::into));
|
2020-01-25 19:04:03 -05:00
|
|
|
self.run_until_cleared(events);
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-21 06:42:07 +08:00
|
|
|
// Process the destroy-pending windows. This should only be called from
|
2023-07-28 17:37:56 +01:00
|
|
|
// `run_until_cleared`, somewhere between emitting `NewEvents` and `AboutToWait`.
|
2023-09-07 08:25:04 +02:00
|
|
|
fn process_destroy_pending_windows(&self) {
|
2020-09-21 06:42:07 +08:00
|
|
|
while let Some(id) = self.0.destroy_pending.borrow_mut().pop_front() {
|
2023-10-16 15:50:22 +02:00
|
|
|
self.0.all_canvases.borrow_mut().retain(|&(item_id, ..)| item_id != id);
|
2023-09-07 08:25:04 +02:00
|
|
|
self.handle_event(Event::WindowEvent {
|
|
|
|
|
window_id: id,
|
|
|
|
|
event: crate::event::WindowEvent::Destroyed,
|
|
|
|
|
});
|
2020-09-21 06:42:07 +08:00
|
|
|
self.0.redraw_pending.borrow_mut().remove(&id);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-25 19:04:03 -05:00
|
|
|
// Given the set of new events, run the event loop until the main events and redraw events are
|
|
|
|
|
// cleared
|
|
|
|
|
//
|
|
|
|
|
// This will also process any events that have been queued or that are queued during processing
|
2023-09-03 02:26:53 +02:00
|
|
|
fn run_until_cleared<E: Into<EventWrapper>>(&self, events: impl Iterator<Item = E>) {
|
2020-01-25 19:04:03 -05:00
|
|
|
for event in events {
|
2023-09-07 08:25:04 +02:00
|
|
|
self.handle_event(event.into());
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
2023-09-07 08:25:04 +02:00
|
|
|
self.process_destroy_pending_windows();
|
2019-12-03 18:16:06 +01:00
|
|
|
|
2019-09-23 09:14:26 -04:00
|
|
|
// 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 {
|
2023-09-07 08:25:04 +02:00
|
|
|
self.handle_event(Event::WindowEvent {
|
|
|
|
|
window_id,
|
|
|
|
|
event: WindowEvent::RedrawRequested,
|
|
|
|
|
});
|
2019-09-23 09:14:26 -04:00
|
|
|
}
|
2023-07-28 17:37:56 +01:00
|
|
|
|
2023-09-07 08:25:04 +02:00
|
|
|
self.handle_event(Event::AboutToWait);
|
2019-12-03 18:16:06 +01:00
|
|
|
|
2023-09-07 08:25:04 +02:00
|
|
|
self.apply_control_flow();
|
2019-06-25 03:15:34 +02:00
|
|
|
// If the event loop is closed, it has been closed this iteration and now the closing
|
|
|
|
|
// event should be emitted
|
2019-06-25 18:07:47 +02:00
|
|
|
if self.is_closed() {
|
2023-09-07 08:25:04 +02:00
|
|
|
self.handle_loop_destroyed();
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-11 11:47:03 -04:00
|
|
|
fn handle_unload(&self) {
|
2023-09-07 08:25:04 +02:00
|
|
|
self.exit();
|
|
|
|
|
self.apply_control_flow();
|
2020-09-21 06:42:07 +08:00
|
|
|
// 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.
|
2023-09-07 08:25:04 +02:00
|
|
|
self.handle_event(Event::LoopExiting);
|
2019-09-11 11:47:03 -04:00
|
|
|
}
|
|
|
|
|
|
2019-06-25 03:15:34 +02:00
|
|
|
// handle_event takes in events and either queues them or applies a callback
|
|
|
|
|
//
|
2023-06-14 09:43:53 +02:00
|
|
|
// It should only ever be called from `run_until_cleared`.
|
2023-09-07 08:25:04 +02:00
|
|
|
fn handle_event(&self, event: impl Into<EventWrapper>) {
|
2020-08-30 21:15:44 +08:00
|
|
|
if self.is_closed() {
|
2023-09-07 08:25:04 +02:00
|
|
|
self.exit();
|
2020-08-30 21:15:44 +08:00
|
|
|
}
|
2019-06-25 03:15:34 +02:00
|
|
|
match *self.0.runner.borrow_mut() {
|
2020-09-21 06:42:07 +08:00
|
|
|
RunnerEnum::Running(ref mut runner) => {
|
2023-09-07 08:25:04 +02:00
|
|
|
runner.handle_single_event(self, event);
|
2019-06-25 03:15:34 +02:00
|
|
|
},
|
|
|
|
|
// If an event is being handled without a runner somehow, add it to the event queue so
|
|
|
|
|
// it will eventually be processed
|
2023-06-14 09:43:53 +02:00
|
|
|
RunnerEnum::Pending => self.0.events.borrow_mut().push_back(event.into()),
|
2020-09-21 06:42:07 +08:00
|
|
|
// If the Runner has been destroyed, there is nothing to do.
|
|
|
|
|
RunnerEnum::Destroyed => return,
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
|
|
|
|
|
2023-09-07 08:25:04 +02:00
|
|
|
let is_closed = self.exiting();
|
2020-08-30 21:15:44 +08:00
|
|
|
|
2019-06-25 03:15:34 +02:00
|
|
|
// 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
|
2020-09-21 06:42:07 +08:00
|
|
|
if !is_closed && self.0.runner.borrow().maybe_runner().is_some() {
|
2023-10-16 15:50:22 +02:00
|
|
|
// Pre-fetch window commands to avoid having to wait until the next event loop cycle
|
|
|
|
|
// and potentially block other threads in the meantime.
|
|
|
|
|
for (_, window, runner) in self.0.all_canvases.borrow().iter() {
|
|
|
|
|
if let Some(window) = window.upgrade() {
|
|
|
|
|
runner.run();
|
|
|
|
|
drop(window)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-25 03:15:34 +02:00
|
|
|
// Take an event out of the queue and handle it
|
2020-04-11 15:20:38 -04:00
|
|
|
// Make sure not to let the borrow_mut live during the next handle_event
|
2023-10-16 15:50:22 +02:00
|
|
|
let event = {
|
|
|
|
|
let mut events = self.0.events.borrow_mut();
|
|
|
|
|
|
|
|
|
|
// Pre-fetch `UserEvent`s to avoid having to wait until the next event loop cycle.
|
|
|
|
|
events.extend(
|
|
|
|
|
iter::repeat(Event::UserEvent(()))
|
|
|
|
|
.take(self.0.proxy_spawner.fetch())
|
|
|
|
|
.map(EventWrapper::from),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
events.pop_front()
|
|
|
|
|
};
|
2020-04-11 15:20:38 -04:00
|
|
|
if let Some(event) = event {
|
2023-09-07 08:25:04 +02:00
|
|
|
self.handle_event(event);
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Apply the new ControlFlow that has been selected by the user
|
|
|
|
|
// Start any necessary timeouts etc
|
2023-09-07 08:25:04 +02:00
|
|
|
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 {
|
2024-03-27 01:20:21 -07:00
|
|
|
_request: backend::Schedule::new(
|
2023-09-08 18:39:23 +02:00
|
|
|
self.poll_strategy(),
|
2023-09-07 12:12:35 +02:00
|
|
|
self.window(),
|
2023-09-07 08:25:04 +02:00
|
|
|
move || cloned.poll(),
|
|
|
|
|
),
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
ControlFlow::Wait => State::Wait { start: Instant::now() },
|
|
|
|
|
ControlFlow::WaitUntil(end) => {
|
|
|
|
|
let start = Instant::now();
|
2019-06-25 18:07:47 +02:00
|
|
|
|
2023-09-07 08:25:04 +02:00
|
|
|
let delay = if end <= start { Duration::from_millis(0) } else { end - start };
|
|
|
|
|
|
|
|
|
|
let cloned = self.clone();
|
|
|
|
|
|
|
|
|
|
State::WaitUntil {
|
|
|
|
|
start,
|
|
|
|
|
end,
|
2024-03-27 01:20:21 -07:00
|
|
|
_timeout: backend::Schedule::new_with_duration(
|
2023-09-07 12:12:35 +02:00
|
|
|
self.window(),
|
2023-09-07 08:25:04 +02:00
|
|
|
move || cloned.resume_time_reached(start, end),
|
2023-09-07 12:12:35 +02:00
|
|
|
delay,
|
2023-09-07 08:25:04 +02:00
|
|
|
),
|
|
|
|
|
}
|
2019-06-25 03:15:34 +02:00
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2022-06-10 13:43:33 +03:00
|
|
|
if let RunnerEnum::Running(ref mut runner) = *self.0.runner.borrow_mut() {
|
|
|
|
|
runner.state = new_state;
|
2020-09-21 06:42:07 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-07 08:25:04 +02:00
|
|
|
fn handle_loop_destroyed(&self) {
|
|
|
|
|
self.handle_event(Event::LoopExiting);
|
2020-09-21 06:42:07 +08:00
|
|
|
let all_canvases = std::mem::take(&mut *self.0.all_canvases.borrow_mut());
|
2023-06-28 12:54:21 +02:00
|
|
|
*self.0.page_transition_event_handle.borrow_mut() = None;
|
2023-06-14 10:26:26 +02:00
|
|
|
*self.0.on_mouse_move.borrow_mut() = None;
|
|
|
|
|
*self.0.on_wheel.borrow_mut() = None;
|
|
|
|
|
*self.0.on_mouse_press.borrow_mut() = None;
|
|
|
|
|
*self.0.on_mouse_release.borrow_mut() = None;
|
|
|
|
|
*self.0.on_key_press.borrow_mut() = None;
|
|
|
|
|
*self.0.on_key_release.borrow_mut() = None;
|
2023-07-10 02:02:38 +02:00
|
|
|
*self.0.on_visibility_change.borrow_mut() = None;
|
2020-09-21 06:42:07 +08:00
|
|
|
// Dropping the `Runner` drops the event handler closure, which will in
|
|
|
|
|
// turn drop all `Window`s moved into the closure.
|
|
|
|
|
*self.0.runner.borrow_mut() = RunnerEnum::Destroyed;
|
2023-10-16 15:50:22 +02:00
|
|
|
for (_, canvas, _) in all_canvases {
|
2020-09-21 06:42:07 +08:00
|
|
|
// In case any remaining `Window`s are still not dropped, we will need
|
|
|
|
|
// to explicitly remove the event handlers associated with their canvases.
|
|
|
|
|
if let Some(canvas) = canvas.upgrade() {
|
|
|
|
|
let mut canvas = canvas.borrow_mut();
|
|
|
|
|
canvas.remove_listeners();
|
|
|
|
|
}
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
2020-09-21 06:42:07 +08:00
|
|
|
// At this point, the `self.0` `Rc` should only be strongly referenced
|
|
|
|
|
// by the following:
|
|
|
|
|
// * `self`, i.e. the item which triggered this event loop wakeup, which is usually a
|
|
|
|
|
// `wasm-bindgen` `Closure`, which will be dropped after returning to the JS glue code.
|
2024-02-23 14:37:21 +04:00
|
|
|
// * The `ActiveEventLoop` leaked inside `EventLoop::run_app` due to the JS exception thrown
|
2020-09-21 06:42:07 +08:00
|
|
|
// at the end.
|
|
|
|
|
// * For each undropped `Window`:
|
|
|
|
|
// * The `register_redraw_request` closure.
|
|
|
|
|
// * The `destroy_fn` closure.
|
2023-06-25 12:03:22 +02:00
|
|
|
if self.0.event_loop_recreation.get() {
|
2023-09-03 02:26:53 +02:00
|
|
|
crate::event_loop::EventLoopBuilder::<()>::allow_event_loop_recreation();
|
2023-06-25 12:03:22 +02:00
|
|
|
}
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
|
|
|
|
|
2019-06-25 18:07:47 +02:00
|
|
|
// Check if the event loop is currently closed
|
|
|
|
|
fn is_closed(&self) -> bool {
|
2020-09-22 06:19:00 +08:00
|
|
|
match self.0.runner.try_borrow().as_ref().map(Deref::deref) {
|
2023-09-07 08:25:04 +02:00
|
|
|
Ok(RunnerEnum::Running(runner)) => runner.state.exiting(),
|
2020-09-21 06:42:07 +08:00
|
|
|
// The event loop is not closed since it is not initialized.
|
2020-09-22 06:19:00 +08:00
|
|
|
Ok(RunnerEnum::Pending) => false,
|
2020-09-21 06:42:07 +08:00
|
|
|
// The event loop is closed since it has been destroyed.
|
2020-09-22 06:19:00 +08:00
|
|
|
Ok(RunnerEnum::Destroyed) => true,
|
|
|
|
|
// Some other code is mutating the runner, which most likely means
|
|
|
|
|
// the event loop is running and busy.
|
|
|
|
|
Err(_) => false,
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-14 10:26:26 +02:00
|
|
|
pub fn listen_device_events(&self, allowed: DeviceEvents) {
|
|
|
|
|
self.0.device_events.set(allowed)
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-29 09:28:30 +02:00
|
|
|
fn device_events(&self) -> bool {
|
2023-06-14 10:26:26 +02:00
|
|
|
match self.0.device_events.get() {
|
|
|
|
|
DeviceEvents::Always => true,
|
2023-10-16 15:50:22 +02:00
|
|
|
DeviceEvents::WhenFocused => {
|
|
|
|
|
self.0.all_canvases.borrow().iter().any(|(_, canvas, _)| {
|
|
|
|
|
if let Some(canvas) = canvas.upgrade() {
|
|
|
|
|
canvas.borrow().has_focus.get()
|
|
|
|
|
} else {
|
|
|
|
|
false
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
},
|
2023-06-14 10:26:26 +02:00
|
|
|
DeviceEvents::Never => false,
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-06-25 12:03:22 +02:00
|
|
|
|
|
|
|
|
pub fn event_loop_recreation(&self, allow: bool) {
|
|
|
|
|
self.0.event_loop_recreation.set(allow)
|
|
|
|
|
}
|
2023-09-07 08:25:04 +02:00
|
|
|
|
|
|
|
|
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()
|
|
|
|
|
}
|
2023-09-07 12:12:35 +02:00
|
|
|
|
2023-09-08 18:39:23 +02:00
|
|
|
pub(crate) fn set_poll_strategy(&self, strategy: PollStrategy) {
|
|
|
|
|
self.0.poll_strategy.set(strategy)
|
2023-09-07 12:12:35 +02:00
|
|
|
}
|
|
|
|
|
|
2023-09-08 18:39:23 +02:00
|
|
|
pub(crate) fn poll_strategy(&self) -> PollStrategy {
|
|
|
|
|
self.0.poll_strategy.get()
|
2023-09-07 12:12:35 +02:00
|
|
|
}
|
2023-10-16 15:50:22 +02:00
|
|
|
|
|
|
|
|
pub(crate) fn waker(&self) -> Waker<Weak<Execution>> {
|
|
|
|
|
self.0.proxy_spawner.waker()
|
|
|
|
|
}
|
2019-06-25 03:15:34 +02:00
|
|
|
}
|
2023-06-14 09:43:53 +02:00
|
|
|
|
2023-09-03 02:26:53 +02:00
|
|
|
pub(crate) enum EventWrapper {
|
|
|
|
|
Event(Event<()>),
|
2023-06-14 09:43:53 +02:00
|
|
|
ScaleChange { canvas: Weak<RefCell<backend::Canvas>>, size: PhysicalSize<u32>, scale: f64 },
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-03 02:26:53 +02:00
|
|
|
impl From<Event<()>> for EventWrapper {
|
|
|
|
|
fn from(value: Event<()>) -> Self {
|
2023-06-14 09:43:53 +02:00
|
|
|
Self::Event(value)
|
|
|
|
|
}
|
|
|
|
|
}
|