Skip to content

Commit 7c3dea7

Browse files
committed
fix(desktop): render the Windows window opaquely
Windows composited the desktop wallpaper behind the window through backgroundMaterial: 'acrylic', so every non-opaque surface blended it into the theme colours and the app looked washed out next to macOS. Paint an opaque background instead.
1 parent 041cd6d commit 7c3dea7

3 files changed

Lines changed: 50 additions & 1 deletion

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@pymodel/pythinker-desktop': patch
3+
---
4+
5+
Render the Windows desktop window opaquely so the theme colours are not blended with the desktop wallpaper

apps/desktop/src/main.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,8 +201,9 @@ async function createMainWindow(): Promise<BrowserWindow> {
201201
vibrancy: 'sidebar' as const,
202202
visualEffectState: 'followWindow' as const,
203203
} : {}),
204+
// Windows uses an opaque window so theme colors do not blend with desktop wallpaper.
204205
...(process.platform === 'win32' ? {
205-
backgroundMaterial: 'acrylic' as const,
206+
backgroundColor: '#0d1117',
206207
hasShadow: true,
207208
roundedCorners: true,
208209
thickFrame: true,
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Static check: no Windows host exists in CI or locally, so this test guards the
2+
// window configuration rather than the rendered result.
3+
import { readFileSync } from 'node:fs'
4+
import { resolve } from 'node:path'
5+
import { describe, expect, it } from 'vitest'
6+
7+
const desktopRoot = resolve(import.meta.dirname, '..')
8+
const mainSource = readFileSync(resolve(desktopRoot, 'src', 'main.ts'), 'utf8')
9+
10+
describe('desktop window appearance configuration', () => {
11+
it('keeps Windows opaque and non-Windows windows transparent', () => {
12+
const backgroundMaterialMatches = [...mainSource.matchAll(/backgroundMaterial/g)]
13+
const win32BranchMatches = [...mainSource.matchAll(
14+
/\.\.\.\(process\.platform === 'win32' \? \{([\s\S]*?)\} : \{\s*transparent: true,/g,
15+
)]
16+
const nonWin32BranchMatches = [...mainSource.matchAll(
17+
/\} : \{\s*transparent: true,[\s\S]*?\}\),\s*title:/g,
18+
)]
19+
20+
expect(backgroundMaterialMatches).toHaveLength(0)
21+
expect(win32BranchMatches).toHaveLength(1)
22+
expect(nonWin32BranchMatches).toHaveLength(1)
23+
24+
const win32Branch = win32BranchMatches[0]![1]!
25+
const opaqueColorMatches = [...win32Branch.matchAll(/backgroundColor:\s*'#[0-9a-fA-F]{6}'/g)]
26+
const alphaColorMatches = [...win32Branch.matchAll(/#[0-9a-fA-F]{8}/g)]
27+
const hasShadowMatches = [...win32Branch.matchAll(/hasShadow:\s*true/g)]
28+
const roundedCornersMatches = [...win32Branch.matchAll(/roundedCorners:\s*true/g)]
29+
const thickFrameMatches = [...win32Branch.matchAll(/thickFrame:\s*true/g)]
30+
31+
expect(opaqueColorMatches).toHaveLength(1)
32+
expect(alphaColorMatches).toHaveLength(0)
33+
expect(hasShadowMatches).toHaveLength(1)
34+
expect(roundedCornersMatches).toHaveLength(1)
35+
expect(thickFrameMatches).toHaveLength(1)
36+
37+
expect(win32Branch).toContain('backgroundColor')
38+
expect(nonWin32BranchMatches[0]![0]).toContain('transparent: true')
39+
expect(win32Branch).toContain('hasShadow')
40+
expect(win32Branch).toContain('roundedCorners')
41+
expect(win32Branch).toContain('thickFrame')
42+
})
43+
})

0 commit comments

Comments
 (0)