| ... | @@ -6565,7 +6565,7 @@ impl App { | ... | @@ -6565,7 +6565,7 @@ impl App { |
| 6565 | .map(|outline| (&outline.id, outline.document()))); | 6565 | .map(|outline| (&outline.id, outline.document()))); |
| 6566 | state.session.is_none() && !unchanged | 6566 | state.session.is_none() && !unchanged |
| 6567 | }) else { | 6567 | }) else { |
| 6568 | return self.exit(event_loop); | 6568 | return event_loop.exit(); |
| 6569 | }; | 6569 | }; |
| 6570 | crate::confirm( | 6570 | crate::confirm( |
| 6571 | "Discard this page?", | 6571 | "Discard this page?", |
| ... | @@ -6578,19 +6578,12 @@ impl App { | ... | @@ -6578,19 +6578,12 @@ impl App { |
| 6578 | }), | 6578 | }), |
| 6579 | ); | 6579 | ); |
| 6580 | } | 6580 | } |
| 6581 | | | |
| 6582 | fn exit(&self, event_loop: &ActiveEventLoop) { | | |
| 6583 | if let Some(state) = &self.state { | | |
| 6584 | state.publish_now(QUIT_PUBLISH); | | |
| 6585 | } | | |
| 6586 | event_loop.exit(); | | |
| 6587 | } | | |
| 6588 | } | 6581 | } |
| 6589 | | 6582 | |
| 6590 | /// How long quitting waits for the open section's edits to reach its file; they stay in the | 6583 | /// How long quitting waits for the open section's edits to reach its file and for every |
| 6591 | /// replica and publish at the next launch otherwise. | 6584 | /// section to close; edits left stay in the replica and publish at the next launch. |
| 6592 | #[cfg(not(target_arch = "wasm32"))] | 6585 | #[cfg(not(target_arch = "wasm32"))] |
| 6593 | const QUIT_PUBLISH: std::time::Duration = std::time::Duration::from_secs(3); | 6586 | const QUIT: std::time::Duration = std::time::Duration::from_secs(3); |
| 6594 | | 6587 | |
| 6595 | #[cfg(not(target_arch = "wasm32"))] | 6588 | #[cfg(not(target_arch = "wasm32"))] |
| 6596 | impl ApplicationHandler<UserEvent> for App { | 6589 | impl ApplicationHandler<UserEvent> for App { |
| ... | @@ -6610,7 +6603,7 @@ impl ApplicationHandler<UserEvent> for App { | ... | @@ -6610,7 +6603,7 @@ impl ApplicationHandler<UserEvent> for App { |
| 6610 | }; | 6603 | }; |
| 6611 | match event { | 6604 | match event { |
| 6612 | UserEvent::Quit | UserEvent::Replay(Replay::Quit) => self.close(event_loop), | 6605 | UserEvent::Quit | UserEvent::Replay(Replay::Quit) => self.close(event_loop), |
| 6613 | UserEvent::Exit => self.exit(event_loop), | 6606 | UserEvent::Exit => event_loop.exit(), |
| 6614 | UserEvent::Renderer(chosen) | UserEvent::Replay(Replay::Renderer(chosen)) => { | 6607 | UserEvent::Renderer(chosen) | UserEvent::Replay(Replay::Renderer(chosen)) => { |
| 6615 | let state = self.state.take().expect("The window is open"); | 6608 | let state = self.state.take().expect("The window is open"); |
| 6616 | match state.switch_renderer(chosen) { | 6609 | match state.switch_renderer(chosen) { |
| ... | @@ -6831,10 +6824,37 @@ impl ApplicationHandler<UserEvent> for App { | ... | @@ -6831,10 +6824,37 @@ impl ApplicationHandler<UserEvent> for App { |
| 6831 | /// Drops the window's state while the event loop still holds the Wayland connection the | 6824 | /// Drops the window's state while the event loop still holds the Wayland connection the |
| 6832 | /// clipboard and the surface use; `run_app` closes it on returning. | 6825 | /// clipboard and the surface use; `run_app` closes it on returning. |
| 6833 | fn exiting(&mut self, _: &ActiveEventLoop) { | 6826 | fn exiting(&mut self, _: &ActiveEventLoop) { |
| 6834 | self.restart = self | 6827 | let Some(mut state) = self.state.take() else { |
| 6835 | .state | 6828 | return; |
| 6836 | .take() | 6829 | }; |
| 6837 | .and_then(|state| state.updates.restarting()); | 6830 | let deadline = Instant::now() + QUIT; |
| | 6831 | state.publish_now(QUIT); |
| | 6832 | self.restart = state.updates.restarting(); |
| | 6833 | let session = state.session.take(); |
| | 6834 | let libraries: Vec<_> = (state.notebooks.iter()) |
| | 6835 | .chain(session.as_ref().map(|session| &session.library)) |
| | 6836 | .cloned() |
| | 6837 | .collect(); |
| | 6838 | // Dropped sections and backgrounds stop without waiting, so the process could end first. |
| | 6839 | let (closed, closing) = mpsc::channel::<()>(); |
| | 6840 | std::thread::spawn(move || { |
| | 6841 | // Backgrounds first, or a released section would be checked again. |
| | 6842 | for background in libraries |
| | 6843 | .iter() |
| | 6844 | .filter_map(|library| library.background.as_ref()) |
| | 6845 | { |
| | 6846 | background.stop(); |
| | 6847 | } |
| | 6848 | if let Some(session) = session |
| | 6849 | && let Err(error) = session.section.close() |
| | 6850 | { |
| | 6851 | eprintln!("Synchronization stopped: {error}"); |
| | 6852 | } |
| | 6853 | libraries.iter().for_each(|library| library.close_kept()); |
| | 6854 | drop(closed); |
| | 6855 | }); |
| | 6856 | drop(state); |
| | 6857 | let _ = closing.recv_timeout(deadline.saturating_duration_since(Instant::now())); |
| 6838 | } | 6858 | } |
| 6839 | } | 6859 | } |
| 6840 | | 6860 | |