summaryrefslogtreecommitdiffstats
path: root/winit/src/multi_window.rs
diff options
context:
space:
mode:
Diffstat (limited to 'winit/src/multi_window.rs')
-rw-r--r--winit/src/multi_window.rs428
1 files changed, 267 insertions, 161 deletions
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,
),