mirror of
https://github.com/danbulant/appit
synced 2026-05-24 12:26:14 +00:00
App::prevent_shutdown()
This commit is contained in:
parent
93479b8111
commit
331bfdd353
3 changed files with 76 additions and 8 deletions
|
|
@ -32,6 +32,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
- `WindowBehavior::moved` is called when the window moves.
|
- `WindowBehavior::moved` is called when the window moves.
|
||||||
- `RunningWindow::outer_size` is a new function that returns the window's
|
- `RunningWindow::outer_size` is a new function that returns the window's
|
||||||
current size including decorations.
|
current size including decorations.
|
||||||
|
- `App::prevent_shutdown()` returns a guard that prevents the application from
|
||||||
|
closing automatically when the final window is closed.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
|
|
||||||
80
src/lib.rs
80
src/lib.rs
|
|
@ -325,6 +325,14 @@ where
|
||||||
ExecutingApp::new(&self.running.windows, event_loop),
|
ExecutingApp::new(&self.running.windows, event_loop),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
EventLoopMessage::PreventShutdown => {
|
||||||
|
self.running.windows.prevent_shutdown();
|
||||||
|
}
|
||||||
|
EventLoopMessage::AllowShutdown => {
|
||||||
|
if self.running.windows.allow_shutdown() {
|
||||||
|
exit(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -365,6 +373,20 @@ where
|
||||||
.ok()?;
|
.ok()?;
|
||||||
response_receiver.recv().ok()
|
response_receiver.recv().ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a guard that prevents this app from shutting down.
|
||||||
|
///
|
||||||
|
/// If the app is not currently running, this function returns None.
|
||||||
|
///
|
||||||
|
/// Once a guard is allocated the app will not be closed automatically when
|
||||||
|
/// the final window is closed. If the final shutdown guard is dropped while
|
||||||
|
/// no windows are open, the app will be closed.
|
||||||
|
pub fn prevent_shutdown(&self) -> Option<ShutdownGuard<AppMessage>> {
|
||||||
|
self.proxy
|
||||||
|
.send_event(EventLoopMessage::PreventShutdown)
|
||||||
|
.ok()
|
||||||
|
.map(|()| ShutdownGuard { app: self.clone() })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<AppMessage> Clone for App<AppMessage>
|
impl<AppMessage> Clone for App<AppMessage>
|
||||||
|
|
@ -540,13 +562,27 @@ where
|
||||||
|
|
||||||
/// A collection of open windows.
|
/// A collection of open windows.
|
||||||
pub struct Windows<Message> {
|
pub struct Windows<Message> {
|
||||||
data: Arc<Mutex<HashMap<WindowId, OpenWindow<Message>>>>,
|
data: Arc<Mutex<WindowsData<Message>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct WindowsData<Message> {
|
||||||
|
open: HashMap<WindowId, OpenWindow<Message>>,
|
||||||
|
guards: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Message> WindowsData<Message> {
|
||||||
|
fn should_shutdown(&self) -> bool {
|
||||||
|
self.open.is_empty() && self.guards == 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Message> Default for Windows<Message> {
|
impl<Message> Default for Windows<Message> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
data: Arc::default(),
|
data: Arc::new(Mutex::new(WindowsData {
|
||||||
|
open: HashMap::new(),
|
||||||
|
guards: 0,
|
||||||
|
})),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -564,7 +600,7 @@ impl<Message> Windows<Message> {
|
||||||
/// been opened and is still open.
|
/// been opened and is still open.
|
||||||
pub fn get(&self, id: WindowId) -> Option<Arc<winit::window::Window>> {
|
pub fn get(&self, id: WindowId) -> Option<Arc<winit::window::Window>> {
|
||||||
let windows = self.data.lock().unwrap_or_else(PoisonError::into_inner);
|
let windows = self.data.lock().unwrap_or_else(PoisonError::into_inner);
|
||||||
windows.get(&id).and_then(|w| w.winit.winit())
|
windows.open.get(&id).and_then(|w| w.winit.winit())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
|
|
@ -626,7 +662,7 @@ impl<Message> Windows<Message> {
|
||||||
let id = winit.id();
|
let id = winit.id();
|
||||||
let winit = OpenedWindow(Arc::new(Mutex::new(Some(winit))));
|
let winit = OpenedWindow(Arc::new(Mutex::new(Some(winit))));
|
||||||
let mut windows = self.data.lock().unwrap_or_else(PoisonError::into_inner);
|
let mut windows = self.data.lock().unwrap_or_else(PoisonError::into_inner);
|
||||||
windows.insert(
|
windows.open.insert(
|
||||||
id,
|
id,
|
||||||
OpenWindow {
|
OpenWindow {
|
||||||
winit: winit.clone(),
|
winit: winit.clone(),
|
||||||
|
|
@ -638,7 +674,7 @@ impl<Message> Windows<Message> {
|
||||||
|
|
||||||
fn send(&self, window: WindowId, message: WindowMessage<Message>) {
|
fn send(&self, window: WindowId, message: WindowMessage<Message>) {
|
||||||
let mut data = self.data.lock().unwrap_or_else(PoisonError::into_inner);
|
let mut data = self.data.lock().unwrap_or_else(PoisonError::into_inner);
|
||||||
if let Some(open_window) = data.get(&window) {
|
if let Some(open_window) = data.open.get(&window) {
|
||||||
match open_window.sender.try_send(message) {
|
match open_window.sender.try_send(message) {
|
||||||
Ok(()) => {}
|
Ok(()) => {}
|
||||||
Err(mpsc::TrySendError::Full(_)) => {
|
Err(mpsc::TrySendError::Full(_)) => {
|
||||||
|
|
@ -646,7 +682,7 @@ impl<Message> Windows<Message> {
|
||||||
}
|
}
|
||||||
Err(mpsc::TrySendError::Disconnected(_)) => {
|
Err(mpsc::TrySendError::Disconnected(_)) => {
|
||||||
// Window no longer active, remove it.
|
// Window no longer active, remove it.
|
||||||
data.remove(&window);
|
data.open.remove(&window);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -654,10 +690,21 @@ impl<Message> Windows<Message> {
|
||||||
|
|
||||||
fn close(&self, window: WindowId) -> bool {
|
fn close(&self, window: WindowId) -> bool {
|
||||||
let mut data = self.data.lock().unwrap_or_else(PoisonError::into_inner);
|
let mut data = self.data.lock().unwrap_or_else(PoisonError::into_inner);
|
||||||
if let Some(closed) = data.remove(&window) {
|
if let Some(closed) = data.open.remove(&window) {
|
||||||
closed.winit.close();
|
closed.winit.close();
|
||||||
}
|
}
|
||||||
data.is_empty()
|
data.should_shutdown()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prevent_shutdown(&self) {
|
||||||
|
let mut data = self.data.lock().unwrap_or_else(PoisonError::into_inner);
|
||||||
|
data.guards += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn allow_shutdown(&self) -> bool {
|
||||||
|
let mut data = self.data.lock().unwrap_or_else(PoisonError::into_inner);
|
||||||
|
data.guards -= 1;
|
||||||
|
data.should_shutdown()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -665,3 +712,20 @@ struct OpenWindow<User> {
|
||||||
winit: OpenedWindow,
|
winit: OpenedWindow,
|
||||||
sender: Arc<mpsc::SyncSender<WindowMessage<User>>>,
|
sender: Arc<mpsc::SyncSender<WindowMessage<User>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A guard preventing an [`App`] from shutting down.
|
||||||
|
pub struct ShutdownGuard<Message>
|
||||||
|
where
|
||||||
|
Message: crate::Message,
|
||||||
|
{
|
||||||
|
app: App<Message>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Message> Drop for ShutdownGuard<Message>
|
||||||
|
where
|
||||||
|
Message: crate::Message,
|
||||||
|
{
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let _ = self.app.proxy.send_event(EventLoopMessage::AllowShutdown);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,8 @@ where
|
||||||
message: AppMessage,
|
message: AppMessage,
|
||||||
response_sender: mpsc::SyncSender<AppMessage::Response>,
|
response_sender: mpsc::SyncSender<AppMessage::Response>,
|
||||||
},
|
},
|
||||||
|
PreventShutdown,
|
||||||
|
AllowShutdown,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue