forked from akai/readest
fix(macos): minimize instead of hide on macOS 26 to avoid black window (#4890)
On macOS 26 (Tahoe), Apple regressed NSWindow ordering so that orderOut: (what Tauri's hide() maps to) no longer removes the window from the screen. The close-to-hide handler left a focused black phantom window instead of hiding it, and the only recovery was to quit and relaunch the app. This is an OS-level regression, not a Readest bug: the same failure hits native, non-webview apps such as kitty (kovidgoyal/kitty#8952), and tao 0.34.8 calls a bare orderOut with no Tahoe workaround. Fix: on macOS 26 or later, minimize() the main window instead of hide(). Minimize is a different AppKit path that dodges the buggy orderOut, keeps the app in the dock, and preserves the open book. The existing Reopen handler already unminimizes on dock reopen, so no extra restore logic is needed. Older macOS keeps the previous hide() behavior. Version detection reads NSProcessInfo.operatingSystemVersion. Closes #4875 Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -574,7 +574,17 @@ pub fn run() {
|
||||
window.on_window_event(move |event| {
|
||||
if let tauri::WindowEvent::CloseRequested { api, .. } = event {
|
||||
api.prevent_close();
|
||||
let _ = window_for_close.hide();
|
||||
// macOS 26 (Tahoe) regressed `NSWindow` ordering: `orderOut:`
|
||||
// (what `hide()` maps to) can leave a focused black phantom
|
||||
// window on screen instead of hiding it (#4875). Minimize
|
||||
// instead on Tahoe — a different AppKit path that still keeps
|
||||
// the app in the dock and preserves the open book. The Reopen
|
||||
// handler below already unminimizes on dock reopen.
|
||||
if macos::os_version::is_macos_tahoe_or_later() {
|
||||
let _ = window_for_close.minimize();
|
||||
} else {
|
||||
let _ = window_for_close.hide();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
pub mod apple_auth;
|
||||
pub mod menu;
|
||||
pub mod os_version;
|
||||
pub mod safari_auth;
|
||||
pub mod system_dictionary;
|
||||
pub mod traffic_light;
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
//! macOS OS-version detection for the Tahoe close-to-hide workaround.
|
||||
//!
|
||||
//! macOS 26 (Tahoe) regressed `NSWindow` ordering so that `orderOut:` —
|
||||
//! which Tauri's `WebviewWindow::hide()` maps to — can leave a focused
|
||||
//! black phantom window on screen instead of hiding it. See issue #4875.
|
||||
//! On Tahoe we minimize the window instead, a different AppKit path that
|
||||
//! still keeps the app in the dock and preserves the open book.
|
||||
|
||||
use objc::{class, msg_send, sel, sel_impl};
|
||||
|
||||
/// Returns true when `major` is macOS Tahoe (26) or later.
|
||||
pub(crate) fn is_tahoe_or_later(major: i64) -> bool {
|
||||
major >= 26
|
||||
}
|
||||
|
||||
/// Reads the running macOS major version via `NSProcessInfo`.
|
||||
fn macos_major_version() -> i64 {
|
||||
#[repr(C)]
|
||||
struct NSOperatingSystemVersion {
|
||||
major: i64,
|
||||
minor: i64,
|
||||
patch: i64,
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let process_info: *mut objc::runtime::Object =
|
||||
msg_send![class!(NSProcessInfo), processInfo];
|
||||
let version: NSOperatingSystemVersion = msg_send![process_info, operatingSystemVersion];
|
||||
version.major
|
||||
}
|
||||
}
|
||||
|
||||
/// True when running on macOS Tahoe (26) or later.
|
||||
pub fn is_macos_tahoe_or_later() -> bool {
|
||||
is_tahoe_or_later(macos_major_version())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::is_tahoe_or_later;
|
||||
|
||||
#[test]
|
||||
fn detects_tahoe_and_later() {
|
||||
assert!(is_tahoe_or_later(26)); // Tahoe
|
||||
assert!(is_tahoe_or_later(27));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rejects_pre_tahoe() {
|
||||
assert!(!is_tahoe_or_later(25)); // Sequoia
|
||||
assert!(!is_tahoe_or_later(15)); // older numbering
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user