Repository: iced-rs/iced (language: rust)

Issue:
Windows need to be created in the winit event loop after receiving `Resumed`.
### Is there an existing issue for this?

- [X] I have searched the existing issues.

### Is this issue related to iced?

- [X] My hardware is compatible and my graphics drivers are up-to-date.

### What happened?

This will be a hard error in the future of winit, but with the newer version you must create the window objects inside the event loop after receiving `Resumed`. Not doing so will cause issues with various macOS platform features, fullscreen, wgpu bugs, etc.

Other platforms will send `Resumed` to emulate the behavior.

### What is the expected behavior?

Iced creates the windows properly.

### Version

master

### Operating System

macOS

### Do you have any log output?

```shell
N/A
```



Discussion / hints:
Recently merged: https://github.com/rust-windowing/winit/pull/3447

Fix patch:
diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml
index ceac39e7a9..8f5e65d628 100644
--- a/.github/workflows/check.yml
+++ b/.github/workflows/check.yml
@@ -17,8 +17,6 @@ jobs:
       run: cargo build --package tour --target wasm32-unknown-unknown
     - name: Check compilation of `todos` example
       run: cargo build --package todos --target wasm32-unknown-unknown
-    - name: Check compilation of `integration` example
-      run: cargo build --package integration --target wasm32-unknown-unknown
 
   widget:
     runs-on: ubuntu-latest
diff --git a/Cargo.toml b/Cargo.toml
index 60773da01d..06f7d19858 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -172,11 +172,11 @@ unicode-segmentation = "1.0"
 wasm-bindgen-futures = "0.4"
 wasm-timer = "0.2"
 web-sys = "=0.3.67"
-web-time = "0.2"
+web-time = "1.1"
 wgpu = "0.19"
 winapi = "0.3"
 window_clipboard = "0.4.1"
-winit = { git = "https://github.com/iced-rs/winit.git", rev = "592bd152f6d5786fae7d918532d7db752c0d164f" }
+winit = { git = "https://github.com/iced-rs/winit.git", rev = "8affa522bc6dcc497d332a28c03491d22a22f5a7" }
 
 [workspace.lints.rust]
 rust_2018_idioms = "forbid"
diff --git a/examples/integration/README.md b/examples/integration/README.md
index aa3a6e94ad..bac0640cd5 100644
--- a/examples/integration/README.md
+++ b/examples/integration/README.md
@@ -10,25 +10,8 @@ The __[`main`]__ file contains all the code of the example.
 
 You can run it with `cargo run`:
 ```
-cargo run --package integration_wgpu
+cargo run --package integration
 ```
 
-### How to run this example with WebGL backend
-NOTE: Currently, WebGL backend is still experimental, so expect bugs.
-
-```sh
-# 0. Install prerequisites
-cargo install wasm-bindgen-cli https
-# 1. cd to the current folder
-# 2. Compile wasm module
-cargo build -p integration_wgpu --target wasm32-unknown-unknown
-# 3. Invoke wasm-bindgen
-wasm-bindgen ../../target/wasm32-unknown-unknown/debug/integration_wgpu.wasm --out-dir . --target web --no-typescript
-# 4. run http server
-http
-# 5. Open 127.0.0.1:8000 in browser
-```
-
-
 [`main`]: src/main.rs
 [`wgpu`]: https://github.com/gfx-rs/wgpu
diff --git a/examples/integration/index.html b/examples/integration/index.html
deleted file mode 100644
index 920bc4a063..0000000000
--- a/examples/integration/index.html
+++ /dev/null
@@ -1,21 +0,0 @@
-<!DOCTYPE html>
-<html>
-  <head>
-    <meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
-    <title>Iced - wgpu + WebGL integration</title>
-  </head>
-  <body>
-    <h1>integration_wgpu</h1>
-    <canvas id="iced_canvas"></canvas>
-    <script type="module">
-      import init from "./integration.js";
-      init('./integration_bg.wasm');
-    </script>
-    <style>
-      body {
-        width: 100%;
-        text-align: center;
-      }
-    </style>
-  </body>
-</html>
diff --git a/examples/integration/src/main.rs b/examples/integration/src/main.rs
index c28332100d..e1c7d62fbc 100644
--- a/examples/integration/src/main.rs
+++ b/examples/integration/src/main.rs
@@ -18,305 +18,342 @@ use iced_winit::winit;
 use iced_winit::Clipboard;
 
 use winit::{
-    event::{Event, WindowEvent},
+    event::WindowEvent,
     event_loop::{ControlFlow, EventLoop},
     keyboard::ModifiersState,
 };
 
 use std::sync::Arc;
 
