Web Async Rework (#3082)
This commit is contained in:
parent
ef34692148
commit
48f6582eb4
12 changed files with 653 additions and 421 deletions
|
|
@ -27,11 +27,12 @@ pub(crate) struct PlatformSpecificEventLoopAttributes {}
|
|||
impl<T> EventLoop<T> {
|
||||
pub(crate) fn new(_: &PlatformSpecificEventLoopAttributes) -> Result<Self, EventLoopError> {
|
||||
let (user_event_sender, user_event_receiver) = mpsc::channel();
|
||||
let elw = RootEventLoopWindowTarget {
|
||||
p: EventLoopWindowTarget::new(),
|
||||
_marker: PhantomData,
|
||||
};
|
||||
Ok(EventLoop {
|
||||
elw: RootEventLoopWindowTarget {
|
||||
p: EventLoopWindowTarget::new(),
|
||||
_marker: PhantomData,
|
||||
},
|
||||
elw,
|
||||
user_event_sender,
|
||||
user_event_receiver,
|
||||
})
|
||||
|
|
@ -101,7 +102,7 @@ impl<T> EventLoop<T> {
|
|||
}
|
||||
|
||||
pub fn create_proxy(&self) -> EventLoopProxy<T> {
|
||||
EventLoopProxy::new(self.elw.p.runner.clone(), self.user_event_sender.clone())
|
||||
EventLoopProxy::new(self.elw.p.waker(), self.user_event_sender.clone())
|
||||
}
|
||||
|
||||
pub fn window_target(&self) -> &RootEventLoopWindowTarget<T> {
|
||||
|
|
|
|||
|
|
@ -1,30 +1,25 @@
|
|||
use std::sync::mpsc::Sender;
|
||||
use std::rc::Weak;
|
||||
use std::sync::mpsc::{SendError, Sender};
|
||||
|
||||
use super::runner;
|
||||
use crate::event::Event;
|
||||
use super::runner::Execution;
|
||||
use crate::event_loop::EventLoopClosed;
|
||||
use crate::platform_impl::platform::r#async::Channel;
|
||||
use crate::platform_impl::platform::r#async::Waker;
|
||||
|
||||
pub struct EventLoopProxy<T: 'static> {
|
||||
// used to wake the event loop handler, not to actually pass data
|
||||
runner: Channel<runner::Shared, ()>,
|
||||
runner: Waker<Weak<Execution>>,
|
||||
sender: Sender<T>,
|
||||
}
|
||||
|
||||
impl<T: 'static> EventLoopProxy<T> {
|
||||
pub fn new(runner: runner::Shared, sender: Sender<T>) -> Self {
|
||||
Self {
|
||||
runner: Channel::new(runner, |runner, event| {
|
||||
runner.send_event(Event::UserEvent(event))
|
||||
})
|
||||
.unwrap(),
|
||||
sender,
|
||||
}
|
||||
pub fn new(runner: Waker<Weak<Execution>>, sender: Sender<T>) -> Self {
|
||||
Self { runner, sender }
|
||||
}
|
||||
|
||||
pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
|
||||
self.sender.send(event).unwrap();
|
||||
self.runner.send(());
|
||||
self.sender
|
||||
.send(event)
|
||||
.map_err(|SendError(event)| EventLoopClosed(event))?;
|
||||
self.runner.wake();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,9 +8,10 @@ use crate::event::{
|
|||
use crate::event_loop::{ControlFlow, DeviceEvents};
|
||||
use crate::platform::web::PollStrategy;
|
||||
use crate::platform_impl::platform::backend::EventListenerHandle;
|
||||
use crate::platform_impl::platform::r#async::{DispatchRunner, Waker, WakerSpawner};
|
||||
use crate::platform_impl::platform::window::Inner;
|
||||
use crate::window::WindowId;
|
||||
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::{
|
||||
cell::{Cell, RefCell},
|
||||
clone::Clone,
|
||||
|
|
@ -36,6 +37,7 @@ impl Clone for Shared {
|
|||
type OnEventHandle<T> = RefCell<Option<EventListenerHandle<dyn FnMut(T)>>>;
|
||||
|
||||
pub struct Execution {
|
||||
proxy_spawner: WakerSpawner<Weak<Self>>,
|
||||
control_flow: Cell<ControlFlow>,
|
||||
poll_strategy: Cell<PollStrategy>,
|
||||
exit: Cell<bool>,
|
||||
|
|
@ -46,7 +48,14 @@ pub struct Execution {
|
|||
id: RefCell<u32>,
|
||||
window: web_sys::Window,
|
||||
document: Document,
|
||||
all_canvases: RefCell<Vec<(WindowId, Weak<RefCell<backend::Canvas>>)>>,
|
||||
#[allow(clippy::type_complexity)]
|
||||
all_canvases: RefCell<
|
||||
Vec<(
|
||||
WindowId,
|
||||
Weak<RefCell<backend::Canvas>>,
|
||||
DispatchRunner<Inner>,
|
||||
)>,
|
||||
>,
|
||||
redraw_pending: RefCell<HashSet<WindowId>>,
|
||||
destroy_pending: RefCell<VecDeque<WindowId>>,
|
||||
page_transition_event_handle: RefCell<Option<backend::PageTransitionEventHandle>>,
|
||||
|
|
@ -140,30 +149,40 @@ impl Shared {
|
|||
#[allow(clippy::disallowed_methods)]
|
||||
let document = window.document().expect("Failed to obtain document");
|
||||
|
||||
Shared(Rc::new(Execution {
|
||||
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),
|
||||
on_touch_end: RefCell::new(None),
|
||||
Shared(Rc::<Execution>::new_cyclic(|weak| {
|
||||
let proxy_spawner = WakerSpawner::new(weak.clone(), |runner, count| {
|
||||
if let Some(runner) = runner.upgrade() {
|
||||
Shared(runner).send_events(iter::repeat(Event::UserEvent(())).take(count))
|
||||
}
|
||||
})
|
||||
.expect("`EventLoop` has to be created in the main thread");
|
||||
|
||||
Execution {
|
||||
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),
|
||||
on_touch_end: RefCell::new(None),
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
|
|
@ -175,11 +194,13 @@ impl Shared {
|
|||
&self.0.document
|
||||
}
|
||||
|
||||
pub fn add_canvas(&self, id: WindowId, canvas: &Rc<RefCell<backend::Canvas>>) {
|
||||
self.0
|
||||
.all_canvases
|
||||
.borrow_mut()
|
||||
.push((id, Rc::downgrade(canvas)));
|
||||
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));
|
||||
}
|
||||
|
||||
pub fn notify_destroy_window(&self, id: WindowId) {
|
||||
|
|
@ -411,7 +432,7 @@ impl Shared {
|
|||
"visibilitychange",
|
||||
Closure::new(move |_| {
|
||||
if !runner.0.suspended.get() {
|
||||
for (id, canvas) in &*runner.0.all_canvases.borrow() {
|
||||
for (id, canvas, _) in &*runner.0.all_canvases.borrow() {
|
||||
if let Some(canvas) = canvas.upgrade() {
|
||||
let is_visible = backend::is_visible(runner.document());
|
||||
// only fire if:
|
||||
|
|
@ -549,7 +570,7 @@ impl Shared {
|
|||
self.0
|
||||
.all_canvases
|
||||
.borrow_mut()
|
||||
.retain(|&(item_id, _)| item_id != id);
|
||||
.retain(|&(item_id, _, _)| item_id != id);
|
||||
self.handle_event(Event::WindowEvent {
|
||||
window_id: id,
|
||||
event: crate::event::WindowEvent::Destroyed,
|
||||
|
|
@ -618,9 +639,29 @@ impl Shared {
|
|||
// 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
|
||||
if !is_closed && self.0.runner.borrow().maybe_runner().is_some() {
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
|
||||
// Take an event out of the queue and handle it
|
||||
// Make sure not to let the borrow_mut live during the next handle_event
|
||||
let event = { self.0.events.borrow_mut().pop_front() };
|
||||
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()
|
||||
};
|
||||
if let Some(event) = event {
|
||||
self.handle_event(event);
|
||||
}
|
||||
|
|
@ -690,7 +731,7 @@ impl Shared {
|
|||
// 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;
|
||||
for (_, canvas) in all_canvases {
|
||||
for (_, canvas, _) in all_canvases {
|
||||
// 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() {
|
||||
|
|
@ -734,23 +775,29 @@ impl Shared {
|
|||
fn device_events(&self) -> bool {
|
||||
match self.0.device_events.get() {
|
||||
DeviceEvents::Always => true,
|
||||
DeviceEvents::WhenFocused => self.0.all_canvases.borrow().iter().any(|(_, canvas)| {
|
||||
if let Some(canvas) = canvas.upgrade() {
|
||||
canvas.borrow().has_focus.load(Ordering::Relaxed)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}),
|
||||
DeviceEvents::WhenFocused => {
|
||||
self.0.all_canvases.borrow().iter().any(|(_, canvas, _)| {
|
||||
if let Some(canvas) = canvas.upgrade() {
|
||||
canvas.borrow().has_focus.get()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
}
|
||||
DeviceEvents::Never => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn transient_activation(&self) {
|
||||
self.0.all_canvases.borrow().iter().for_each(|(_, canvas)| {
|
||||
if let Some(canvas) = canvas.upgrade() {
|
||||
canvas.borrow().transient_activation();
|
||||
}
|
||||
});
|
||||
self.0
|
||||
.all_canvases
|
||||
.borrow()
|
||||
.iter()
|
||||
.for_each(|(_, canvas, _)| {
|
||||
if let Some(canvas) = canvas.upgrade() {
|
||||
canvas.borrow().transient_activation();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn event_loop_recreation(&self, allow: bool) {
|
||||
|
|
@ -780,6 +827,10 @@ impl Shared {
|
|||
pub(crate) fn poll_strategy(&self) -> PollStrategy {
|
||||
self.0.poll_strategy.get()
|
||||
}
|
||||
|
||||
pub(crate) fn waker(&self) -> Waker<Weak<Execution>> {
|
||||
self.0.proxy_spawner.waker()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) enum EventWrapper {
|
||||
|
|
|
|||
|
|
@ -3,10 +3,9 @@ use std::clone::Clone;
|
|||
use std::collections::{vec_deque::IntoIter as VecDequeIter, VecDeque};
|
||||
use std::iter;
|
||||
use std::marker::PhantomData;
|
||||
use std::rc::Rc;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::rc::{Rc, Weak};
|
||||
|
||||
use super::runner::EventWrapper;
|
||||
use super::runner::{EventWrapper, Execution};
|
||||
use super::{
|
||||
super::{monitor::MonitorHandle, KeyEventExtra},
|
||||
backend,
|
||||
|
|
@ -20,6 +19,7 @@ use crate::event::{
|
|||
use crate::event_loop::{ControlFlow, DeviceEvents};
|
||||
use crate::keyboard::ModifiersState;
|
||||
use crate::platform::web::PollStrategy;
|
||||
use crate::platform_impl::platform::r#async::Waker;
|
||||
use crate::window::{Theme, WindowId as RootWindowId};
|
||||
|
||||
#[derive(Default)]
|
||||
|
|
@ -81,7 +81,6 @@ impl<T> EventLoopWindowTarget<T> {
|
|||
id: WindowId,
|
||||
prevent_default: bool,
|
||||
) {
|
||||
self.runner.add_canvas(RootWindowId(id), canvas);
|
||||
let canvas_clone = canvas.clone();
|
||||
let mut canvas = canvas.borrow_mut();
|
||||
canvas.set_attribute("data-raw-handle", &id.0.to_string());
|
||||
|
|
@ -92,7 +91,7 @@ impl<T> EventLoopWindowTarget<T> {
|
|||
let has_focus = canvas.has_focus.clone();
|
||||
let modifiers = self.modifiers.clone();
|
||||
canvas.on_blur(move || {
|
||||
has_focus.store(false, Ordering::Relaxed);
|
||||
has_focus.set(false);
|
||||
|
||||
let clear_modifiers = (!modifiers.get().is_empty()).then(|| {
|
||||
modifiers.set(ModifiersState::empty());
|
||||
|
|
@ -115,7 +114,7 @@ impl<T> EventLoopWindowTarget<T> {
|
|||
let runner = self.runner.clone();
|
||||
let has_focus = canvas.has_focus.clone();
|
||||
canvas.on_focus(move || {
|
||||
if !has_focus.swap(true, Ordering::Relaxed) {
|
||||
if !has_focus.replace(true) {
|
||||
runner.send_event(Event::WindowEvent {
|
||||
window_id: RootWindowId(id),
|
||||
event: WindowEvent::Focused(true),
|
||||
|
|
@ -204,15 +203,13 @@ impl<T> EventLoopWindowTarget<T> {
|
|||
let modifiers = self.modifiers.clone();
|
||||
|
||||
move |active_modifiers, pointer_id| {
|
||||
let focus = (has_focus.load(Ordering::Relaxed)
|
||||
&& modifiers.get() != active_modifiers)
|
||||
.then(|| {
|
||||
modifiers.set(active_modifiers);
|
||||
Event::WindowEvent {
|
||||
window_id: RootWindowId(id),
|
||||
event: WindowEvent::ModifiersChanged(active_modifiers.into()),
|
||||
}
|
||||
});
|
||||
let focus = (has_focus.get() && modifiers.get() != active_modifiers).then(|| {
|
||||
modifiers.set(active_modifiers);
|
||||
Event::WindowEvent {
|
||||
window_id: RootWindowId(id),
|
||||
event: WindowEvent::ModifiersChanged(active_modifiers.into()),
|
||||
}
|
||||
});
|
||||
|
||||
let pointer = pointer_id.map(|pointer_id| Event::WindowEvent {
|
||||
window_id: RootWindowId(id),
|
||||
|
|
@ -233,15 +230,13 @@ impl<T> EventLoopWindowTarget<T> {
|
|||
let modifiers = self.modifiers.clone();
|
||||
|
||||
move |active_modifiers, pointer_id| {
|
||||
let focus = (has_focus.load(Ordering::Relaxed)
|
||||
&& modifiers.get() != active_modifiers)
|
||||
.then(|| {
|
||||
modifiers.set(active_modifiers);
|
||||
Event::WindowEvent {
|
||||
window_id: RootWindowId(id),
|
||||
event: WindowEvent::ModifiersChanged(active_modifiers.into()),
|
||||
}
|
||||
});
|
||||
let focus = (has_focus.get() && modifiers.get() != active_modifiers).then(|| {
|
||||
modifiers.set(active_modifiers);
|
||||
Event::WindowEvent {
|
||||
window_id: RootWindowId(id),
|
||||
event: WindowEvent::ModifiersChanged(active_modifiers.into()),
|
||||
}
|
||||
});
|
||||
|
||||
let pointer = pointer_id.map(|pointer_id| Event::WindowEvent {
|
||||
window_id: RootWindowId(id),
|
||||
|
|
@ -263,7 +258,7 @@ impl<T> EventLoopWindowTarget<T> {
|
|||
let modifiers = self.modifiers.clone();
|
||||
|
||||
move |active_modifiers| {
|
||||
if has_focus.load(Ordering::Relaxed) && modifiers.get() != active_modifiers {
|
||||
if has_focus.get() && modifiers.get() != active_modifiers {
|
||||
modifiers.set(active_modifiers);
|
||||
runner.send_event(Event::WindowEvent {
|
||||
window_id: RootWindowId(id),
|
||||
|
|
@ -278,9 +273,8 @@ impl<T> EventLoopWindowTarget<T> {
|
|||
let modifiers = self.modifiers.clone();
|
||||
|
||||
move |active_modifiers, pointer_id, events| {
|
||||
let modifiers = (has_focus.load(Ordering::Relaxed)
|
||||
&& modifiers.get() != active_modifiers)
|
||||
.then(|| {
|
||||
let modifiers =
|
||||
(has_focus.get() && modifiers.get() != active_modifiers).then(|| {
|
||||
modifiers.set(active_modifiers);
|
||||
Event::WindowEvent {
|
||||
window_id: RootWindowId(id),
|
||||
|
|
@ -307,9 +301,8 @@ impl<T> EventLoopWindowTarget<T> {
|
|||
let modifiers = self.modifiers.clone();
|
||||
|
||||
move |active_modifiers, device_id, events| {
|
||||
let modifiers = (has_focus.load(Ordering::Relaxed)
|
||||
&& modifiers.get() != active_modifiers)
|
||||
.then(|| {
|
||||
let modifiers =
|
||||
(has_focus.get() && modifiers.get() != active_modifiers).then(|| {
|
||||
modifiers.set(active_modifiers);
|
||||
Event::WindowEvent {
|
||||
window_id: RootWindowId(id),
|
||||
|
|
@ -341,9 +334,8 @@ impl<T> EventLoopWindowTarget<T> {
|
|||
position: crate::dpi::PhysicalPosition<f64>,
|
||||
buttons,
|
||||
button| {
|
||||
let modifiers = (has_focus.load(Ordering::Relaxed)
|
||||
&& modifiers.get() != active_modifiers)
|
||||
.then(|| {
|
||||
let modifiers =
|
||||
(has_focus.get() && modifiers.get() != active_modifiers).then(|| {
|
||||
modifiers.set(active_modifiers);
|
||||
Event::WindowEvent {
|
||||
window_id: RootWindowId(id),
|
||||
|
|
@ -473,7 +465,7 @@ impl<T> EventLoopWindowTarget<T> {
|
|||
let modifiers = self.modifiers.clone();
|
||||
|
||||
move |active_modifiers| {
|
||||
if has_focus.load(Ordering::Relaxed) && modifiers.get() != active_modifiers {
|
||||
if has_focus.get() && modifiers.get() != active_modifiers {
|
||||
modifiers.set(active_modifiers);
|
||||
runner.send_event(Event::WindowEvent {
|
||||
window_id: RootWindowId(id),
|
||||
|
|
@ -488,9 +480,8 @@ impl<T> EventLoopWindowTarget<T> {
|
|||
let modifiers = self.modifiers.clone();
|
||||
|
||||
move |active_modifiers, pointer_id, position, button| {
|
||||
let modifiers = (has_focus.load(Ordering::Relaxed)
|
||||
&& modifiers.get() != active_modifiers)
|
||||
.then(|| {
|
||||
let modifiers =
|
||||
(has_focus.get() && modifiers.get() != active_modifiers).then(|| {
|
||||
modifiers.set(active_modifiers);
|
||||
Event::WindowEvent {
|
||||
window_id: RootWindowId(id),
|
||||
|
|
@ -528,9 +519,8 @@ impl<T> EventLoopWindowTarget<T> {
|
|||
let modifiers = self.modifiers.clone();
|
||||
|
||||
move |active_modifiers, device_id, location, force| {
|
||||
let modifiers = (has_focus.load(Ordering::Relaxed)
|
||||
&& modifiers.get() != active_modifiers)
|
||||
.then(|| {
|
||||
let modifiers =
|
||||
(has_focus.get() && modifiers.get() != active_modifiers).then(|| {
|
||||
modifiers.set(active_modifiers);
|
||||
Event::WindowEvent {
|
||||
window_id: RootWindowId(id),
|
||||
|
|
@ -558,8 +548,7 @@ impl<T> EventLoopWindowTarget<T> {
|
|||
let modifiers = self.modifiers.clone();
|
||||
canvas.on_mouse_wheel(
|
||||
move |pointer_id, delta, active_modifiers| {
|
||||
let modifiers_changed = (has_focus.load(Ordering::Relaxed)
|
||||
&& modifiers.get() != active_modifiers)
|
||||
let modifiers_changed = (has_focus.get() && modifiers.get() != active_modifiers)
|
||||
.then(|| {
|
||||
modifiers.set(active_modifiers);
|
||||
Event::WindowEvent {
|
||||
|
|
@ -713,4 +702,8 @@ impl<T> EventLoopWindowTarget<T> {
|
|||
pub(crate) fn poll_strategy(&self) -> PollStrategy {
|
||||
self.runner.poll_strategy()
|
||||
}
|
||||
|
||||
pub(crate) fn waker(&self) -> Waker<Weak<Execution>> {
|
||||
self.runner.waker()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue