Added the keep_running builder to prevent the event loop from stopping when no windows are open

This commit is contained in:
Laurent Stéphenne 2025-08-20 00:32:19 -04:00
parent d273aca1c1
commit 0bbb6c0f25
No known key found for this signature in database
GPG key ID: 1F1C47D520393678
7 changed files with 36 additions and 6 deletions

View file

@ -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<F>(self, on_finish_launching: F)

View file

@ -232,6 +232,7 @@ pub(crate) trait Platform: 'static {
fn on_quit(&self, callback: Box<dyn FnMut()>);
fn on_reopen(&self, callback: Box<dyn FnMut()>);
fn on_keyboard_layout_change(&self, callback: Box<dyn FnMut()>);
fn set_quit_when_last_window_closes(&self, should_quit: bool);
fn set_menus(&self, menus: Vec<Menu>, keymap: &Keymap);
fn get_menus(&self) -> Option<Vec<OwnedMenu>> {

View file

@ -92,6 +92,7 @@ pub(crate) struct LinuxCommon {
pub(crate) text_system: Arc<dyn PlatformTextSystem>,
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<OwnedMenu>,
@ -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<P: LinuxClient + 'static> 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<dyn FnOnce()>) {
on_finish_launching();

View file

@ -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();
}
}

View file

@ -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();
}
}

View file

@ -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<dyn FnMut(&dyn Action)>) {
self.0.lock().menu_command = Some(callback);
}

View file

@ -51,6 +51,7 @@ pub(crate) struct WindowsPlatformState {
callbacks: PlatformCallbacks,
menus: Vec<OwnedMenu>,
jump_list: JumpList,
quit_when_last_window_closes: bool,
// NOTE: standard cursor handles don't need to close.
pub(crate) current_cursor: Option<HCURSOR>,
}
@ -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<dyn 'static + FnOnce()>) {
on_finish_launching();
self.begin_vsync_thread();