From 46323ce06b54cc81632d647bef91c1daa85f8a17 Mon Sep 17 00:00:00 2001 From: Ernest Badu <55922827+Ernxst@users.noreply.github.com> Date: Tue, 22 Sep 2026 00:32:43 +0100 Subject: [PATCH 1/2] fix: pump AppKit immediately after init The first frame-loop tick waited `frameMs` (8ms) before pumping AppKit, delaying the post-show occlusion pump that reports the window visible. Run the first idle tick synchronously instead of scheduling it. Co-Authored-By: Claude Opus 5 (1M context) --- packages/react/src/reconciler/renderer.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/react/src/reconciler/renderer.ts b/packages/react/src/reconciler/renderer.ts index 5add153d..aeaa22bd 100644 --- a/packages/react/src/reconciler/renderer.ts +++ b/packages/react/src/reconciler/renderer.ts @@ -186,7 +186,10 @@ export function startFrameLoop( } if (nativeFrameSource) { - scheduleTimer(() => drive("idle"), frameMs) + // Pump AppKit immediately rather than waiting `frameMs`: the first idle + // tick is what runs the post-show occlusion pump, and delaying it here + // only adds to the time before the window is reported visible. + drive("idle") } else { drive("timer") } From 3085b9d689f8c3f443f9e9f75910738b6918760f Mon Sep 17 00:00:00 2001 From: Ernest Badu <55922827+Ernxst@users.noreply.github.com> Date: Tue, 22 Sep 2026 00:32:50 +0100 Subject: [PATCH 2/2] fix: install default menus after the second frame The default menu bar (no `menus` option) loads WritingToolsUI and, with it, SwiftUI, WebKit and about a hundred other frameworks, all before the window's first present. Defer that install until after the window's second frame; a caller-supplied menu spec still installs synchronously during init so an invalid spec still fails `init()` immediately. Co-Authored-By: Claude Opus 5 (1M context) --- packages/native/src/renderer.rs | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/packages/native/src/renderer.rs b/packages/native/src/renderer.rs index 0ab90125..0e213b16 100644 --- a/packages/native/src/renderer.rs +++ b/packages/native/src/renderer.rs @@ -3095,9 +3095,17 @@ impl GpuixRenderer { init_key_bindings(cx); crate::custom_elements::input::init(cx); init_application_menu_support(cx, Some(application_callback.clone())); - if let Err(error) = install_application_menus(cx, &app_name, menus) { - *startup_error_for_app.borrow_mut() = Some(error); - return; + // Default menus (`menus: None`) load WritingToolsUI and, with it, + // SwiftUI, WebKit and about a hundred other frameworks; deferred + // below until after the second frame so it does not delay the + // first present. Caller-supplied menus are cheap and installed + // now so `open_window` observes any invalid spec immediately. + let defer_default_menus = menus.is_none(); + if !defer_default_menus { + if let Err(error) = install_application_menus(cx, &app_name, menus) { + *startup_error_for_app.borrow_mut() = Some(error); + return; + } } let window_size = gpui::size(gpui::px(width as f32), gpui::px(height as f32)); #[cfg(feature = "display-discovery-fault-injection")] @@ -3139,6 +3147,19 @@ impl GpuixRenderer { .ok(); } } + if defer_default_menus { + let app_name = app_name.clone(); + window_handle + .update(cx, |_view, window, _cx| { + window.on_next_frame(move |window, _cx| { + window.on_next_frame(move |_window, cx| { + // The default-menu path cannot fail. + let _ = install_application_menus(cx, &app_name, None); + }); + }); + }) + .ok(); + } } Err(error) => { *startup_error_for_app.borrow_mut() = Some(error.to_string());