#566

macOS: a window created with hidden: true shows blank frames on show(), because WKWebView does not paint while hidden

OpenGiorgosflopened 1mo ago

Environment: Electrobun 2.0.1 (via Hutch), macOS 27.0 on arm64, system webview (WKWebView), bundleCEF off, Bun main process.

What happens

The main window is created hidden, the view renders its first frame and tells the main process over RPC, and only then is the window shown:

const win = new BrowserWindow({
  title: "App",
  url: "views://mainview/index.html",
  frame: { width: 1000, height: 700 },
  hidden: true,
  rpc,
});
await viewReady; // sent by the view after its first render
win.show();

A 60 fps screen recording of the launch shows the window appear with only its background for 2 to 4 frames (about 33 to 67 ms), and then the complete page. The DOM is already complete when show() is called; the page just has not been painted yet.

Why

WebKit does not paint a WKWebView whose window is ordered out, so nothing is drawn until the window is shown. Parking the window off screen or behind other windows does not help either: WebKit treats an occluded window as hidden and stops producing frames. The only way found around it is the private -[WKWebView _setWindowOcclusionDetectionEnabled:NO], and it only works when set before the web view is added to its window. A titled window parked off screen also needs constrainFrameRect(_:to:) overridden, or AppKit moves it back on screen. Measurements: https://github.com/tophatch/swift-pwa/issues/208

None of this is reachable from app code in Electrobun, so an app cannot open its window already painted.

Request

A way on macOS to show a window whose first visible frame is the painted page. For example:

  • an option on BrowserWindow / BrowserView (macOS only) that turns off window occlusion detection when the web view is created, before it enters its window, guarded with respondsToSelector: since it is private API, so an app can render in a window that is ordered in but out of sight and then reveal it; or
  • a supported "show when painted" path in Electrobun itself, like Electron's ready-to-show event.

Related: #399 asks for setOpacity, which could be one way to keep the window ordered in but invisible until it has painted (not checked whether WebKit keeps painting a window at alpha 0).

Similar reports in other frameworks: https://github.com/electron/electron/issues/46602, https://github.com/AlteredCraft/B2/issues/225

Activity

0

No activity yet.