summaryrefslogtreecommitdiffstats
path: root/winit/src
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón Jiménez <hector@hecrj.dev>2024-05-07 15:50:18 +0200
committerLibravatar Héctor Ramón Jiménez <hector@hecrj.dev>2024-05-07 16:07:56 +0200
commit2645524f88414393d8b3ca9c6fe801b32b5ebd33 (patch)
tree9fad3313f97bcc5ca9c75c2c7ca08eb21ff578a2 /winit/src
parentdb07b9ba9ef20c5995076992bf5592af12698000 (diff)
downloadiced-2645524f88414393d8b3ca9c6fe801b32b5ebd33.tar.gz
iced-2645524f88414393d8b3ca9c6fe801b32b5ebd33.tar.bz2
iced-2645524f88414393d8b3ca9c6fe801b32b5ebd33.zip
Update `winit` to `0.30`
Diffstat (limited to 'winit/src')
-rw-r--r--winit/src/application.rs383
-rw-r--r--winit/src/conversion.rs58
-rw-r--r--winit/src/multi_window.rs428
-rw-r--r--winit/src/multi_window/window_manager.rs3
4 files changed, 573 insertions, 299 deletions
diff --git a/winit/src/application.rs b/winit/src/application.rs
index a447c9da..e056f4c5 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,267 @@ 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();
- 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()));
+ 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>(())
+ }
+ };
+
+ #[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;
+ });
}
- };
- }
+ }
+
+ 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 compositor = C::new(graphics_settings, window.clone()).await?;
- let renderer = compositor.create_renderer();
+ fn user_event(
+ &mut self,
+ event_loop: &winit::event_loop::ActiveEventLoop,
+ message: Message,
+ ) {
+ self.process_event(
+ event_loop,
+ winit::event::Event::UserEvent(message),
+ );
+ }
- for font in settings.fonts {
- compositor.load_font(font);
+ fn about_to_wait(
+ &mut self,
+ event_loop: &winit::event_loop::ActiveEventLoop,
+ ) {
+ self.process_event(event_loop, winit::event::Event::AboutToWait);
+ }
}
- let (mut event_sender, event_receiver) = mpsc::unbounded();
- let (control_sender, mut control_receiver) = mpsc::unbounded();
-
- 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,
- ));
+ 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);
- let mut context = task::Context::from_waker(task::noop_waker_ref());
+ // 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 +435,45 @@ where
event_loop.exit();
}
}
- };
+ }
+ }
- #[cfg(not(target_os = "windows"))]
- let _ = event_loop.run(process_event);
+ #[cfg(not(target_arch = "wasm32"))]
+ {
+ let mut runner = runner;
+ let _ = event_loop.run_app(&mut runner);
+
+ 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 +484,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 +651,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 0f83dac3..d04fc2f1 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 2c148031..145b1569 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,277 @@ 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());
- #[cfg(target_arch = "wasm32")]
- {
- use winit::platform::web::WindowExtWebSys;
+ 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>,
+ }
- let canvas = main_window.canvas();
+ struct BootConfig<C> {
+ sender: oneshot::Sender<Boot<C>>,
+ id: Option<String>,
+ title: String,
+ window_settings: window::Settings,
+ graphics_settings: graphics::Settings,
+ }
- let window = web_sys::window().unwrap();
- let document = window.document().unwrap();
- let body = document.body().unwrap();
+ 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,
+ };
- let target = target.and_then(|target| {
- body.query_selector(&format!("#{}", target))
- .ok()
- .unwrap_or(None)
- });
+ impl<Message, F, C> winit::application::ApplicationHandler<Message>
+ for Runner<Message, F, C>
+ where
+ F: Future<Output = ()>,
+ C: Compositor,
+ {
+ 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;
+ };
- 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 should_be_visible = window_settings.visible;
+ let exit_on_close_request = window_settings.exit_on_close_request;
- let mut compositor =
- executor::block_on(C::new(graphics_settings, main_window.clone()))?;
+ let window_attributes = conversion::window_attributes(
+ window_settings,
+ &title,
+ event_loop.primary_monitor(),
+ id,
+ )
+ .with_visible(false);
- let mut window_manager = WindowManager::new();
- let _ = window_manager.insert(
- window::Id::MAIN,
- main_window,
- &application,
- &mut compositor,
- exit_on_close_request,
- );
+ log::debug!("Window attributes: {window_attributes:#?}");
- let (mut event_sender, event_receiver) = mpsc::unbounded();
- let (control_sender, mut control_receiver) = mpsc::unbounded();
+ 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 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,
- ));
+ 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 context = task::Context::from_waker(task::noop_waker_ref());
+ if let Err(error) = executor::block_on(finish_boot) {
+ self.error = Some(Error::GraphicsCreationFailed(error));
+ event_loop.exit();
+ }
+ }
- let process_event = move |event, event_loop: &winit::event_loop::EventLoopWindowTarget<_>| {
- if event_loop.exiting() {
- return;
+ 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,
+ ),
+ );
+ }
+ }
}
- 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);
+ 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,
+ )),
+ );
+ }
+
+ fn about_to_wait(
+ &mut self,
+ event_loop: &winit::event_loop::ActiveEventLoop,
+ ) {
+ self.process_event(
+ event_loop,
+ Event::EventLoopAwakened(winit::event::Event::AboutToWait),
+ );
+ }
+ }
+
+ 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 +432,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 +448,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 +638,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 +709,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 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,
{