From 0bbb6c0f251170ad81aafc687a116fd38b4f9590 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laurent=20St=C3=A9phenne?= Date: Wed, 20 Aug 2025 00:32:19 -0400 Subject: [PATCH 1/2] Added the keep_running builder to prevent the event loop from stopping when no windows are open --- crates/gpui/src/app.rs | 14 ++++++++++++-- crates/gpui/src/platform.rs | 1 + crates/gpui/src/platform/linux/platform.rs | 6 ++++++ crates/gpui/src/platform/linux/wayland/client.rs | 5 +++-- crates/gpui/src/platform/linux/x11/client.rs | 2 +- crates/gpui/src/platform/mac/platform.rs | 6 ++++++ crates/gpui/src/platform/windows/platform.rs | 8 +++++++- 7 files changed, 36 insertions(+), 6 deletions(-) diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index bbd59fa7bc..1e6f97c534 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -39,8 +39,8 @@ use crate::{ Keymap, Keystroke, LayoutId, Menu, MenuItem, OwnedMenu, PathPromptOptions, Pixels, Platform, PlatformDisplay, PlatformKeyboardLayout, Point, PromptBuilder, PromptButton, PromptHandle, PromptLevel, Render, RenderImage, RenderablePromptHandle, Reservation, ScreenCaptureSource, - SubscriberSet, Subscription, SvgRenderer, Task, TextSystem, Window, WindowAppearance, - WindowHandle, WindowId, WindowInvalidator, + SubscriberSet, Subscription, SvgRenderer, Task, TextSystem, WaylandClient, Window, + WindowAppearance, WindowHandle, WindowId, WindowInvalidator, colors::{Colors, GlobalColors}, current_platform, hash, init_app_menus, }; @@ -168,6 +168,16 @@ impl Application { self } + /// Sets the behaviour of the event loop when all windows are closed. + pub fn keep_running(self, keep_running: bool) -> Self { + let mut context_lock = self.0.borrow_mut(); + context_lock + .platform + .set_quit_when_last_window_closes(!keep_running); + drop(context_lock); + self + } + /// Start the application. The provided callback will be called once the /// app is fully launched. pub fn run(self, on_finish_launching: F) diff --git a/crates/gpui/src/platform.rs b/crates/gpui/src/platform.rs index 1df8a608f4..7a4b903a8f 100644 --- a/crates/gpui/src/platform.rs +++ b/crates/gpui/src/platform.rs @@ -232,6 +232,7 @@ pub(crate) trait Platform: 'static { fn on_quit(&self, callback: Box); fn on_reopen(&self, callback: Box); fn on_keyboard_layout_change(&self, callback: Box); + fn set_quit_when_last_window_closes(&self, should_quit: bool); fn set_menus(&self, menus: Vec, keymap: &Keymap); fn get_menus(&self) -> Option> { diff --git a/crates/gpui/src/platform/linux/platform.rs b/crates/gpui/src/platform/linux/platform.rs index ed824744a9..12713d219c 100644 --- a/crates/gpui/src/platform/linux/platform.rs +++ b/crates/gpui/src/platform/linux/platform.rs @@ -92,6 +92,7 @@ pub(crate) struct LinuxCommon { pub(crate) text_system: Arc, pub(crate) appearance: WindowAppearance, pub(crate) auto_hide_scrollbars: bool, + pub(crate) quit_when_last_window_closes: bool, pub(crate) callbacks: PlatformHandlers, pub(crate) signal: LoopSignal, pub(crate) menus: Vec, @@ -118,6 +119,7 @@ impl LinuxCommon { text_system, appearance: WindowAppearance::Light, auto_hide_scrollbars: false, + quit_when_last_window_closes: true, callbacks, signal, menus: Vec::new(), @@ -148,6 +150,10 @@ impl Platform for P { self.with_common(|common| common.callbacks.keyboard_layout_change = Some(callback)); } + fn set_quit_when_last_window_closes(&self, should_quit: bool) { + self.with_common(|common| common.quit_when_last_window_closes = should_quit); + } + fn run(&self, on_finish_launching: Box) { on_finish_launching(); diff --git a/crates/gpui/src/platform/linux/wayland/client.rs b/crates/gpui/src/platform/linux/wayland/client.rs index 4d31428094..5586684d6a 100644 --- a/crates/gpui/src/platform/linux/wayland/client.rs +++ b/crates/gpui/src/platform/linux/wayland/client.rs @@ -353,7 +353,7 @@ impl WaylandClientStatePtr { } changed } else { - let changed = &UNKNOWN_KEYBOARD_LAYOUT_NAME != state.keyboard_layout.name(); + let changed: bool = &UNKNOWN_KEYBOARD_LAYOUT_NAME != state.keyboard_layout.name(); if changed { state.keyboard_layout = LinuxKeyboardLayout::new(UNKNOWN_KEYBOARD_LAYOUT_NAME); } @@ -383,7 +383,8 @@ impl WaylandClientStatePtr { { state.keyboard_focused_window = Some(window); } - if state.windows.is_empty() { + + if state.common.quit_when_last_window_closes && state.windows.is_empty() { state.common.signal.stop(); } } diff --git a/crates/gpui/src/platform/linux/x11/client.rs b/crates/gpui/src/platform/linux/x11/client.rs index 346ba8718b..da7d210714 100644 --- a/crates/gpui/src/platform/linux/x11/client.rs +++ b/crates/gpui/src/platform/linux/x11/client.rs @@ -247,7 +247,7 @@ impl X11ClientStatePtr { } state.cursor_styles.remove(&x_window); - if state.windows.is_empty() { + if state.common.quit_when_last_window_closes && state.windows.is_empty() { state.common.signal.stop(); } } diff --git a/crates/gpui/src/platform/mac/platform.rs b/crates/gpui/src/platform/mac/platform.rs index 832550dc46..c1f8895982 100644 --- a/crates/gpui/src/platform/mac/platform.rs +++ b/crates/gpui/src/platform/mac/platform.rs @@ -208,6 +208,7 @@ impl MacPlatform { finish_launching: None, dock_menu: None, on_keyboard_layout_change: None, + quit_when_last_window_closes: false, menus: None, })) } @@ -866,6 +867,11 @@ impl Platform for MacPlatform { self.0.lock().on_keyboard_layout_change = Some(callback); } + fn set_quit_when_last_window_closes(&self, should_quit: bool) { + self.0.lock().quit_when_last_window_closes = should_quit; + unimplemented!("quit_when_last_window_closes is not implemented on macOS yet"); + } + fn on_app_menu_action(&self, callback: Box) { self.0.lock().menu_command = Some(callback); } diff --git a/crates/gpui/src/platform/windows/platform.rs b/crates/gpui/src/platform/windows/platform.rs index b13b9915f1..f24fc77159 100644 --- a/crates/gpui/src/platform/windows/platform.rs +++ b/crates/gpui/src/platform/windows/platform.rs @@ -51,6 +51,7 @@ pub(crate) struct WindowsPlatformState { callbacks: PlatformCallbacks, menus: Vec, jump_list: JumpList, + quit_when_last_window_closes: bool, // NOTE: standard cursor handles don't need to close. pub(crate) current_cursor: Option, } @@ -77,6 +78,7 @@ impl WindowsPlatformState { jump_list, current_cursor, menus: Vec::new(), + quit_when_last_window_closes: true, } } } @@ -160,7 +162,7 @@ impl WindowsPlatform { .unwrap(); lock.remove(index); - lock.is_empty() + self.state.borrow().quit_when_last_window_closes && lock.is_empty() } #[inline] @@ -354,6 +356,10 @@ impl Platform for WindowsPlatform { self.state.borrow_mut().callbacks.keyboard_layout_change = Some(callback); } + fn set_quit_when_last_window_closes(&self, should_quit: bool) { + self.state.borrow_mut().quit_when_last_window_closes = should_quit; + } + fn run(&self, on_finish_launching: Box) { on_finish_launching(); self.begin_vsync_thread(); From 9250d1bb0dac8515c41a8fc19e7c665e9ee09926 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laurent=20St=C3=A9phenne?= Date: Tue, 26 Aug 2025 00:15:36 -0400 Subject: [PATCH 2/2] Fixes --- crates/gpui/src/app.rs | 7 +++---- crates/gpui/src/platform/linux/wayland/client.rs | 2 +- crates/gpui/src/platform/mac/platform.rs | 1 + 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 1e6f97c534..48760dccf5 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -32,6 +32,7 @@ use util::{ResultExt, debug_panic}; #[cfg(any(feature = "inspector", debug_assertions))] use crate::InspectorElementRegistry; +use crate::colors::{Colors, GlobalColors}; use crate::{ Action, ActionBuildError, ActionRegistry, Any, AnyView, AnyWindowHandle, AppContext, Asset, AssetSource, BackgroundExecutor, Bounds, ClipboardItem, CursorStyle, DispatchPhase, DisplayId, @@ -39,10 +40,8 @@ use crate::{ Keymap, Keystroke, LayoutId, Menu, MenuItem, OwnedMenu, PathPromptOptions, Pixels, Platform, PlatformDisplay, PlatformKeyboardLayout, Point, PromptBuilder, PromptButton, PromptHandle, PromptLevel, Render, RenderImage, RenderablePromptHandle, Reservation, ScreenCaptureSource, - SubscriberSet, Subscription, SvgRenderer, Task, TextSystem, WaylandClient, Window, - WindowAppearance, WindowHandle, WindowId, WindowInvalidator, - colors::{Colors, GlobalColors}, - current_platform, hash, init_app_menus, + SubscriberSet, Subscription, SvgRenderer, Task, TextSystem, Window, WindowAppearance, + WindowHandle, WindowId, WindowInvalidator, current_platform, hash, init_app_menus, }; mod async_context; diff --git a/crates/gpui/src/platform/linux/wayland/client.rs b/crates/gpui/src/platform/linux/wayland/client.rs index 5586684d6a..aae2b98f2e 100644 --- a/crates/gpui/src/platform/linux/wayland/client.rs +++ b/crates/gpui/src/platform/linux/wayland/client.rs @@ -353,7 +353,7 @@ impl WaylandClientStatePtr { } changed } else { - let changed: bool = &UNKNOWN_KEYBOARD_LAYOUT_NAME != state.keyboard_layout.name(); + let changed = &UNKNOWN_KEYBOARD_LAYOUT_NAME != state.keyboard_layout.name(); if changed { state.keyboard_layout = LinuxKeyboardLayout::new(UNKNOWN_KEYBOARD_LAYOUT_NAME); } diff --git a/crates/gpui/src/platform/mac/platform.rs b/crates/gpui/src/platform/mac/platform.rs index c1f8895982..51aef802df 100644 --- a/crates/gpui/src/platform/mac/platform.rs +++ b/crates/gpui/src/platform/mac/platform.rs @@ -162,6 +162,7 @@ pub(crate) struct MacPlatformState { metadata_pasteboard_type: id, reopen: Option>, on_keyboard_layout_change: Option>, + quit_when_last_window_closes: bool, quit: Option>, menu_command: Option>, validate_menu_command: Option bool>>,