fix: preserve GPUI lifetime and avoid WASAPI silence warnings

This commit is contained in:
2026-10-13 18:58:37 +02:00
parent d065ad7775
commit 072a4ab7ca
17 changed files with 470 additions and 188 deletions
+14
View File
@@ -0,0 +1,14 @@
# Clipbin GPUI 0.2.2 patch
Baseline: crates.io gpui 0.2.2, checksum
`979b45cfa6ec723b6f42330915a1b3769b930d02b2d505f9697f8ca602bee707`.
Original Apache-2.0 license retained. This dependency is excluded from Clipbin's
workspace; its existing third-party unsafe code is unchanged.
`clipbin-background.patch` is the complete source delta from the published
crate (zero-context unified diff; apply with `patch -p1` or
`git apply --unidiff-zero`). It adds App::set_quit_on_last_window_close and an initially true backend
flag on Wayland, X11 and Windows. Clipbin sets it false so one Application/loop
lives until explicit Quit, while visible windows can be destroyed/recreated.
No timers, dispatchers or FFI calls are changed. Two taffy float literals
are explicitly typed f32 to satisfy Rust 1.98 strict clippy.
+55
View File
@@ -0,0 +1,55 @@
--- a/src/app.rs
+++ b/src/app.rs
@@ -982,0 +983,5 @@
+ /// Keep the native loop alive when the last window closes (for tray apps).
+ pub fn set_quit_on_last_window_close(&self, quit: bool) {
+ self.platform.set_quit_on_last_window_close(quit);
+ }
+
--- a/src/platform/linux/platform.rs
+++ b/src/platform/linux/platform.rs
@@ -96,0 +97 @@
+ pub quit_on_last_window_close: bool,
@@ -122,0 +124 @@
+ quit_on_last_window_close: true,
@@ -232,0 +235,4 @@
+ }
+
+ fn set_quit_on_last_window_close(&self, quit: bool) {
+ self.with_common(|common| common.quit_on_last_window_close = quit);
--- a/src/platform/linux/wayland/client.rs
+++ b/src/platform/linux/wayland/client.rs
@@ -387 +387 @@
- if state.windows.is_empty() {
+ if state.windows.is_empty() && state.common.quit_on_last_window_close {
--- a/src/platform/linux/x11/client.rs
+++ b/src/platform/linux/x11/client.rs
@@ -250 +250 @@
- if state.windows.is_empty() {
+ if state.windows.is_empty() && state.common.quit_on_last_window_close {
--- a/src/platform/windows/platform.rs
+++ b/src/platform/windows/platform.rs
@@ -2 +2 @@
- cell::RefCell,
+ cell::{Cell, RefCell},
@@ -45,0 +46 @@
+ quit_on_last_window_close: Cell<bool>,
@@ -369,0 +371,4 @@
+ fn set_quit_on_last_window_close(&self, quit: bool) {
+ self.inner.quit_on_last_window_close.set(quit);
+ }
+
@@ -682,0 +688 @@
+ quit_on_last_window_close: Cell::new(true),
@@ -744 +750 @@
- lock.is_empty()
+ lock.is_empty() && self.quit_on_last_window_close.get()
--- a/src/platform.rs
+++ b/src/platform.rs
@@ -171,0 +172 @@
+ fn set_quit_on_last_window_close(&self, _quit: bool) {}
--- a/src/taffy.rs
+++ b/src/taffy.rs
@@ -312 +312 @@
- unit.map(|count| vec![repeat(count, vec![minmax(length(0.0), fr(1.0))])])
+ unit.map(|count| vec![repeat(count, vec![minmax(length(0.0_f32), fr(1.0_f32))])])
+5
View File
@@ -980,6 +980,11 @@ impl App {
self.platform.activate(ignoring_other_apps);
}
/// Keep the native loop alive when the last window closes (for tray apps).
pub fn set_quit_on_last_window_close(&self, quit: bool) {
self.platform.set_quit_on_last_window_close(quit);
}
/// Hide the application at the platform level.
pub fn hide(&self) {
self.platform.hide();
+1
View File
@@ -169,6 +169,7 @@ pub(crate) trait Platform: 'static {
fn quit(&self);
fn restart(&self, binary_path: Option<PathBuf>);
fn activate(&self, ignoring_other_apps: bool);
fn set_quit_on_last_window_close(&self, _quit: bool) {}
fn hide(&self);
fn hide_other_apps(&self);
fn unhide_other_apps(&self);
+6
View File
@@ -94,6 +94,7 @@ pub(crate) struct PlatformHandlers {
}
pub(crate) struct LinuxCommon {
pub quit_on_last_window_close: bool,
pub(crate) background_executor: BackgroundExecutor,
pub(crate) foreground_executor: ForegroundExecutor,
pub(crate) text_system: Arc<dyn PlatformTextSystem>,
@@ -120,6 +121,7 @@ impl LinuxCommon {
let background_executor = BackgroundExecutor::new(dispatcher.clone());
let common = LinuxCommon {
quit_on_last_window_close: true,
background_executor,
foreground_executor: ForegroundExecutor::new(dispatcher),
text_system,
@@ -232,6 +234,10 @@ impl<P: LinuxClient + 'static> Platform for P {
log::info!("activate is not implemented on Linux, ignoring the call")
}
fn set_quit_on_last_window_close(&self, quit: bool) {
self.with_common(|common| common.quit_on_last_window_close = quit);
}
fn hide(&self) {
log::info!("hide is not implemented on Linux, ignoring the call")
}
+1 -1
View File
@@ -384,7 +384,7 @@ impl WaylandClientStatePtr {
{
state.keyboard_focused_window = Some(window);
}
if state.windows.is_empty() {
if state.windows.is_empty() && state.common.quit_on_last_window_close {
state.common.signal.stop();
}
}
+1 -1
View File
@@ -247,7 +247,7 @@ impl X11ClientStatePtr {
}
state.cursor_styles.remove(&x_window);
if state.windows.is_empty() {
if state.windows.is_empty() && state.common.quit_on_last_window_close {
state.common.signal.stop();
}
}
+8 -2
View File
@@ -1,5 +1,5 @@
use std::{
cell::RefCell,
cell::{Cell, RefCell},
ffi::OsStr,
mem::ManuallyDrop,
path::{Path, PathBuf},
@@ -43,6 +43,7 @@ pub(crate) struct WindowsPlatform {
}
struct WindowsPlatformInner {
quit_on_last_window_close: Cell<bool>,
state: RefCell<WindowsPlatformState>,
raw_window_handles: std::sync::Weak<RwLock<SmallVec<[SafeHwnd; 4]>>>,
// The below members will never change throughout the entire lifecycle of the app.
@@ -367,6 +368,10 @@ impl Platform for WindowsPlatform {
fn activate(&self, _ignoring_other_apps: bool) {}
fn set_quit_on_last_window_close(&self, quit: bool) {
self.inner.quit_on_last_window_close.set(quit);
}
fn hide(&self) {}
// todo(windows)
@@ -680,6 +685,7 @@ impl WindowsPlatformInner {
context.directx_devices.take().unwrap(),
));
Ok(Rc::new(Self {
quit_on_last_window_close: Cell::new(true),
state,
raw_window_handles: context.raw_window_handles.clone(),
validation_number: context.validation_number,
@@ -741,7 +747,7 @@ impl WindowsPlatformInner {
.unwrap();
lock.remove(index);
lock.is_empty()
lock.is_empty() && self.quit_on_last_window_close.get()
}
#[inline]
+1 -1
View File
@@ -309,7 +309,7 @@ impl ToTaffy<taffy::style::Style> for Style {
unit: &Option<u16>,
) -> Vec<taffy::GridTemplateComponent<T>> {
// grid-template-columns: repeat(<number>, minmax(0, 1fr));
unit.map(|count| vec![repeat(count, vec![minmax(length(0.0), fr(1.0))])])
unit.map(|count| vec![repeat(count, vec![minmax(length(0.0_f32), fr(1.0_f32))])])
.unwrap_or_default()
}