-#[cfg(target_arch = "wasm32")]
-use wasm_bindgen::JsCast;
-#[cfg(target_arch = "wasm32")]
-use web_sys::HtmlCanvasElement;
-#[cfg(target_arch = "wasm32")]
-use winit::platform::web::WindowBuilderExtWebSys;
-
-pub fn main() -> Result<(), Box<dyn std::error::Error>> {
-    #[cfg(target_arch = "wasm32")]
-    let canvas_element = {
-        console_log::init().expect("Initialize logger");
-
-        std::panic::set_hook(Box::new(console_error_panic_hook::hook));
-
-        web_sys::window()
-            .and_then(|win| win.document())
-            .and_then(|doc| doc.get_element_by_id("iced_canvas"))
-            .and_then(|element| element.dyn_into::<HtmlCanvasElement>().ok())
-            .expect("Get canvas element")
-    };
-
-    #[cfg(not(target_arch = "wasm32"))]
+pub fn main() -> Result<(), winit::error::EventLoopError> {
     tracing_subscriber::fmt::init();
 
     // Initialize winit
     let event_loop = EventLoop::new()?;
 
-    #[cfg(target_arch = "wasm32")]
-    let window = winit::window::WindowBuilder::new()
-        .with_canvas(Some(canvas_element))
-        .build(&event_loop)?;
-
-    #[cfg(not(target_arch = "wasm32"))]
-    let window = winit::window::Window::new(&event_loop)?;
-
-    let window = Arc::new(window);
-
-    let physical_size = window.inner_size();
-    let mut viewport = Viewport::with_physical_size(
-        Size::new(physical_size.width, physical_size.height),
-        window.scale_factor(),
-    );
-    let mut cursor_position = None;
-    let mut modifiers = ModifiersState::default();
-    let mut clipboard = Clipboard::connect(&window);
-
-    // Initialize wgpu
-    #[cfg(target_arch = "wasm32")]
-    let default_backend = wgpu::Backends::GL;
-    #[cfg(not(target_arch = "wasm32"))]
-    let default_backend = wgpu::Backends::PRIMARY;
-
-    let backend =
-        wgpu::util::backend_bits_from_env().unwrap_or(default_backend);
-
-    let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
-        backends: backend,
-        ..Default::default()
-    });
-    let surface = instance.create_surface(window.clone())?;
-
-    let (format, adapter, device, queue) =
-        futures::futures::executor::block_on(async {
-            let adapter = wgpu::util::initialize_adapter_from_env_or_default(
-                &instance,
-                Some(&surface),
-            )
-            .await
-            .expect("Create adapter");
-
-            let adapter_features = adapter.features();
-
-            #[cfg(target_arch = "wasm32")]
-            let needed_limits = wgpu::Limits::downlevel_webgl2_defaults()
-                .using_resolution(adapter.limits());
-
-            #[cfg(not(target_arch = "wasm32"))]
-            let needed_limits = wgpu::Limits::default();
-
-            let capabilities = surface.get_capabilities(&adapter);
-
-            let (device, queue) = adapter
-                .request_device(
-                    &wgpu::DeviceDescriptor {
-                        label: None,
-                        required_features: adapter_features
-                            & wgpu::Features::default(),
-                        required_limits: needed_limits,
+    #[allow(clippy::large_enum_variant)]
+    enum Runner {
+        Loading,
+        Ready {
+            window: Arc<winit::window::Window>,
+            device: wgpu::Device,
+            queue: wgpu::Queue,
+            surface: wgpu::Surface<'static>,
+            format: wgpu::TextureFormat,
+            engine: Engine,
+            renderer: Renderer,
+            scene: Scene,
+            state: program::State<Controls>,
+            cursor_position: Option<winit::dpi::PhysicalPosition<f64>>,
+            clipboard: Clipboard,
+            viewport: Viewport,
+            modifiers: ModifiersState,
+            resized: bool,
+            debug: Debug,
+        },
+    }
+
+    impl winit::application::ApplicationHandler for Runner {
+        fn resumed(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) {
+            if let Self::Loading = self {
+                let window = Arc::new(
+                    event_loop
+                        .create_window(
+                            winit::window::WindowAttributes::default(),
+                        )
+                        .expect("Create window"),
+                );
+
+                let physical_size = window.inner_size();
+                let viewport = Viewport::with_physical_size(
+                    Size::new(physical_size.width, physical_size.height),
+                    window.scale_factor(),
+                );
+                let clipboard = Clipboard::connect(&window);
+
+                let backend =
+                    wgpu::util::backend_bits_from_env().unwrap_or_default();
+
+                let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
+                    backends: backend,
+                    ..Default::default()
+                });
+                let surface = instance
+                    .create_surface(window.clone())
+                    .expect("Create window surface");
+
+                let (format, adapter, device, queue) =
+                    futures::futures::executor::block_on(async {
+                        let adapter =
+                            wgpu::util::initialize_adapter_from_env_or_default(
+                                &instance,
+                                Some(&surface),
+                            )
+                            .await
+                            .expect("Create adapter");
+
+                        let adapter_features = adapter.features();
+
+                        let capabilities = surface.get_capabilities(&adapter);
+
+                        let (device, queue) = adapter
+                            .request_device(
+                                &wgpu::DeviceDescriptor {
+                                    label: None,
+                                    required_features: adapter_features
+                                        & wgpu::Features::default(),
+                                    required_limits: wgpu::Limits::default(),
+                                },
+                                None,
+                            )
+                            .await
+                            .expect("Request device");
+
+                        (
+                            capabilities
+                                .formats
+                                .iter()
+                                .copied()
+                                .find(wgpu::TextureFormat::is_srgb)
+                                .or_else(|| {
+                                    capabilities.formats.first().copied()
+                                })
+                                .expect("Get preferred format"),
+                            adapter,
+                            device,
+                            queue,
+                        )
+                    });
+
+                surface.configure(
+                    &device,
+                    &wgpu::SurfaceConfiguration {
+                        usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
+                        format,
+                        width: physical_size.width,
+                        height: physical_size.height,
+                        present_mode: wgpu::PresentMode::AutoVsync,
+                        alpha_mode: wgpu::CompositeAlphaMode::Auto,
+                        view_formats: vec![],
+                        desired_maximum_frame_latency: 2,
                     },
-                    None,
-                )
-                .await
-                .expect("Request device");
-
-            (
-                capabilities
-                    .formats
-                    .iter()
-                    .copied()
-                    .find(wgpu::TextureFormat::is_srgb)
-                    .or_else(|| capabilities.formats.first().copied())
-                    .expect("Get preferred format"),
-                adapter,
+                );
+
+                // Initialize scene and GUI controls
+                let scene = Scene::new(&device, format);
+                let controls = Controls::new();
+
+                // Initialize iced
+                let mut debug = Debug::new();
+                let engine =
+                    Engine::new(&adapter, &device, &queue, format, None);
+                let mut renderer = Renderer::new(
+                    &device,
+                    &engine,
+                    Font::default(),
+                    Pixels::from(16),
+                );
+
+                let state = program::State::new(
+                    controls,
+                    viewport.logical_size(),
+                    &mut renderer,
+                    &mut debug,
+                );
+
+                // You should change this if you want to render continuously
+                event_loop.set_control_flow(ControlFlow::Wait);
+
+                *self = Self::Ready {
+                    window,
+                    device,
+                    queue,
+                    surface,
+                    format,
+                    engine,
+                    renderer,
+                    scene,
+                    state,
+                    cursor_position: None,
+                    modifiers: ModifiersState::default(),
+                    clipboard,
+                    viewport,
+                    resized: false,
+                    debug,
+                };
+            }
+        }
+
+        fn window_event(
+            &mut self,
+            event_loop: &winit::event_loop::ActiveEventLoop,
+            _window_id: winit::window::WindowId,
+            event: WindowEvent,
+        ) {
+            let Self::Ready {
+                window,
                 device,
                 queue,
-            )
-        });
-
-    surface.configure(
-        &device,
-        &wgpu::SurfaceConfiguration {
-            usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
-            format,
-            width: physical_size.width,
-            height: physical_size.height,
-            present_mode: wgpu::PresentMode::AutoVsync,
-            alpha_mode: wgpu::CompositeAlphaMode::Auto,
-            view_formats: vec![],
-            desired_maximum_frame_latency: 2,
-        },
-    );
-
-    let mut resized = false;
-
-    // Initialize scene and GUI controls
-    let scene = Scene::new(&device, format);
-    let controls = Controls::new();
-
-    // Initialize iced
-    let mut debug = Debug::new();
-    let mut engine = Engine::new(&adapter, &device, &queue, format, None);
-    let mut renderer =
-        Renderer::new(&device, &engine, Font::default(), Pixels::from(16));
-
-    let mut state = program::State::new(
-        controls,
-        viewport.logical_size(),
-        &mut renderer,
-        &mut debug,
-    );
-
-    // Run event loop
-    event_loop.run(move |event, window_target| {
-        // You should change this if you want to render continuously
-        window_target.set_control_flow(ControlFlow::Wait);
-
-        match event {
-            Event::WindowEvent {
-                event: WindowEvent::RedrawRequested,
-                ..
-            } => {
-                if resized {
-                    let size = window.inner_size();
-
-                    viewport = Viewport::with_physical_size(
-                        Size::new(size.width, size.height),
-                        window.scale_factor(),
-                    );
-
-                    surface.configure(
-                        &device,
-                        &wgpu::SurfaceConfiguration {
-                            format,
-                            usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
-                            width: size.width,
-                            height: size.height,
-                            present_mode: wgpu::PresentMode::AutoVsync,
-                            alpha_mode: wgpu::CompositeAlphaMode::Auto,
-                            view_formats: vec![],
-                            desired_maximum_frame_latency: 2,
-                        },
-                    );
-
-                    resized = false;
-                }
-
-                match surface.get_current_texture() {
-                    Ok(frame) => {
-                        let mut encoder = device.create_command_encoder(
-                            &wgpu::CommandEncoderDescriptor { label: None },
+                surface,
+                format,
+                engine,
+                renderer,
+                scene,
+                state,
+                viewport,
+                cursor_position,
+                modifiers,
+                clipboard,
+                resized,
+                debug,
+            } = self
+            else {
+                return;
+            };
+
+            match event {
+                WindowEvent::RedrawRequested => {
+                    if *resized {
+                        let size = window.inner_size();
+
+                        *viewport = Viewport::with_physical_size(
+                            Size::new(size.width, size.height),
+                            window.scale_factor(),
                         );
 
-                        let program = state.program();
-
-                        let view = frame.texture.create_view(
-                            &wgpu::TextureViewDescriptor::default(),
+                        surface.configure(
+                            device,
+                            &wgpu::SurfaceConfiguration {
+                                format: *format,
+                                usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
+                                width: size.width,
+                                height: size.height,
+                                present_mode: wgpu::PresentMode::AutoVsync,
+                                alpha_mode: wgpu::CompositeAlphaMode::Auto,
+                                view_formats: vec![],
+                                desired_maximum_frame_latency: 2,
+                            },
                         );
 
-                        {
-                            // We clear the frame
-                            let mut render_pass = Scene::clear(
-                                &view,
-                                &mut encoder,
-                                program.background_color(),
+                        *resized = false;
+                    }
+
+                    match surface.get_current_texture() {
+                        Ok(frame) => {
+                            let mut encoder = device.create_command_encoder(
+                                &wgpu::CommandEncoderDescriptor { label: None },
                             );
 
-                            // Draw the scene
-                            scene.draw(&mut render_pass);
-                        }
+                            let program = state.program();
 
-                        // And then iced on top
-                        renderer.present(
-                            &mut engine,
-                            &device,
-                            &queue,
-                            &mut encoder,
-                            None,
-                            frame.texture.format(),
-                            &view,
-                            &viewport,
-                            &debug.overlay(),
-                        );
+                            let view = frame.texture.create_view(
+                                &wgpu::TextureViewDescriptor::default(),
+                            );
+
+                            {
+                                // We clear the frame
+                                let mut render_pass = Scene::clear(
+                                    &view,
+                                    &mut encoder,
+                                    program.background_color(),
+                                );
+
+                                // Draw the scene
+                                scene.draw(&mut render_pass);
+                            }
+
+                            // And then iced on top
+                            renderer.present(
+                                engine,
+                                device,
+                                queue,
+                                &mut encoder,
+                                None,
+                                frame.texture.format(),
+                                &view,
+                                viewport,
+                                &debug.overlay(),
+                            );
 
-                        // Then we submit the work
-                        queue.submit(Some(encoder.finish()));
-                        frame.present();
+                            // Then we submit the work
+                            engine.submit(queue, encoder);
+                            frame.present();
 
-                        // Update the mouse cursor
-                        window.set_cursor_icon(
-                            iced_winit::conversion::mouse_interaction(
-                                state.mouse_interaction(),
-                            ),
-                        );
-                    }
-                    Err(error) => match error {
-                        wgpu::SurfaceError::OutOfMemory => {
-                            panic!(
-                                "Swapchain error: {error}. \
-                                Rendering cannot continue."
-                            )
-                        }
-                        _ => {
-                            // Try rendering again next frame.
-                            window.request_redraw();
+                            // Update the mouse cursor
+                            window.set_cursor(
+                                iced_winit::conversion::mouse_interaction(
+                                    state.mouse_interaction(),
+                                ),
+                            );
                         }
-                    },
-                }
-            }
-            Event::WindowEvent { event, .. } => {
-                match event {
-                    WindowEvent::CursorMoved { position, .. } => {
-                        cursor_position = Some(position);
-                    }
-                    WindowEvent::ModifiersChanged(new_modifiers) => {
-                        modifiers = new_modifiers.state();
-                    }
-                    WindowEvent::Resized(_) => {
-                        resized = true;
-                    }
-                    WindowEvent::CloseRequested => {
-                        window_target.exit();
+                        Err(error) => match error {
+                            wgpu::SurfaceError::OutOfMemory => {
+                                panic!(
+                                    "Swapchain error: {error}. \
+                                Rendering cannot continue."
+                                )
+                            }
+                            _ => {
+                                // Try rendering again next frame.
+                                window.request_redraw();
+                            }
+                        },
                     }
-                    _ => {}
                 }
-
-                // Map window event to iced event
-                if let Some(event) = iced_winit::conversion::window_event(
-                    window::Id::MAIN,
-                    event,
-                    window.scale_factor(),
-                    modifiers,
-                ) {
-                    state.queue_event(event);
+                WindowEvent::CursorMoved { position, .. } => {
+                    *cursor_position = Some(position);
+                }
+                WindowEvent::ModifiersChanged(new_modifiers) => {
+                    *modifiers = new_modifiers.state();
                 }
+                WindowEvent::Resized(_) => {
+                    *resized = true;
+                }
+                WindowEvent::CloseRequested => {
+                    event_loop.exit();
+                }
+                _ => {}
             }
-            _ => {}
-        }
 
-        // If there are events pending
-        if !state.is_queue_empty() {
-            // We update iced
-            let _ = state.update(
-                viewport.logical_size(),
-                cursor_position
-                    .map(|p| {
-                        conversion::cursor_position(p, viewport.scale_factor())
-                    })
-                    .map(mouse::Cursor::Available)
-                    .unwrap_or(mouse::Cursor::Unavailable),
-                &mut renderer,
-                &Theme::Dark,
-                &renderer::Style {
-                    text_color: Color::WHITE,
-                },
-                &mut clipboard,
-                &mut debug,
-            );
-
-            // and request a redraw
-            window.request_redraw();
+            // Map window event to iced event
+            if let Some(event) = iced_winit::conversion::window_event(
+                window::Id::MAIN,
+                event,
+                window.scale_factor(),
+                *modifiers,
+            ) {
+                state.queue_event(event);
+            }
+
+            // If there are events pending
+            if !state.is_queue_empty() {
+                // We update iced
+                let _ = state.update(
+                    viewport.logical_size(),
+                    cursor_position
+                        .map(|p| {
+                            conversion::cursor_position(
+                                p,
+                                viewport.scale_factor(),
+                            )
+                        })
+                        .map(mouse::Cursor::Available)
+                        .unwrap_or(mouse::Cursor::Unavailable),
+                    renderer,
+                    &Theme::Dark,
+                    &renderer::Style {
+                        text_color: Color::WHITE,
+                    },
+                    clipboard,
+                    debug,
+                );
+
+                // and request a redraw
+                window.request_redraw();
+            }
         }
-    })?;
+    }
 
-    Ok(())
+    let mut runner = Runner::Loading;
+    event_loop.run_app(&mut runner)
 }
diff --git a/src/application.rs b/src/application.rs
index 9197834b23..d12ba73dcc 100644
--- a/src/application.rs
+++ b/src/application.rs
@@ -212,26 +212,11 @@ where
             ..crate::graphics::Settings::default()
         };
 
-        let run = crate::shell::application::run::<
+        Ok(crate::shell::application::run::<
             Instance<Self>,
             Self::Executor,
             <Self::Renderer as compositor::Default>::Compositor,
-        >(settings.into(), renderer_settings);
-
-        #[cfg(target_arch = "wasm32")]
-        {
-            use crate::futures::FutureExt;
-            use iced_futures::backend::wasm::wasm_bindgen::Executor;
-
-            Executor::new()
-                .expect("Create Wasm executor")
-                .spawn(run.map(|_| ()));
-
-            Ok(())
-        }
-
-        #[cfg(not(target_arch = "wasm32"))]
-        Ok(crate::futures::executor::block_on(run)?)
+        >(settings.into(), renderer_settings)?)
     }
 }
 
diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs
index ad8ac59195..1fbdbe9a3d 100644
--- a/wgpu/src/lib.rs
+++ b/wgpu/src/lib.rs
@@ -67,8 +67,6 @@ use crate::core::{
 use crate::graphics::text::{Editor, Paragraph};
 use crate::graphics::Viewport;
 
-use std::cell::RefCell;
-
 /// A [`wgpu`] graphics renderer for [`iced`].
 ///
 /// [`wgpu`]: https://github.com/gfx-rs/wgpu-rs
@@ -84,7 +82,7 @@ pub struct Renderer {
 
     // TODO: Centralize all the image feature handling
     #[cfg(any(feature = "svg", feature = "image"))]
-    image_cache: RefCell<image::Cache>,
+    image_cache: std::cell::RefCell<image::Cache>,
 }
 
 impl Renderer {
@@ -103,7 +101,9 @@ impl Renderer {
             text_storage: text::Storage::new(),
 
             #[cfg(any(feature = "svg", feature = "image"))]
-            image_cache: RefCell::new(_engine.create_image_cache(_device)),
+            image_cache: std::cell::RefCell::new(
+                _engine.create_image_cache(_device),
+            ),
         }
     }
 
diff --git a/winit/Cargo.toml b/winit/Cargo.toml
index dccb7c07f0..6d3dddde8e 100644
--- a/winit/Cargo.toml
+++ b/winit/Cargo.toml
@@ -25,6 +25,7 @@ wayland-csd-adwaita = ["winit/wayland-csd-adwaita"]
 multi-window = ["iced_runtime/multi-window"]
 
 [dependencies]
+iced_futures.workspace = true
 iced_graphics.workspace = true
 iced_runtime.workspace = true
 
@@ -32,6 +33,7 @@ log.workspace = true
 rustc-hash.workspace = true
 thiserror.workspace = true
 tracing.workspace = true
+wasm-bindgen-futures.workspace = true
 window_clipboard.workspace = true
 winit.workspace = true
 
diff --git a/winit/src/application.rs b/winit/src/application.rs
index a447c9da05..3bc292552c 100644
--- a/winit/src/application.rs
+++ b/winit/src/application.rs
@@ -22,7 +22,9 @@ use crate::runtime::{Command, Debug};
 use crate::{Clipboard, Error, Proxy, Settings};
 
 use futures::channel::mpsc;
+use futures::channel::oneshot;
 
+use std::borrow::Cow;
 use std::mem::ManuallyDrop;
 use std::sync::Arc;
 
@@ -129,7 +131,7 @@ pub fn default(theme: &Theme) -> Appearance {
 
 /// Runs an [`Application`] with an executor, compositor, and the provided
 /// settings.
-pub async fn run<A, E, C>(
+pub fn run<A, E, C>(
     settings: Settings<A::Flags>,
     graphics_settings: graphics::Settings,
 ) -> Result<(), Error>
@@ -141,12 +143,12 @@ where
 {
     use futures::task;
     use futures::Future;
-    use winit::event_loop::EventLoopBuilder;
+    use winit::event_loop::EventLoop;
 
     let mut debug = Debug::new();
     debug.startup_started();
 
-    let event_loop = EventLoopBuilder::with_user_event()
+    let event_loop = EventLoop::with_user_event()
         .build()
         .expect("Create event loop");
 
@@ -165,102 +167,282 @@ where
         runtime.enter(|| A::new(flags))
     };
 
-    #[cfg(target_arch = "wasm32")]
-    let target = settings.window.platform_specific.target.clone();
+    let id = settings.id;
+    let title = application.title();
 
-    let should_be_visible = settings.window.visible;
-    let exit_on_close_request = settings.window.exit_on_close_request;
+    let (boot_sender, boot_receiver) = oneshot::channel();
+    let (event_sender, event_receiver) = mpsc::unbounded();
+    let (control_sender, control_receiver) = mpsc::unbounded();
 
-    let builder = conversion::window_settings(
-        settings.window,
-        &application.title(),
-        event_loop.primary_monitor(),
-        settings.id,
-    )
-    .with_visible(false);
+    let instance = Box::pin(run_instance::<A, E, C>(
+        application,
+        runtime,
+        proxy,
+        debug,
+        boot_receiver,
+        event_receiver,
+        control_sender,
+        init_command,
+        settings.fonts,
+    ));
 
-    log::debug!("Window builder: {builder:#?}");
+    let context = task::Context::from_waker(task::noop_waker_ref());
+
+    struct Runner<Message: 'static, F, C> {
+        instance: std::pin::Pin<Box<F>>,
+        context: task::Context<'static>,
+        boot: Option<BootConfig<C>>,
+        sender: mpsc::UnboundedSender<winit::event::Event<Message>>,
+        receiver: mpsc::UnboundedReceiver<winit::event_loop::ControlFlow>,
+        error: Option<Error>,
+        #[cfg(target_arch = "wasm32")]
+        is_booted: std::rc::Rc<std::cell::RefCell<bool>>,
+        #[cfg(target_arch = "wasm32")]
+        queued_events: Vec<winit::event::Event<Message>>,
+    }
 
-    let window = Arc::new(
-        builder
-            .build(&event_loop)
-            .map_err(Error::WindowCreationFailed)?,
-    );
+    struct BootConfig<C> {
+        sender: oneshot::Sender<Boot<C>>,
+        id: Option<String>,
+        title: String,
+        window_settings: window::Settings,
+        graphics_settings: graphics::Settings,
+    }
 
-    #[cfg(target_arch = "wasm32")]
+    let runner = Runner {
+        instance,
+        context,
+        boot: Some(BootConfig {
+            sender: boot_sender,
+            id,
+            title,
+            window_settings: settings.window,
+            graphics_settings,
+        }),
+        sender: event_sender,
+        receiver: control_receiver,
+        error: None,
+        #[cfg(target_arch = "wasm32")]
+        is_booted: std::rc::Rc::new(std::cell::RefCell::new(false)),
+        #[cfg(target_arch = "wasm32")]
+        queued_events: Vec::new(),
+    };
+
+    impl<Message, F, C> winit::application::ApplicationHandler<Message>
+        for Runner<Message, F, C>
+    where
+        F: Future<Output = ()>,
+        C: Compositor + 'static,
     {
-        use winit::platform::web::WindowExtWebSys;
+        fn resumed(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) {
+            let Some(BootConfig {
+                sender,
+                id,
+                title,
+                window_settings,
+                graphics_settings,
+            }) = self.boot.take()
+            else {
+                return;
+            };
 
-        let canvas = window.canvas().expect("Get window canvas");
-        let _ = canvas.set_attribute(
-            "style",
-            "display: block; width: 100%; height: 100%",
-        );
+            let should_be_visible = window_settings.visible;
+            let exit_on_close_request = window_settings.exit_on_close_request;
+
+            #[cfg(target_arch = "wasm32")]
+            let target = window_settings.platform_specific.target.clone();
+
+            let window_attributes = conversion::window_attributes(
+                window_settings,
+                &title,
+                event_loop.primary_monitor(),
+                id,
+            )
+            .with_visible(false);
+
+            log::debug!("Window attributes: {window_attributes:#?}");
+
+            let window = match event_loop.create_window(window_attributes) {
+                Ok(window) => Arc::new(window),
+                Err(error) => {
+                    self.error = Some(Error::WindowCreationFailed(error));
+                    event_loop.exit();
+                    return;
+                }
+            };
+
+            let finish_boot = {
+                let window = window.clone();
+
+                async move {
+                    let compositor =
+                        C::new(graphics_settings, window.clone()).await?;
 
-        let window = web_sys::window().unwrap();
-        let document = window.document().unwrap();
-        let body = document.body().unwrap();
-
-        let target = target.and_then(|target| {
-            body.query_selector(&format!("#{target}"))
-                .ok()
-                .unwrap_or(None)
-        });
-
-        match target {
-            Some(node) => {
-                let _ = node
-                    .replace_with_with_node_1(&canvas)
-                    .expect(&format!("Could not replace #{}", node.id()));
+                    sender
+                        .send(Boot {
+                            window,
+                            compositor,
+                            should_be_visible,
+                            exit_on_close_request,
+                        })
+                        .ok()
+                        .expect("Send boot event");
+
+                    Ok::<_, graphics::Error>(())
+                }
+            };
+
+            #[cfg(not(target_arch = "wasm32"))]
+            if let Err(error) = futures::executor::block_on(finish_boot) {
+                self.error = Some(Error::GraphicsCreationFailed(error));
+                event_loop.exit();
             }
-            None => {
-                let _ = body
-                    .append_child(&canvas)
-                    .expect("Append canvas to HTML body");
+
+            #[cfg(target_arch = "wasm32")]
+            {
+                use winit::platform::web::WindowExtWebSys;
+
+                let canvas = window.canvas().expect("Get window canvas");
+                let _ = canvas.set_attribute(
+                    "style",
+                    "display: block; width: 100%; height: 100%",
+                );
+
+                let window = web_sys::window().unwrap();
+                let document = window.document().unwrap();
+                let body = document.body().unwrap();
+
+                let target = target.and_then(|target| {
+                    body.query_selector(&format!("#{target}"))
+                        .ok()
+                        .unwrap_or(None)
+                });
+
+                match target {
+                    Some(node) => {
+                        let _ = node.replace_with_with_node_1(&canvas).expect(
+                            &format!("Could not replace #{}", node.id()),
+                        );
+                    }
+                    None => {
+                        let _ = body
+                            .append_child(&canvas)
+                            .expect("Append canvas to HTML body");
+                    }
+                };
+
+                let is_booted = self.is_booted.clone();
+
+                wasm_bindgen_futures::spawn_local(async move {
+                    finish_boot.await.expect("Finish boot!");
+
+                    *is_booted.borrow_mut() = true;
+                });
             }
-        };
-    }
+        }
 
-    let mut compositor = C::new(graphics_settings, window.clone()).await?;
-    let renderer = compositor.create_renderer();
+        fn new_events(
+            &mut self,
+            event_loop: &winit::event_loop::ActiveEventLoop,
+            cause: winit::event::StartCause,
+        ) {
+            if self.boot.is_some() {
+                return;
+            }
 
-    for font in settings.fonts {
-        compositor.load_font(font);
-    }
+            self.process_event(
+                event_loop,
+                winit::event::Event::NewEvents(cause),
+            );
+        }
 
-    let (mut event_sender, event_receiver) = mpsc::unbounded();
-    let (control_sender, mut control_receiver) = mpsc::unbounded();
+        fn window_event(
+            &mut self,
+            event_loop: &winit::event_loop::ActiveEventLoop,
+            window_id: winit::window::WindowId,
+            event: winit::event::WindowEvent,
+        ) {
+            #[cfg(target_os = "windows")]
+            let is_move_or_resize = matches!(
+                event,
+                winit::event::WindowEvent::Resized(_)
+                    | winit::event::WindowEvent::Moved(_)
+            );
+
+            self.process_event(
+                event_loop,
+                winit::event::Event::WindowEvent { window_id, event },
+            );
+
+            // TODO: Remove when unnecessary
+            // On Windows, we emulate an `AboutToWait` event after every `Resized` event
+            // since the event loop does not resume during resize interaction.
+            // More details: https://github.com/rust-windowing/winit/issues/3272
+            #[cfg(target_os = "windows")]
+            {
+                if is_move_or_resize {
+                    self.process_event(
+                        event_loop,
+                        winit::event::Event::AboutToWait,
+                    );
+                }
+            }
+        }
 
-    let mut instance = Box::pin(run_instance::<A, E, C>(
-        application,
-        compositor,
-        renderer,
-        runtime,
-        proxy,
-        debug,
-        event_receiver,
-        control_sender,
-        init_command,
-        window,
-        should_be_visible,
-        exit_on_close_request,
-    ));
+        fn user_event(
+            &mut self,
+            event_loop: &winit::event_loop::ActiveEventLoop,
+            message: Message,
+        ) {
+            self.process_event(
+                event_loop,
+                winit::event::Event::UserEvent(message),
+            );
+        }
+
+        fn about_to_wait(
+            &mut self,
+            event_loop: &winit::event_loop::ActiveEventLoop,
+        ) {
+            self.process_event(event_loop, winit::event::Event::AboutToWait);
+        }
+    }
 
-    let mut context = task::Context::from_waker(task::noop_waker_ref());
+    impl<Message, F, C> Runner<Message, F, C>
+    where
+        F: Future<Output = ()>,
+    {
+        fn process_event(
+            &mut self,
+            event_loop: &winit::event_loop::ActiveEventLoop,
+            event: winit::event::Event<Message>,
+        ) {
+            // On Wasm, events may start being processed before the compositor
+            // boots up. We simply queue them and process them once ready.
+            #[cfg(target_arch = "wasm32")]
+            if !*self.is_booted.borrow() {
+                self.queued_events.push(event);
+                return;
+            } else if !self.queued_events.is_empty() {
+                let queued_events = std::mem::take(&mut self.queued_events);
+
+                // This won't infinitely recurse, since we `mem::take`
+                for event in queued_events {
+                    self.process_event(event_loop, event);
+                }
+            }
 
-    let process_event =
-        move |event, event_loop: &winit::event_loop::EventLoopWindowTarget<_>| {
             if event_loop.exiting() {
                 return;
             }
 
-            event_sender.start_send(event).expect("Send event");
+            self.sender.start_send(event).expect("Send event");
 
-            let poll = instance.as_mut().poll(&mut context);
+            let poll = self.instance.as_mut().poll(&mut self.context);
 
             match poll {
                 task::Poll::Pending => {
-                    if let Ok(Some(flow)) = control_receiver.try_next() {
+                    if let Ok(Some(flow)) = self.receiver.try_next() {
                         event_loop.set_control_flow(flow);
                     }
                 }
@@ -268,54 +450,45 @@ where
                     event_loop.exit();
                 }
             }
-        };
+        }
+    }
+
+    #[cfg(not(target_arch = "wasm32"))]
+    {
+        let mut runner = runner;
+        let _ = event_loop.run_app(&mut runner);
 
-    #[cfg(not(target_os = "windows"))]
-    let _ = event_loop.run(process_event);
+        runner.error.map(Err).unwrap_or(Ok(()))
+    }
 
-    // TODO: Remove when unnecessary
-    // On Windows, we emulate an `AboutToWait` event after every `Resized` event
-    // since the event loop does not resume during resize interaction.
-    // More details: https://github.com/rust-windowing/winit/issues/3272
-    #[cfg(target_os = "windows")]
+    #[cfg(target_arch = "wasm32")]
     {
-        let mut process_event = process_event;
+        use winit::platform::web::EventLoopExtWebSys;
+        let _ = event_loop.spawn_app(runner);
 
-        let _ = event_loop.run(move |event, event_loop| {
-            if matches!(
-                event,
-                winit::event::Event::WindowEvent {
-                    event: winit::event::WindowEvent::Resized(_)
-                        | winit::event::WindowEvent::Moved(_),
-                    ..
-                }
-            ) {
-                process_event(event, event_loop);
-                process_event(winit::event::Event::AboutToWait, event_loop);
-            } else {
-                process_event(event, event_loop);
-            }
-        });
+        Ok(())
     }
+}
 
-    Ok(())
+struct Boot<C> {
+    window: Arc<winit::window::Window>,
+    compositor: C,
+    should_be_visible: bool,
+    exit_on_close_request: bool,
 }
 
 async fn run_instance<A, E, C>(
     mut application: A,
-    mut compositor: C,
-    mut renderer: A::Renderer,
     mut runtime: Runtime<E, Proxy<A::Message>, A::Message>,
     mut proxy: Proxy<A::Message>,
     mut debug: Debug,
+    mut boot: oneshot::Receiver<Boot<C>>,
     mut event_receiver: mpsc::UnboundedReceiver<
         winit::event::Event<A::Message>,
     >,
     mut control_sender: mpsc::UnboundedSender<winit::event_loop::ControlFlow>,
     init_command: Command<A::Message>,
-    window: Arc<winit::window::Window>,
-    should_be_visible: bool,
-    exit_on_close_request: bool,
+    fonts: Vec<Cow<'static, [u8]>>,
 ) where
     A: Application + 'static,
     E: Executor + 'static,
@@ -326,6 +499,19 @@ async fn run_instance<A, E, C>(
     use winit::event;
     use winit::event_loop::ControlFlow;
 
+    let Boot {
+        window,
+        mut compositor,
+        should_be_visible,
+        exit_on_close_request,
+    } = boot.try_recv().ok().flatten().expect("Receive boot");
+
+    let mut renderer = compositor.create_renderer();
+
+    for font in fonts {
+        compositor.load_font(font);
+    }
+
     let mut state = State::new(&application, &window);
     let mut viewport_version = state.viewport_version();
     let physical_size = state.physical_size();
@@ -480,7 +666,7 @@ async fn run_instance<A, E, C>(
                 debug.draw_finished();
 
                 if new_mouse_interaction != mouse_interaction {
-                    window.set_cursor_icon(conversion::mouse_interaction(
+                    window.set_cursor(conversion::mouse_interaction(
                         new_mouse_interaction,
                     ));
 
diff --git a/winit/src/conversion.rs b/winit/src/conversion.rs
index 0f83dac3cb..d04fc2f1e0 100644
--- a/winit/src/conversion.rs
+++ b/winit/src/conversion.rs
@@ -8,16 +8,16 @@ use crate::core::touch;
 use crate::core::window;
 use crate::core::{Event, Point, Size};
 
-/// Converts some [`window::Settings`] into a `WindowBuilder` from `winit`.
-pub fn window_settings(
+/// Converts some [`window::Settings`] into some `WindowAttributes` from `winit`.
+pub fn window_attributes(
     settings: window::Settings,
     title: &str,
     primary_monitor: Option<winit::monitor::MonitorHandle>,
     _id: Option<String>,
-) -> winit::window::WindowBuilder {
-    let mut window_builder = winit::window::WindowBuilder::new();
+) -> winit::window::WindowAttributes {
+    let mut attributes = winit::window::WindowAttributes::default();
 
-    window_builder = window_builder
+    attributes = attributes
         .with_title(title)
         .with_inner_size(winit::dpi::LogicalSize {
             width: settings.size.width,
@@ -39,23 +39,21 @@ pub fn window_settings(
     if let Some(position) =
         position(primary_monitor.as_ref(), settings.size, settings.position)
     {
-        window_builder = window_builder.with_position(position);
+        attributes = attributes.with_position(position);
     }
 
     if let Some(min_size) = settings.min_size {
-        window_builder =
-            window_builder.with_min_inner_size(winit::dpi::LogicalSize {
-                width: min_size.width,
-                height: min_size.height,
-            });
+        attributes = attributes.with_min_inner_size(winit::dpi::LogicalSize {
+            width: min_size.width,
+            height: min_size.height,
+        });
     }
 
     if let Some(max_size) = settings.max_size {
-        window_builder =
-            window_builder.with_max_inner_size(winit::dpi::LogicalSize {
-                width: max_size.width,
-                height: max_size.height,
-            });
+        attributes = attributes.with_max_inner_size(winit::dpi::LogicalSize {
+            width: max_size.width,
+            height: max_size.height,
+        });
     }
 
     #[cfg(any(
@@ -65,35 +63,33 @@ pub fn window_settings(
         target_os = "openbsd"
     ))]
     {
-        // `with_name` is available on both `WindowBuilderExtWayland` and `WindowBuilderExtX11` and they do
-        // exactly the same thing. We arbitrarily choose `WindowBuilderExtWayland` here.
-        use ::winit::platform::wayland::WindowBuilderExtWayland;
+        use ::winit::platform::wayland::WindowAttributesExtWayland;
 
         if let Some(id) = _id {
-            window_builder = window_builder.with_name(id.clone(), id);
+            attributes = attributes.with_name(id.clone(), id);
         }
     }
 
     #[cfg(target_os = "windows")]
     {
-        use winit::platform::windows::WindowBuilderExtWindows;
+        use winit::platform::windows::WindowAttributesExtWindows;
         #[allow(unsafe_code)]
         unsafe {
-            window_builder = window_builder
+            attributes = attributes
                 .with_parent_window(settings.platform_specific.parent);
         }
-        window_builder = window_builder
+        attributes = attributes
             .with_drag_and_drop(settings.platform_specific.drag_and_drop);
 
-        window_builder = window_builder
+        attributes = attributes
             .with_skip_taskbar(settings.platform_specific.skip_taskbar);
     }
 
     #[cfg(target_os = "macos")]
     {
-        use winit::platform::macos::WindowBuilderExtMacOS;
+        use winit::platform::macos::WindowAttributesExtMacOS;
 
-        window_builder = window_builder
+        attributes = attributes
             .with_title_hidden(settings.platform_specific.title_hidden)
             .with_titlebar_transparent(
                 settings.platform_specific.titlebar_transparent,
@@ -107,25 +103,25 @@ pub fn window_settings(
     {
         #[cfg(feature = "x11")]
         {
-            use winit::platform::x11::WindowBuilderExtX11;
+            use winit::platform::x11::WindowAttributesExtX11;
 
-            window_builder = window_builder.with_name(
+            attributes = attributes.with_name(
                 &settings.platform_specific.application_id,
                 &settings.platform_specific.application_id,
             );
         }
         #[cfg(feature = "wayland")]
         {
-            use winit::platform::wayland::WindowBuilderExtWayland;
+            use winit::platform::wayland::WindowAttributesExtWayland;
 
-            window_builder = window_builder.with_name(
+            attributes = attributes.with_name(
                 &settings.platform_specific.application_id,
                 &settings.platform_specific.application_id,
             );
         }
     }
 
-    window_builder
+    attributes
 }
 
 /// Converts a winit window event into an iced event.
diff --git a/winit/src/multi_window.rs b/winit/src/multi_window.rs
index 2c148031c1..673a6f3067 100644
--- a/winit/src/multi_window.rs
+++ b/winit/src/multi_window.rs
@@ -12,6 +12,7 @@ use crate::core::widget::operation;
 use crate::core::window;
 use crate::core::{Point, Size};
 use crate::futures::futures::channel::mpsc;
+use crate::futures::futures::channel::oneshot;
 use crate::futures::futures::executor;
 use crate::futures::futures::task;
 use crate::futures::futures::{Future, StreamExt};
@@ -114,12 +115,12 @@ where
     C: Compositor<Renderer = A::Renderer> + 'static,
     A::Theme: DefaultStyle,
 {
-    use winit::event_loop::EventLoopBuilder;
+    use winit::event_loop::EventLoop;
 
     let mut debug = Debug::new();
     debug.startup_started();
 
-    let event_loop = EventLoopBuilder::with_user_event()
+    let event_loop = EventLoop::with_user_event()
         .build()
         .expect("Create event loop");
 
@@ -138,187 +139,292 @@ where
         runtime.enter(|| A::new(flags))
     };
 
-    let should_main_be_visible = settings.window.visible;
-    let exit_on_close_request = settings.window.exit_on_close_request;
+    let id = settings.id;
+    let title = application.title(window::Id::MAIN);
 
-    let builder = conversion::window_settings(
-        settings.window,
-        &application.title(window::Id::MAIN),
-        event_loop.primary_monitor(),
-        settings.id,
-    )
-    .with_visible(false);
+    let (boot_sender, boot_receiver) = oneshot::channel();
+    let (event_sender, event_receiver) = mpsc::unbounded();
+    let (control_sender, control_receiver) = mpsc::unbounded();
 
-    log::info!("Window builder: {:#?}", builder);
+    let instance = Box::pin(run_instance::<A, E, C>(
+        application,
+        runtime,
+        proxy,
+        debug,
+        boot_receiver,
+        event_receiver,
+        control_sender,
+        init_command,
+    ));
 
-    let main_window = Arc::new(
-        builder
-            .build(&event_loop)
-            .map_err(Error::WindowCreationFailed)?,
-    );
+    let context = task::Context::from_waker(task::noop_waker_ref());
+
+    struct Runner<Message: 'static, F, C> {
+        instance: std::pin::Pin<Box<F>>,
+        context: task::Context<'static>,
+        boot: Option<BootConfig<C>>,
+        sender: mpsc::UnboundedSender<Event<Message>>,
+        receiver: mpsc::UnboundedReceiver<Control>,
+        error: Option<Error>,
+    }
 
-    #[cfg(target_arch = "wasm32")]
+    struct BootConfig<C> {
+        sender: oneshot::Sender<Boot<C>>,
+        id: Option<String>,
+        title: String,
+        window_settings: window::Settings,
+        graphics_settings: graphics::Settings,
+    }
+
+    let mut runner = Runner {
+        instance,
+        context,
+        boot: Some(BootConfig {
+            sender: boot_sender,
+            id,
+            title,
+            window_settings: settings.window,
+            graphics_settings,
+        }),
+        sender: event_sender,
+        receiver: control_receiver,
+        error: None,
+    };
+
+    impl<Message, F, C> winit::application::ApplicationHandler<Message>
+        for Runner<Message, F, C>
+    where
+        F: Future<Output = ()>,
+        C: Compositor,
     {
-        use winit::platform::web::WindowExtWebSys;
+        fn resumed(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) {
+            let Some(BootConfig {
+                sender,
+                id,
+                title,
+                window_settings,
+                graphics_settings,
+            }) = self.boot.take()
+            else {
+                return;
+            };
 
-        let canvas = main_window.canvas();
+            let should_be_visible = window_settings.visible;
+            let exit_on_close_request = window_settings.exit_on_close_request;
 
-        let window = web_sys::window().unwrap();
-        let document = window.document().unwrap();
-        let body = document.body().unwrap();
+            let window_attributes = conversion::window_attributes(
+                window_settings,
+                &title,
+                event_loop.primary_monitor(),
+                id,
+            )
+            .with_visible(false);
 
-        let target = target.and_then(|target| {
-            body.query_selector(&format!("#{}", target))
-                .ok()
-                .unwrap_or(None)
-        });
+            log::debug!("Window attributes: {window_attributes:#?}");
 
-        match target {
-            Some(node) => {
-                let _ = node
-                    .replace_with_with_node_1(&canvas)
-                    .expect(&format!("Could not replace #{}", node.id()));
-            }
-            None => {
-                let _ = body
-                    .append_child(&canvas)
-                    .expect("Append canvas to HTML body");
-            }
-        };
-    }
+            let window = match event_loop.create_window(window_attributes) {
+                Ok(window) => Arc::new(window),
+                Err(error) => {
+                    self.error = Some(Error::WindowCreationFailed(error));
+                    event_loop.exit();
+                    return;
+                }
+            };
 
-    let mut compositor =
-        executor::block_on(C::new(graphics_settings, main_window.clone()))?;
+            let finish_boot = async move {
+                let compositor =
+                    C::new(graphics_settings, window.clone()).await?;
+
+                sender
+                    .send(Boot {
+                        window,
+                        compositor,
+                        should_be_visible,
+                        exit_on_close_request,
+                    })
+                    .ok()
+                    .expect("Send boot event");
+
+                Ok::<_, graphics::Error>(())
+            };
 
-    let mut window_manager = WindowManager::new();
-    let _ = window_manager.insert(
-        window::Id::MAIN,
-        main_window,
-        &application,
-        &mut compositor,
-        exit_on_close_request,
-    );
+            if let Err(error) = executor::block_on(finish_boot) {
+                self.error = Some(Error::GraphicsCreationFailed(error));
+                event_loop.exit();
+            }
+        }
 
-    let (mut event_sender, event_receiver) = mpsc::unbounded();
-    let (control_sender, mut control_receiver) = mpsc::unbounded();
+        fn new_events(
+            &mut self,
+            event_loop: &winit::event_loop::ActiveEventLoop,
+            cause: winit::event::StartCause,
+        ) {
+            if self.boot.is_some() {
+                return;
+            }
 
-    let mut instance = Box::pin(run_instance::<A, E, C>(
-        application,
-        compositor,
-        runtime,
-        proxy,
-        debug,
-        event_receiver,
-        control_sender,
-        init_command,
-        window_manager,
-        should_main_be_visible,
-    ));
+            self.process_event(
+                event_loop,
+                Event::EventLoopAwakened(winit::event::Event::NewEvents(cause)),
+            );
+        }
+
+        fn window_event(
+            &mut self,
+            event_loop: &winit::event_loop::ActiveEventLoop,
+            window_id: winit::window::WindowId,
+            event: winit::event::WindowEvent,
+        ) {
+            #[cfg(target_os = "windows")]
+            let is_move_or_resize = matches!(
+                event,
+                winit::event::WindowEvent::Resized(_)
+                    | winit::event::WindowEvent::Moved(_)
+            );
+
+            self.process_event(
+                event_loop,
+                Event::EventLoopAwakened(winit::event::Event::WindowEvent {
+                    window_id,
+                    event,
+                }),
+            );
+
+            // TODO: Remove when unnecessary
+            // On Windows, we emulate an `AboutToWait` event after every `Resized` event
+            // since the event loop does not resume during resize interaction.
+            // More details: https://github.com/rust-windowing/winit/issues/3272
+            #[cfg(target_os = "windows")]
+            {
+                if is_move_or_resize {
+                    self.process_event(
+                        event_loop,
+                        Event::EventLoopAwakened(
+                            winit::event::Event::AboutToWait,
+                        ),
+                    );
+                }
+            }
+        }
 
-    let mut context = task::Context::from_waker(task::noop_waker_ref());
+        fn user_event(
+            &mut self,
+            event_loop: &winit::event_loop::ActiveEventLoop,
+            message: Message,
+        ) {
+            self.process_event(
+                event_loop,
+                Event::EventLoopAwakened(winit::event::Event::UserEvent(
+                    message,
+                )),
+            );
+        }
 
-    let process_event = move |event, event_loop: &winit::event_loop::EventLoopWindowTarget<_>| {
-        if event_loop.exiting() {
-            return;
+        fn about_to_wait(
+            &mut self,
+            event_loop: &winit::event_loop::ActiveEventLoop,
+        ) {
+            self.process_event(
+                event_loop,
+                Event::EventLoopAwakened(winit::event::Event::AboutToWait),
+            );
         }
+    }
 
-        event_sender
-            .start_send(Event::EventLoopAwakened(event))
-            .expect("Send event");
-
-        loop {
-            let poll = instance.as_mut().poll(&mut context);
-
-            match poll {
-                task::Poll::Pending => match control_receiver.try_next() {
-                    Ok(Some(control)) => match control {
-                        Control::ChangeFlow(flow) => {
-                            use winit::event_loop::ControlFlow;
-
-                            match (event_loop.control_flow(), flow) {
-                                (
-                                    ControlFlow::WaitUntil(current),
-                                    ControlFlow::WaitUntil(new),
-                                ) if new < current => {}
-                                (
-                                    ControlFlow::WaitUntil(target),
-                                    ControlFlow::Wait,
-                                ) if target > Instant::now() => {}
-                                _ => {
-                                    event_loop.set_control_flow(flow);
+    impl<Message, F, C> Runner<Message, F, C>
+    where
+        F: Future<Output = ()>,
+        C: Compositor,
+    {
+        fn process_event(
+            &mut self,
+            event_loop: &winit::event_loop::ActiveEventLoop,
+            event: Event<Message>,
+        ) {
+            if event_loop.exiting() {
+                return;
+            }
+
+            self.sender.start_send(event).expect("Send event");
+
+            loop {
+                let poll = self.instance.as_mut().poll(&mut self.context);
+
+                match poll {
+                    task::Poll::Pending => match self.receiver.try_next() {
+                        Ok(Some(control)) => match control {
+                            Control::ChangeFlow(flow) => {
+                                use winit::event_loop::ControlFlow;
+
+                                match (event_loop.control_flow(), flow) {
+                                    (
+                                        ControlFlow::WaitUntil(current),
+                                        ControlFlow::WaitUntil(new),
+                                    ) if new < current => {}
+                                    (
+                                        ControlFlow::WaitUntil(target),
+                                        ControlFlow::Wait,
+                                    ) if target > Instant::now() => {}
+                                    _ => {
+                                        event_loop.set_control_flow(flow);
+                                    }
                                 }
                             }
-                        }
-                        Control::CreateWindow {
-                            id,
-                            settings,
-                            title,
-                            monitor,
-                        } => {
-                            let exit_on_close_request =
-                                settings.exit_on_close_request;
-
-                            let window = conversion::window_settings(
-                                settings, &title, monitor, None,
-                            )
-                            .build(event_loop)
-                            .expect("Failed to build window");
-
-                            event_sender
-                                .start_send(Event::WindowCreated {
-                                    id,
-                                    window,
-                                    exit_on_close_request,
-                                })
-                                .expect("Send event");
-                        }
-                        Control::Exit => {
-                            event_loop.exit();
+                            Control::CreateWindow {
+                                id,
+                                settings,
+                                title,
+                                monitor,
+                            } => {
+                                let exit_on_close_request =
+                                    settings.exit_on_close_request;
+
+                                let window = event_loop
+                                    .create_window(
+                                        conversion::window_attributes(
+                                            settings, &title, monitor, None,
+                                        ),
+                                    )
+                                    .expect("Create window");
+
+                                self.process_event(
+                                    event_loop,
+                                    Event::WindowCreated {
+                                        id,
+                                        window,
+                                        exit_on_close_request,
+                                    },
+                                );
+                            }
+                            Control::Exit => {
+                                event_loop.exit();
+                            }
+                        },
+                        _ => {
+                            break;
                         }
                     },
-                    _ => {
+                    task::Poll::Ready(_) => {
+                        event_loop.exit();
                         break;
                     }
-                },
-                task::Poll::Ready(_) => {
-                    event_loop.exit();
-                    break;
-                }
-            };
-        }
-    };
-
-    #[cfg(not(target_os = "windows"))]
-    let _ = event_loop.run(process_event);
-
-    // TODO: Remove when unnecessary
-    // On Windows, we emulate an `AboutToWait` event after every `Resized` event
-    // since the event loop does not resume during resize interaction.
-    // More details: https://github.com/rust-windowing/winit/issues/3272
-    #[cfg(target_os = "windows")]
-    {
-        let mut process_event = process_event;
-
-        let _ = event_loop.run(move |event, event_loop| {
-            if matches!(
-                event,
-                winit::event::Event::WindowEvent {
-                    event: winit::event::WindowEvent::Resized(_)
-                        | winit::event::WindowEvent::Moved(_),
-                    ..
-                }
-            ) {
-                process_event(event, event_loop);
-                process_event(winit::event::Event::AboutToWait, event_loop);
-            } else {
-                process_event(event, event_loop);
+                };
             }
-        });
+        }
     }
 
+    let _ = event_loop.run_app(&mut runner);
+
     Ok(())
 }
 
+struct Boot<C> {
+    window: Arc<winit::window::Window>,
+    compositor: C,
+    should_be_visible: bool,
+    exit_on_close_request: bool,
+}
+
 enum Event<Message: 'static> {
     WindowCreated {
         id: window::Id,
@@ -341,15 +447,13 @@ enum Control {
 
 async fn run_instance<A, E, C>(
     mut application: A,
-    mut compositor: C,
     mut runtime: Runtime<E, Proxy<A::Message>, A::Message>,
     mut proxy: Proxy<A::Message>,
     mut debug: Debug,
+    mut boot: oneshot::Receiver<Boot<C>>,
     mut event_receiver: mpsc::UnboundedReceiver<Event<A::Message>>,
     mut control_sender: mpsc::UnboundedSender<Control>,
     init_command: Command<A::Message>,
-    mut window_manager: WindowManager<A, C>,
-    should_main_window_be_visible: bool,
 ) where
     A: Application + 'static,
     E: Executor + 'static,
@@ -359,11 +463,28 @@ async fn run_instance<A, E, C>(
     use winit::event;
     use winit::event_loop::ControlFlow;
 
+    let Boot {
+        window: main_window,
+        mut compositor,
+        should_be_visible,
+        exit_on_close_request,
+    } = boot.try_recv().ok().flatten().expect("Receive boot");
+
+    let mut window_manager = WindowManager::new();
+
+    let _ = window_manager.insert(
+        window::Id::MAIN,
+        main_window.clone(),
+        &application,
+        &mut compositor,
+        exit_on_close_request,
+    );
+
     let main_window = window_manager
         .get_mut(window::Id::MAIN)
         .expect("Get main window");
 
-    if should_main_window_be_visible {
+    if should_be_visible {
         main_window.raw.set_visible(true);
     }
 
@@ -532,7 +653,7 @@ async fn run_instance<A, E, C>(
                         debug.draw_finished();
 
                         if new_mouse_interaction != window.mouse_interaction {
-                            window.raw.set_cursor_icon(
+                            window.raw.set_cursor(
                                 conversion::mouse_interaction(
                                     new_mouse_interaction,
                                 ),
@@ -603,7 +724,7 @@ async fn run_instance<A, E, C>(
 
                             if new_mouse_interaction != window.mouse_interaction
                             {
-                                window.raw.set_cursor_icon(
+                                window.raw.set_cursor(
                                     conversion::mouse_interaction(
                                         new_mouse_interaction,
                                     ),
diff --git a/winit/src/multi_window/window_manager.rs b/winit/src/multi_window/window_manager.rs
index 3a0c8556a9..57a7dc7e38 100644
--- a/winit/src/multi_window/window_manager.rs
+++ b/winit/src/multi_window/window_manager.rs
@@ -9,8 +9,9 @@ use std::sync::Arc;
 use winit::monitor::MonitorHandle;
 
 #[allow(missing_debug_implementations)]
-pub struct WindowManager<A: Application, C: Compositor>
+pub struct WindowManager<A, C>
 where
+    A: Application,
     C: Compositor<Renderer = A::Renderer>,
     A::Theme: DefaultStyle,
 {


Test patch: