From 24614e4e8b5d362617d770d9a2e4ba0c7ef5f655 Mon Sep 17 00:00:00 2001 From: Neil <4138956+nwparker@users.noreply.github.com> Date: Sat, 25 Jul 2026 22:04:01 -0700 Subject: [PATCH] fix(window): stop burning macOS GPU on an invisible blur effect (#8482) macOS Window Blur set `vibrancy: 'under-window'` and `transparent: true`, taking the window off the opaque fast path so WindowServer alpha-composited every frame. The effect was never visible: an opaque backgroundColor is always set and the renderer paints an opaque root, so it sat fully occluded. Reporter's A/B measured 5,365 mW with blur on vs 804 mW off at the same workload. Windows acrylic and Linux are untouched. Co-authored-by: Orca --- src/main/window/createMainWindow.test.ts | 53 ++++++++++++++++++++++++ src/main/window/createMainWindow.ts | 12 ++---- 2 files changed, 57 insertions(+), 8 deletions(-) diff --git a/src/main/window/createMainWindow.test.ts b/src/main/window/createMainWindow.test.ts index 6076a505582..1e01e55974d 100644 --- a/src/main/window/createMainWindow.test.ts +++ b/src/main/window/createMainWindow.test.ts @@ -311,6 +311,59 @@ describe('createMainWindow', () => { } }) + it('never requests macOS vibrancy or transparency when window blur is enabled (#8482)', () => { + for (const [platform, expected] of [ + ['darwin', { backgroundMaterial: undefined }], + ['win32', { backgroundMaterial: 'acrylic' }], + ['linux', { backgroundMaterial: undefined }] + ] satisfies [NodeJS.Platform, { backgroundMaterial: string | undefined }][]) { + browserWindowMock.mockReset() + const webContents = { + on: vi.fn(), + setZoomLevel: vi.fn(), + setBackgroundThrottling: vi.fn(), + invalidate: vi.fn(), + setWindowOpenHandler: vi.fn(), + send: vi.fn(), + isDevToolsOpened: vi.fn(), + openDevTools: vi.fn(), + closeDevTools: vi.fn() + } + const browserWindowInstance = { + webContents, + on: vi.fn(), + isDestroyed: vi.fn(() => false), + isMaximized: vi.fn(() => false), + isFullScreen: vi.fn(() => false), + getSize: vi.fn(() => [1200, 800]), + getBounds: vi.fn(() => ({ x: 10, y: 20, width: 1000, height: 700 })), + setSize: vi.fn(), + setWindowButtonPosition: vi.fn(), + maximize: vi.fn(), + show: vi.fn(), + loadFile: vi.fn(), + loadURL: vi.fn() + } + browserWindowMock.mockImplementation(function () { + return browserWindowInstance + }) + + withPlatform(platform, () => + createMainWindow({ + getUI: () => ({}), + getSettings: () => ({ windowBackgroundBlur: true }), + updateUI: vi.fn() + } as never) + ) + + const browserWindowOptions = browserWindowMock.mock.calls[0]?.[0] + expect(browserWindowOptions.vibrancy).toBeUndefined() + expect(browserWindowOptions.transparent).toBeUndefined() + expect(browserWindowOptions.backgroundMaterial).toBe(expected.backgroundMaterial) + expect(browserWindowOptions.backgroundColor).toBe('#ffffff') + } + }) + it('keeps main-window background throttling enabled while repainting macOS visibility transitions', () => { vi.useFakeTimers() const windowHandlers = new Map void)[]>() diff --git a/src/main/window/createMainWindow.ts b/src/main/window/createMainWindow.ts index 29e92a8de10..387f0d2b5f4 100644 --- a/src/main/window/createMainWindow.ts +++ b/src/main/window/createMainWindow.ts @@ -253,14 +253,10 @@ export function createMainWindow( return false }) const blur = settings?.windowBackgroundBlur ?? false - // Why: blur uses platform APIs (macOS vibrancy+transparent, Windows backgroundMaterial, Linux none) and only applies at creation, needs restart. - const platformBlurOptions = blur - ? process.platform === 'darwin' - ? { vibrancy: 'under-window' as const, transparent: true } - : process.platform === 'win32' - ? { backgroundMaterial: 'acrylic' as const } - : {} - : {} + // Why: only Windows acrylic is ever visible; macOS vibrancy+transparent sat behind our opaque background yet + // forced per-frame WindowServer alpha compositing (#8482). Applies at creation only, so it needs a restart. + const platformBlurOptions = + blur && process.platform === 'win32' ? { backgroundMaterial: 'acrylic' as const } : {} const mainWindow = new BrowserWindow({ width: savedBounds?.width ?? defaultBounds.width,