diff options
author | 2024-06-19 19:03:07 +0200 | |
---|---|---|
committer | 2024-06-19 19:07:07 +0200 | |
commit | 65c8e08b440f012e4a26cb55ff5554cd36fde614 (patch) | |
tree | 9556731f4ebf702b7f012c6efe349a1a22e74b97 /winit | |
parent | 5f259434497fcc3b39d377181c05fe78f566d475 (diff) | |
download | iced-65c8e08b440f012e4a26cb55ff5554cd36fde614.tar.gz iced-65c8e08b440f012e4a26cb55ff5554cd36fde614.tar.bz2 iced-65c8e08b440f012e4a26cb55ff5554cd36fde614.zip |
Fix initialization race conditions in WebAssembly
WebGL is still broken, but oh well... Time to move on.
Diffstat (limited to 'winit')
-rw-r--r-- | winit/src/program.rs | 100 |
1 files changed, 42 insertions, 58 deletions
diff --git a/winit/src/program.rs b/winit/src/program.rs index 8e3563f7..62f8b6af 100644 --- a/winit/src/program.rs +++ b/winit/src/program.rs @@ -200,20 +200,22 @@ where Runtime::new(executor, proxy.clone()) }; - let (application, task) = runtime.enter(|| P::new(flags)); + let (program, task) = runtime.enter(|| P::new(flags)); if let Some(stream) = task.into_stream() { runtime.run(stream); } + runtime.track(program.subscription().map(Action::Output).into_recipes()); + let (boot_sender, boot_receiver) = oneshot::channel(); let (event_sender, event_receiver) = mpsc::unbounded(); let (control_sender, control_receiver) = mpsc::unbounded(); let instance = Box::pin(run_instance::<P, C>( - application, + program, runtime, - proxy, + proxy.clone(), debug, boot_receiver, event_receiver, @@ -226,18 +228,19 @@ where instance: std::pin::Pin<Box<F>>, context: task::Context<'static>, id: Option<String>, - boot: Option<BootConfig<C>>, - sender: mpsc::UnboundedSender<Event<Message>>, + boot: Option<BootConfig<Message, C>>, + sender: mpsc::UnboundedSender<Event<Action<Message>>>, receiver: mpsc::UnboundedReceiver<Control>, error: Option<Error>, #[cfg(target_arch = "wasm32")] is_booted: std::rc::Rc<std::cell::RefCell<bool>>, #[cfg(target_arch = "wasm32")] - queued_events: Vec<Event<Message>>, + queued_events: Vec<Event<Action<Message>>>, } - struct BootConfig<C> { + struct BootConfig<Message: 'static, C> { + proxy: Proxy<Message>, sender: oneshot::Sender<Boot<C>>, window_settings: Option<window::Settings>, graphics_settings: graphics::Settings, @@ -248,6 +251,7 @@ where context, id: settings.id, boot: Some(BootConfig { + proxy, sender: boot_sender, window_settings, graphics_settings, @@ -262,14 +266,16 @@ where queued_events: Vec::new(), }; - impl<Message, F, C> winit::application::ApplicationHandler<Message> + impl<Message, F, C> winit::application::ApplicationHandler<Action<Message>> for Runner<Message, F, C> where + Message: std::fmt::Debug, F: Future<Output = ()>, C: Compositor + 'static, { fn resumed(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) { let Some(BootConfig { + mut proxy, sender, window_settings, graphics_settings, @@ -299,11 +305,23 @@ where .send(Boot { compositor, clipboard, - window_settings, + is_daemon: window_settings.is_none(), }) .ok() .expect("Send boot event"); + if let Some(window_settings) = window_settings { + let (sender, _receiver) = oneshot::channel(); + + proxy.send_action(Action::Window( + runtime::window::Action::Open( + window::Id::unique(), + window_settings, + sender, + ), + )); + } + Ok::<_, graphics::Error>(()) }; @@ -383,12 +401,12 @@ where fn user_event( &mut self, event_loop: &winit::event_loop::ActiveEventLoop, - message: Message, + action: Action<Message>, ) { self.process_event( event_loop, Event::EventLoopAwakened(winit::event::Event::UserEvent( - message, + action, )), ); } @@ -412,7 +430,7 @@ where fn process_event( &mut self, event_loop: &winit::event_loop::ActiveEventLoop, - event: Event<Message>, + event: Event<Action<Message>>, ) { #[cfg(target_arch = "wasm32")] if !*self.is_booted.borrow() { @@ -574,7 +592,7 @@ where struct Boot<C> { compositor: C, clipboard: Clipboard, - window_settings: Option<window::Settings>, + is_daemon: bool, } enum Event<Message: 'static> { @@ -616,7 +634,7 @@ async fn run_instance<P, C>( let Boot { mut compositor, mut clipboard, - window_settings, + is_daemon, } = boot.try_recv().ok().flatten().expect("Receive boot"); let mut window_manager = WindowManager::new(); @@ -626,29 +644,7 @@ async fn run_instance<P, C>( let mut actions = 0; let mut ui_caches = FxHashMap::default(); - let mut user_interfaces = ManuallyDrop::new(build_user_interfaces( - &program, - &mut debug, - &mut window_manager, - FxHashMap::from_iter([( - window::Id::MAIN, - user_interface::Cache::default(), - )]), - )); - - runtime.track(program.subscription().map(Action::Output).into_recipes()); - - let is_daemon = window_settings.is_none(); - - if let Some(window_settings) = window_settings { - let (sender, _receiver) = oneshot::channel(); - - proxy.send_action(Action::Window(runtime::window::Action::Open( - window::Id::unique(), - window_settings, - sender, - ))); - } + let mut user_interfaces = ManuallyDrop::new(FxHashMap::default()); debug.startup_finished(); @@ -697,8 +693,6 @@ async fn run_instance<P, C>( | event::StartCause::ResumeTimeReached { .. }, ) => { for (_id, window) in window_manager.iter_mut() { - // TODO once widgets can request to be redrawn, we can avoid always requesting a - // redraw window.raw.request_redraw(); } } @@ -878,9 +872,6 @@ async fn run_instance<P, C>( ) { Ok(()) => { debug.render_finished(); - - // TODO: Handle animations! - // Maybe we can use `ControlFlow::WaitUntil` for this. } Err(error) => match error { // This is an unrecoverable error. @@ -1024,7 +1015,6 @@ async fn run_instance<P, C>( debug.event_processing_finished(); - // TODO mw application update returns which window IDs to update if !messages.is_empty() || uis_stale { let cached_interfaces: FxHashMap< window::Id, @@ -1034,7 +1024,6 @@ async fn run_instance<P, C>( .map(|(id, ui)| (id, ui.into_cache())) .collect(); - // Update application update( &mut program, &mut runtime, @@ -1042,8 +1031,6 @@ async fn run_instance<P, C>( &mut messages, ); - // we must synchronize all window states with application state after an - // application update since we don't know what changed for (id, window) in window_manager.iter_mut() { window.state.synchronize( &program, @@ -1051,12 +1038,9 @@ async fn run_instance<P, C>( &window.raw, ); - // TODO once widgets can request to be redrawn, we can avoid always requesting a - // redraw window.raw.request_redraw(); } - // rebuild UIs with the synchronized states user_interfaces = ManuallyDrop::new(build_user_interfaces( &program, @@ -1082,7 +1066,7 @@ async fn run_instance<P, C>( /// Builds a window's [`UserInterface`] for the [`Program`]. fn build_user_interface<'a, P: Program>( - application: &'a P, + program: &'a P, cache: user_interface::Cache, renderer: &mut P::Renderer, size: Size, @@ -1093,7 +1077,7 @@ where P::Theme: DefaultStyle, { debug.view_started(); - let view = application.view(id); + let view = program.view(id); debug.view_finished(); debug.layout_started(); @@ -1104,7 +1088,7 @@ where } fn update<P: Program, E: Executor>( - application: &mut P, + program: &mut P, runtime: &mut Runtime<E, Proxy<P::Message>, Action<P::Message>>, debug: &mut Debug, messages: &mut Vec<P::Message>, @@ -1115,7 +1099,7 @@ fn update<P: Program, E: Executor>( debug.log_message(&message); debug.update_started(); - let task = runtime.enter(|| application.update(message)); + let task = runtime.enter(|| program.update(message)); debug.update_finished(); if let Some(stream) = task.into_stream() { @@ -1123,13 +1107,13 @@ fn update<P: Program, E: Executor>( } } - let subscription = application.subscription(); + let subscription = program.subscription(); runtime.track(subscription.map(Action::Output).into_recipes()); } fn run_action<P, C>( action: Action<P::Message>, - application: &P, + program: &P, compositor: &mut C, messages: &mut Vec<P::Message>, clipboard: &mut Clipboard, @@ -1170,7 +1154,7 @@ fn run_action<P, C>( .start_send(Control::CreateWindow { id, settings, - title: application.title(id), + title: program.title(id), monitor, }) .expect("Send control action"); @@ -1403,7 +1387,7 @@ fn run_action<P, C>( /// Build the user interface for every window. pub fn build_user_interfaces<'a, P: Program, C>( - application: &'a P, + program: &'a P, debug: &mut Debug, window_manager: &mut WindowManager<P, C>, mut cached_user_interfaces: FxHashMap<window::Id, user_interface::Cache>, @@ -1420,7 +1404,7 @@ where Some(( id, build_user_interface( - application, + program, cache, &mut window.renderer, window.state.logical_size(), |