Skip to content

Commit 112b5c1

Browse files
authored
Add QuitMode policy to GPUI (#42391)
Applications can select a policy for when the app quits using the new function `Application::with_quit_mode`: - Only on explicit calls to `App::quit` - When the last window is closed - Platform default (former on macOS, latter everywhere else) Release Notes: - N/A
1 parent 32ec103 commit 112b5c1

File tree

2 files changed

+64
-25
lines changed

2 files changed

+64
-25
lines changed

crates/gpui/src/app.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,13 @@ impl Application {
169169
self
170170
}
171171

172+
/// Configures when the application should automatically quit.
173+
/// By default, [`QuitMode::Default`] is used.
174+
pub fn with_quit_mode(self, mode: QuitMode) -> Self {
175+
self.0.borrow_mut().quit_mode = mode;
176+
self
177+
}
178+
172179
/// Start the application. The provided callback will be called once the
173180
/// app is fully launched.
174181
pub fn run<F>(self, on_finish_launching: F)
@@ -238,6 +245,18 @@ type WindowClosedHandler = Box<dyn FnMut(&mut App)>;
238245
type ReleaseListener = Box<dyn FnOnce(&mut dyn Any, &mut App) + 'static>;
239246
type NewEntityListener = Box<dyn FnMut(AnyEntity, &mut Option<&mut Window>, &mut App) + 'static>;
240247

248+
/// Defines when the application should automatically quit.
249+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
250+
pub enum QuitMode {
251+
/// Use [`QuitMode::Explicit`] on macOS and [`QuitMode::LastWindowClosed`] on other platforms.
252+
#[default]
253+
Default,
254+
/// Quit automatically when the last window is closed.
255+
LastWindowClosed,
256+
/// Quit only when requested via [`App::quit`].
257+
Explicit,
258+
}
259+
241260
#[doc(hidden)]
242261
#[derive(Clone, PartialEq, Eq)]
243262
pub struct SystemWindowTab {
@@ -588,6 +607,7 @@ pub struct App {
588607
pub(crate) inspector_element_registry: InspectorElementRegistry,
589608
#[cfg(any(test, feature = "test-support", debug_assertions))]
590609
pub(crate) name: Option<&'static str>,
610+
quit_mode: QuitMode,
591611
quitting: bool,
592612
}
593613

@@ -659,6 +679,7 @@ impl App {
659679
inspector_renderer: None,
660680
#[cfg(any(feature = "inspector", debug_assertions))]
661681
inspector_element_registry: InspectorElementRegistry::default(),
682+
quit_mode: QuitMode::default(),
662683
quitting: false,
663684

664685
#[cfg(any(test, feature = "test-support", debug_assertions))]
@@ -1172,6 +1193,12 @@ impl App {
11721193
self.http_client = new_client;
11731194
}
11741195

1196+
/// Configures when the application should automatically quit.
1197+
/// By default, [`QuitMode::Default`] is used.
1198+
pub fn set_quit_mode(&mut self, mode: QuitMode) {
1199+
self.quit_mode = mode;
1200+
}
1201+
11751202
/// Returns the SVG renderer used by the application.
11761203
pub fn svg_renderer(&self) -> SvgRenderer {
11771204
self.svg_renderer.clone()
@@ -1379,6 +1406,16 @@ impl App {
13791406
callback(cx);
13801407
true
13811408
});
1409+
1410+
let quit_on_empty = match cx.quit_mode {
1411+
QuitMode::Explicit => false,
1412+
QuitMode::LastWindowClosed => true,
1413+
QuitMode::Default => !cfg!(macos),
1414+
};
1415+
1416+
if quit_on_empty && cx.windows.is_empty() {
1417+
cx.quit();
1418+
}
13821419
} else {
13831420
cx.windows.get_mut(id)?.replace(window);
13841421
}

crates/zed/src/main.rs

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use extension::ExtensionHostProxy;
1515
use fs::{Fs, RealFs};
1616
use futures::{StreamExt, channel::oneshot, future};
1717
use git::GitHostingProviderRegistry;
18-
use gpui::{App, AppContext, Application, AsyncApp, Focusable as _, UpdateGlobal as _};
18+
use gpui::{App, AppContext, Application, AsyncApp, Focusable as _, QuitMode, UpdateGlobal as _};
1919

2020
use gpui_tokio::Tokio;
2121
use language::LanguageRegistry;
@@ -87,31 +87,33 @@ fn files_not_created_on_launch(errors: HashMap<io::ErrorKind, Vec<&Path>>) {
8787
.collect::<Vec<_>>().join("\n\n");
8888

8989
eprintln!("{message}: {error_details}");
90-
Application::new().run(move |cx| {
91-
if let Ok(window) = cx.open_window(gpui::WindowOptions::default(), |_, cx| {
92-
cx.new(|_| gpui::Empty)
93-
}) {
94-
window
95-
.update(cx, |_, window, cx| {
96-
let response = window.prompt(
97-
gpui::PromptLevel::Critical,
98-
message,
99-
Some(&error_details),
100-
&["Exit"],
101-
cx,
102-
);
103-
104-
cx.spawn_in(window, async move |_, cx| {
105-
response.await?;
106-
cx.update(|_, cx| cx.quit())
90+
Application::new()
91+
.with_quit_mode(QuitMode::Explicit)
92+
.run(move |cx| {
93+
if let Ok(window) = cx.open_window(gpui::WindowOptions::default(), |_, cx| {
94+
cx.new(|_| gpui::Empty)
95+
}) {
96+
window
97+
.update(cx, |_, window, cx| {
98+
let response = window.prompt(
99+
gpui::PromptLevel::Critical,
100+
message,
101+
Some(&error_details),
102+
&["Exit"],
103+
cx,
104+
);
105+
106+
cx.spawn_in(window, async move |_, cx| {
107+
response.await?;
108+
cx.update(|_, cx| cx.quit())
109+
})
110+
.detach_and_log_err(cx);
107111
})
108-
.detach_and_log_err(cx);
109-
})
110-
.log_err();
111-
} else {
112-
fail_to_open_window(anyhow::anyhow!("{message}: {error_details}"), cx)
113-
}
114-
})
112+
.log_err();
113+
} else {
114+
fail_to_open_window(anyhow::anyhow!("{message}: {error_details}"), cx)
115+
}
116+
})
115117
}
116118

117119
fn fail_to_open_window_async(e: anyhow::Error, cx: &mut AsyncApp) {

0 commit comments

Comments
 (0)