Skip to content

Commit ae4fa74

Browse files
committed
fix: skip about:blank when revealing startup window
macOS cert-bypass starts on about:blank before the real URL. Treating that Finished event as ready would re-show a blank shell and consume the once-reveal latch. Wait for a non-about document, with tests locking the guard.
1 parent 5d68417 commit ae4fa74

2 files changed

Lines changed: 51 additions & 6 deletions

File tree

src-tauri/src/lib.rs

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@ use std::sync::{
66
atomic::{AtomicBool, Ordering},
77
Arc,
88
};
9-
use tauri::{webview::PageLoadEvent, Manager, WebviewWindow};
9+
use tauri::{webview::PageLoadEvent, Manager, Url, WebviewWindow};
1010
use tauri_plugin_window_state::Builder as WindowStatePlugin;
1111
use tauri_plugin_window_state::StateFlags;
1212

1313
#[cfg(target_os = "macos")]
1414
use std::time::Duration;
1515

16+
// Fallback when PageLoadEvent::Finished never arrives (offline / stalled).
17+
// Deliberately longer than a paint tick so the normal path can win first.
1618
const STARTUP_WINDOW_FALLBACK_DELAY: u64 = 3_000;
1719
#[cfg(target_os = "linux")]
1820
const PAKE_LINUX_WEBKIT_SAFE_MODE: &str = "PAKE_LINUX_WEBKIT_SAFE_MODE";
@@ -33,6 +35,13 @@ use app::{
3335
};
3436
use util::get_pake_config;
3537

38+
/// Placeholder documents used before the real target URL navigates (e.g. macOS
39+
/// cert-bypass starts on about:blank). Revealing on these would reintroduce the
40+
/// blank-window flash the page-load gate is meant to prevent.
41+
fn is_placeholder_startup_url(url: &Url) -> bool {
42+
url.scheme().eq_ignore_ascii_case("about")
43+
}
44+
3645
fn reveal_startup_window(window: WebviewWindow, init_fullscreen: bool, revealed: &Arc<AtomicBool>) {
3746
if revealed.swap(true, Ordering::AcqRel) {
3847
return;
@@ -221,13 +230,26 @@ pub fn run_app() {
221230
));
222231
}
223232

233+
// Reveal the main window after the first real document finishes loading so
234+
// slow WKWebView cold starts do not expose an empty but interactive shell.
235+
// start_to_tray keeps the window hidden for the whole session until the user
236+
// opens it from the tray / shortcut.
224237
if !start_to_tray {
225238
let page_load_revealed = startup_window_revealed.clone();
226239
app_builder = app_builder.on_page_load(move |webview, payload| {
227-
if webview.label() == "pake" && matches!(payload.event(), PageLoadEvent::Finished) {
228-
if let Some(window) = webview.app_handle().get_webview_window("pake") {
229-
reveal_startup_window(window, init_fullscreen, &page_load_revealed);
230-
}
240+
if webview.label() != "pake" {
241+
return;
242+
}
243+
if !matches!(payload.event(), PageLoadEvent::Finished) {
244+
return;
245+
}
246+
// Skip about:blank (and other about: placeholders) used by the macOS
247+
// cert-bypass path before the real target URL navigates.
248+
if is_placeholder_startup_url(payload.url()) {
249+
return;
250+
}
251+
if let Some(window) = webview.app_handle().get_webview_window("pake") {
252+
reveal_startup_window(window, init_fullscreen, &page_load_revealed);
231253
}
232254
});
233255
}
@@ -352,6 +374,19 @@ pub fn run() {
352374
mod tests {
353375
use super::*;
354376

377+
#[test]
378+
fn placeholder_startup_urls_cover_about_blank() {
379+
let blank: Url = "about:blank".parse().unwrap();
380+
let srcdoc: Url = "about:srcdoc".parse().unwrap();
381+
let https: Url = "https://github.com/".parse().unwrap();
382+
let tauri: Url = "tauri://localhost/".parse().unwrap();
383+
384+
assert!(is_placeholder_startup_url(&blank));
385+
assert!(is_placeholder_startup_url(&srcdoc));
386+
assert!(!is_placeholder_startup_url(&https));
387+
assert!(!is_placeholder_startup_url(&tauri));
388+
}
389+
355390
#[test]
356391
fn linux_webkit_safe_mode_stays_on_by_default() {
357392
assert!(should_enable_linux_webkit_safe_mode_from_values(

tests/unit/startup-window-reveal.test.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,24 @@ const libSource = fs.readFileSync(
88
);
99

1010
describe('startup window reveal', () => {
11-
it('waits for the initial page to finish instead of exposing a blank webview', () => {
11+
it('waits for the first real page finish instead of a fixed short delay', () => {
1212
expect(libSource).toContain('.on_page_load(');
1313
expect(libSource).toContain('PageLoadEvent::Finished');
1414
expect(libSource).toContain('revealed.swap(true');
1515
expect(libSource).toContain('STARTUP_WINDOW_FALLBACK_DELAY');
16+
expect(libSource).toContain('is_placeholder_startup_url');
1617
expect(libSource).toMatch(
1718
/if !start_to_tray \{[\s\S]*?app_builder = app_builder\.on_page_load/,
1819
);
1920
expect(libSource).not.toContain('WINDOW_SHOW_DELAY');
2021
});
22+
23+
it('does not treat about:blank as a ready first paint', () => {
24+
expect(libSource).toMatch(
25+
/is_placeholder_startup_url\(payload\.url\(\)\)/,
26+
);
27+
expect(libSource).toMatch(
28+
/url\.scheme\(\)\.eq_ignore_ascii_case\("about"\)/,
29+
);
30+
});
2131
});

0 commit comments

Comments
 (0)