diff options
Diffstat (limited to 'winit/src')
| -rw-r--r-- | winit/src/application.rs | 400 | ||||
| -rw-r--r-- | winit/src/conversion.rs | 87 | ||||
| -rw-r--r-- | winit/src/multi_window.rs | 443 | ||||
| -rw-r--r-- | winit/src/multi_window/window_manager.rs | 3 | 
4 files changed, 633 insertions, 300 deletions
diff --git a/winit/src/application.rs b/winit/src/application.rs index a447c9da..f7508b4c 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,                      )); @@ -864,7 +1050,7 @@ pub fn run_command<A, C, E>(                      use window::raw_window_handle::HasWindowHandle;                      if let Ok(handle) = window.window_handle() { -                        proxy.send(tag(&handle)); +                        proxy.send(tag(handle));                      }                  } diff --git a/winit/src/conversion.rs b/winit/src/conversion.rs index 0f83dac3..ea33e610 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. @@ -327,6 +323,35 @@ pub fn position(                  y: f64::from(position.y),              }))          } +        window::Position::SpecificWith(to_position) => { +            if let Some(monitor) = monitor { +                let start = monitor.position(); + +                let resolution: winit::dpi::LogicalSize<f32> = +                    monitor.size().to_logical(monitor.scale_factor()); + +                let position = to_position( +                    size, +                    Size::new(resolution.width, resolution.height), +                ); + +                let centered: winit::dpi::PhysicalPosition<i32> = +                    winit::dpi::LogicalPosition { +                        x: position.x, +                        y: position.y, +                    } +                    .to_physical(monitor.scale_factor()); + +                Some(winit::dpi::Position::Physical( +                    winit::dpi::PhysicalPosition { +                        x: start.x + centered.x, +                        y: start.y + centered.y, +                    }, +                )) +            } else { +                None +            } +        }          window::Position::Centered => {              if let Some(monitor) = monitor {                  let start = monitor.position(); diff --git a/winit/src/multi_window.rs b/winit/src/multi_window.rs index 2c148031..95d78b83 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, +        &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,                                      ), @@ -1102,7 +1223,7 @@ fn run_command<A, C, E>(                          .get_mut(id)                          .and_then(|window| window.raw.window_handle().ok())                      { -                        proxy.send(tag(&handle)); +                        proxy.send(tag(handle));                      }                  }                  window::Action::Screenshot(id, tag) => { diff --git a/winit/src/multi_window/window_manager.rs b/winit/src/multi_window/window_manager.rs index 3a0c8556..57a7dc7e 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,  {  | 
