diff options
Diffstat (limited to 'winit/src/program.rs')
-rw-r--r-- | winit/src/program.rs | 199 |
1 files changed, 142 insertions, 57 deletions
diff --git a/winit/src/program.rs b/winit/src/program.rs index d55aedf1..52d8eb5f 100644 --- a/winit/src/program.rs +++ b/winit/src/program.rs @@ -202,12 +202,25 @@ where }; let (program, task) = runtime.enter(|| P::new(flags)); + let is_daemon = window_settings.is_none(); - if let Some(stream) = task.into_stream() { + let task = if let Some(window_settings) = window_settings { + let mut task = Some(task); + + let (_id, open) = runtime::window::open(window_settings); + + open.then(move |_| task.take().unwrap_or(Task::none())) + } else { + task + }; + + if let Some(stream) = runtime::task::into_stream(task) { runtime.run(stream); } - runtime.track(program.subscription().map(Action::Output).into_recipes()); + runtime.track(subscription::into_recipes( + program.subscription().map(Action::Output), + )); let (boot_sender, boot_receiver) = oneshot::channel(); let (event_sender, event_receiver) = mpsc::unbounded(); @@ -221,6 +234,7 @@ where boot_receiver, event_receiver, control_sender, + is_daemon, )); let context = task::Context::from_waker(task::noop_waker_ref()); @@ -229,7 +243,7 @@ where instance: std::pin::Pin<Box<F>>, context: task::Context<'static>, id: Option<String>, - boot: Option<BootConfig<Message, C>>, + boot: Option<BootConfig<C>>, sender: mpsc::UnboundedSender<Event<Action<Message>>>, receiver: mpsc::UnboundedReceiver<Control>, error: Option<Error>, @@ -240,11 +254,9 @@ where queued_events: Vec<Event<Action<Message>>>, } - struct BootConfig<Message: 'static, C> { - proxy: Proxy<Message>, + struct BootConfig<C> { sender: oneshot::Sender<Boot<C>>, fonts: Vec<Cow<'static, [u8]>>, - window_settings: Option<window::Settings>, graphics_settings: graphics::Settings, } @@ -253,10 +265,8 @@ where context, id: settings.id, boot: Some(BootConfig { - proxy, sender: boot_sender, fonts: settings.fonts, - window_settings, graphics_settings, }), sender: event_sender, @@ -278,10 +288,8 @@ where { fn resumed(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) { let Some(BootConfig { - mut proxy, sender, fonts, - window_settings, graphics_settings, }) = self.boot.take() else { @@ -299,8 +307,6 @@ where } }; - let clipboard = Clipboard::connect(&window); - let finish_boot = async move { let mut compositor = C::new(graphics_settings, window.clone()).await?; @@ -310,27 +316,10 @@ where } sender - .send(Boot { - compositor, - clipboard, - window: window.id(), - is_daemon: window_settings.is_none(), - }) + .send(Boot { compositor }) .ok() .expect("Send boot event"); - if let Some(window_settings) = window_settings { - let (sender, _receiver) = oneshot::channel(); - - proxy.send_action(Action::Window( - runtime::window::Action::Open( - window::Id::unique(), - window_settings, - sender, - ), - )); - } - Ok::<_, graphics::Error>(()) }; @@ -420,6 +409,23 @@ where ); } + fn received_url( + &mut self, + event_loop: &winit::event_loop::ActiveEventLoop, + url: String, + ) { + self.process_event( + event_loop, + Event::EventLoopAwakened( + winit::event::Event::PlatformSpecific( + winit::event::PlatformSpecific::MacOS( + winit::event::MacOS::ReceivedUrl(url), + ), + ), + ), + ); + } + fn about_to_wait( &mut self, event_loop: &winit::event_loop::ActiveEventLoop, @@ -488,10 +494,13 @@ where settings, title, monitor, + on_open, } => { let exit_on_close_request = settings.exit_on_close_request; + let visible = settings.visible; + #[cfg(target_arch = "wasm32")] let target = settings.platform_specific.target.clone(); @@ -505,7 +514,8 @@ where .or(event_loop .primary_monitor()), self.id.clone(), - ), + ) + .with_visible(false), ) .expect("Create window"); @@ -561,6 +571,8 @@ where id, window, exit_on_close_request, + make_visible: visible, + on_open, }, ); } @@ -600,20 +612,21 @@ where struct Boot<C> { compositor: C, - clipboard: Clipboard, - window: winit::window::WindowId, - is_daemon: bool, } +#[derive(Debug)] enum Event<Message: 'static> { WindowCreated { id: window::Id, window: winit::window::Window, exit_on_close_request: bool, + make_visible: bool, + on_open: oneshot::Sender<window::Id>, }, EventLoopAwakened(winit::event::Event<Message>), } +#[derive(Debug)] enum Control { ChangeFlow(winit::event_loop::ControlFlow), Exit, @@ -622,6 +635,7 @@ enum Control { settings: window::Settings, title: String, monitor: Option<winit::monitor::MonitorHandle>, + on_open: oneshot::Sender<window::Id>, }, } @@ -630,9 +644,10 @@ async fn run_instance<P, C>( mut runtime: Runtime<P::Executor, Proxy<P::Message>, Action<P::Message>>, mut proxy: Proxy<P::Message>, mut debug: Debug, - mut boot: oneshot::Receiver<Boot<C>>, + boot: oneshot::Receiver<Boot<C>>, mut event_receiver: mpsc::UnboundedReceiver<Event<Action<P::Message>>>, mut control_sender: mpsc::UnboundedSender<Control>, + is_daemon: bool, ) where P: Program + 'static, C: Compositor<Renderer = P::Renderer> + 'static, @@ -641,14 +656,10 @@ async fn run_instance<P, C>( use winit::event; use winit::event_loop::ControlFlow; - let Boot { - mut compositor, - mut clipboard, - window: boot_window, - is_daemon, - } = boot.try_recv().ok().flatten().expect("Receive boot"); + let Boot { mut compositor } = boot.await.expect("Receive boot"); let mut window_manager = WindowManager::new(); + let mut is_window_opening = !is_daemon; let mut events = Vec::new(); let mut messages = Vec::new(); @@ -656,15 +667,29 @@ async fn run_instance<P, C>( let mut ui_caches = FxHashMap::default(); let mut user_interfaces = ManuallyDrop::new(FxHashMap::default()); + let mut clipboard = Clipboard::unconnected(); debug.startup_finished(); - 'main: while let Some(event) = event_receiver.next().await { + loop { + // Empty the queue if possible + let event = if let Ok(event) = event_receiver.try_next() { + event + } else { + event_receiver.next().await + }; + + let Some(event) = event else { + break; + }; + match event { Event::WindowCreated { id, window, exit_on_close_request, + make_visible, + on_open, } => { let window = window_manager.insert( id, @@ -689,6 +714,10 @@ async fn run_instance<P, C>( ); let _ = ui_caches.insert(id, user_interface::Cache::default()); + if make_visible { + window.raw.set_visible(true); + } + events.push(( id, core::Event::Window(window::Event::Opened { @@ -696,6 +725,13 @@ async fn run_instance<P, C>( size: window.size(), }), )); + + if clipboard.window_id().is_none() { + clipboard = Clipboard::connect(window.raw.clone()); + } + + let _ = on_open.send(id); + is_window_opening = false; } Event::EventLoopAwakened(event) => { match event { @@ -725,6 +761,7 @@ async fn run_instance<P, C>( action, &program, &mut compositor, + &mut events, &mut messages, &mut clipboard, &mut control_sender, @@ -732,6 +769,7 @@ async fn run_instance<P, C>( &mut user_interfaces, &mut window_manager, &mut ui_caches, + &mut is_window_opening, ); actions += 1; } @@ -916,10 +954,14 @@ async fn run_instance<P, C>( window_event, winit::event::WindowEvent::Destroyed ) - && window_id != boot_window + && !is_window_opening && window_manager.is_empty() { - break 'main; + control_sender + .start_send(Control::Exit) + .expect("Send control action"); + + continue; } let Some((id, window)) = @@ -933,14 +975,22 @@ async fn run_instance<P, C>( winit::event::WindowEvent::CloseRequested ) && window.exit_on_close_request { - let _ = window_manager.remove(id); - let _ = user_interfaces.remove(&id); - let _ = ui_caches.remove(&id); - - events.push(( - id, - core::Event::Window(window::Event::Closed), - )); + run_action( + Action::Window(runtime::window::Action::Close( + id, + )), + &program, + &mut compositor, + &mut events, + &mut messages, + &mut clipboard, + &mut control_sender, + &mut debug, + &mut user_interfaces, + &mut window_manager, + &mut ui_caches, + &mut is_window_opening, + ); } else { window.state.update( &window.raw, @@ -1114,19 +1164,20 @@ fn update<P: Program, E: Executor>( let task = runtime.enter(|| program.update(message)); debug.update_finished(); - if let Some(stream) = task.into_stream() { + if let Some(stream) = runtime::task::into_stream(task) { runtime.run(stream); } } let subscription = program.subscription(); - runtime.track(subscription.map(Action::Output).into_recipes()); + runtime.track(subscription::into_recipes(subscription.map(Action::Output))); } fn run_action<P, C>( action: Action<P::Message>, program: &P, compositor: &mut C, + events: &mut Vec<(window::Id, core::Event)>, messages: &mut Vec<P::Message>, clipboard: &mut Clipboard, control_sender: &mut mpsc::UnboundedSender<Control>, @@ -1137,6 +1188,7 @@ fn run_action<P, C>( >, window_manager: &mut WindowManager<P, C>, ui_caches: &mut FxHashMap<window::Id, user_interface::Cache>, + is_window_opening: &mut bool, ) where P: Program, C: Compositor<Renderer = P::Renderer> + 'static, @@ -1168,14 +1220,30 @@ fn run_action<P, C>( settings, title: program.title(id), monitor, + on_open: channel, }) .expect("Send control action"); - let _ = channel.send(id); + *is_window_opening = true; } window::Action::Close(id) => { - let _ = window_manager.remove(id); let _ = ui_caches.remove(&id); + let _ = interfaces.remove(&id); + + if let Some(window) = window_manager.remove(id) { + if clipboard.window_id() == Some(window.raw.id()) { + *clipboard = window_manager + .first() + .map(|window| window.raw.clone()) + .map(Clipboard::connect) + .unwrap_or_else(Clipboard::unconnected); + } + + events.push(( + id, + core::Event::Window(core::window::Event::Closed), + )); + } } window::Action::GetOldest(channel) => { let id = @@ -1235,7 +1303,7 @@ fn run_action<P, C>( } } window::Action::GetPosition(id, channel) => { - if let Some(window) = window_manager.get_mut(id) { + if let Some(window) = window_manager.get(id) { let position = window .raw .inner_position() @@ -1250,6 +1318,13 @@ fn run_action<P, C>( let _ = channel.send(position); } } + window::Action::GetScaleFactor(id, channel) => { + if let Some(window) = window_manager.get_mut(id) { + let scale_factor = window.raw.scale_factor(); + + let _ = channel.send(scale_factor as f32); + } + } window::Action::Move(id, position) => { if let Some(window) = window_manager.get_mut(id) { window.raw.set_outer_position( @@ -1360,6 +1435,16 @@ fn run_action<P, C>( )); } } + window::Action::EnableMousePassthrough(id) => { + if let Some(window) = window_manager.get_mut(id) { + let _ = window.raw.set_cursor_hittest(false); + } + } + window::Action::DisableMousePassthrough(id) => { + if let Some(window) = window_manager.get_mut(id) { + let _ = window.raw.set_cursor_hittest(true); + } + } }, Action::System(action) => match action { system::Action::QueryInformation(_channel) => { |