Skip to content

Commit bc3d1c8

Browse files
authored
Add VS Code dark non-client frame mod (#4464)
Adds a new mod: VS Code Dark Non-client Frame. This mod forces Visual Studio Code’s Windows non-client frame into immersive dark mode. It fixes a visible 2px white bottom edge that can appear when VS Code is maximized with the custom title bar in Windows light mode, especially with a hidden or transparent taskbar. ## Changelog If this pull request updates an existing mod, describe the changes below: * N/A - this pull request introduces a new mod. ## Mod authorship If this pull request introduces a new mod, please complete the section below. This mod was created by: - - [ ] The submitter, without AI assistance - - [x] The submitter, with AI assistance - - [ ] Claude - - [x] ChatGPT - - [ ] Gemini - - [ ] Another AI (please specify): - - [ ] Other (please specify): Please select the options that best apply. Your selection does not affect the acceptance criteria, but it helps reviewers understand the context of the code and provide relevant feedback.
1 parent bc44726 commit bc3d1c8

1 file changed

Lines changed: 134 additions & 0 deletions

File tree

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
// ==WindhawkMod==
2+
// @id vscode-dark-nonclient-frame
3+
// @name VS Code Dark Non-client Frame
4+
// @description Forces VS Code's non-client frame into dark mode to remove the light 2px bottom edge in Windows light mode.
5+
// @version 1.0
6+
// @author v1b3s0
7+
// @github https://github.com/v1b3s0
8+
// @license MIT
9+
// @include Code.exe
10+
// @compilerOptions -ldwmapi -luser32
11+
// ==/WindhawkMod==
12+
13+
// ==WindhawkModReadme==
14+
/*
15+
# VS Code Dark Non-client Frame
16+
17+
Forces Visual Studio Code's Windows non-client frame into immersive dark mode.
18+
19+
This fixes the 2px light gray bottom edge that can appear when VS Code is maximized with the custom title bar in Windows light mode, especially with a hidden or transparent taskbar.
20+
21+
Before:
22+
23+
![Before](https://i.imgur.com/DVrOPag.png)
24+
25+
After:
26+
27+
![After](https://i.imgur.com/ldT3xJt.png)
28+
29+
The mod targets only `Code.exe` by default. Users of VS Code Insiders, VSCodium, or renamed/portable builds can add the relevant executable name to the mod's custom include list.
30+
31+
When the mod is disabled, it stops overriding VS Code's frame mode. Already affected windows may keep their current frame mode until VS Code applies a new value, for example after a theme or window state change.
32+
*/
33+
// ==/WindhawkModReadme==
34+
35+
#include <dwmapi.h>
36+
#include <windhawk_api.h>
37+
38+
using DwmSetWindowAttribute_t = decltype(&DwmSetWindowAttribute);
39+
DwmSetWindowAttribute_t DwmSetWindowAttribute_orig;
40+
41+
BOOL IsCurrentProcessWindow(HWND hWnd) {
42+
DWORD windowPid = 0;
43+
GetWindowThreadProcessId(hWnd, &windowPid);
44+
45+
return windowPid == GetCurrentProcessId();
46+
}
47+
48+
BOOL IsValidWindow(HWND hWnd) {
49+
LONG_PTR style = GetWindowLongPtr(hWnd, GWL_STYLE);
50+
51+
return (style & WS_THICKFRAME) == WS_THICKFRAME ||
52+
(style & WS_CAPTION) == WS_CAPTION;
53+
}
54+
55+
void ApplyDarkFrame(HWND hWnd) {
56+
if (!IsValidWindow(hWnd)) {
57+
return;
58+
}
59+
60+
BOOL enabled = TRUE;
61+
62+
DwmSetWindowAttribute_orig(
63+
hWnd,
64+
DWMWA_USE_IMMERSIVE_DARK_MODE,
65+
&enabled,
66+
sizeof(enabled)
67+
);
68+
}
69+
70+
HRESULT WINAPI DwmSetWindowAttribute_hook(
71+
HWND hWnd,
72+
DWORD dwAttribute,
73+
LPCVOID pvAttribute,
74+
DWORD cbAttribute
75+
) {
76+
if (dwAttribute == DWMWA_USE_IMMERSIVE_DARK_MODE &&
77+
IsCurrentProcessWindow(hWnd) &&
78+
IsValidWindow(hWnd)) {
79+
BOOL enabled = TRUE;
80+
81+
return DwmSetWindowAttribute_orig(
82+
hWnd,
83+
dwAttribute,
84+
&enabled,
85+
sizeof(enabled)
86+
);
87+
}
88+
89+
return DwmSetWindowAttribute_orig(
90+
hWnd,
91+
dwAttribute,
92+
pvAttribute,
93+
cbAttribute
94+
);
95+
}
96+
97+
BOOL CALLBACK EnableEnumWindowsCallback(HWND hWnd, LPARAM lParam) {
98+
DWORD targetPid = static_cast<DWORD>(lParam);
99+
100+
DWORD windowPid = 0;
101+
GetWindowThreadProcessId(hWnd, &windowPid);
102+
103+
if (targetPid == windowPid) {
104+
ApplyDarkFrame(hWnd);
105+
}
106+
107+
return TRUE;
108+
}
109+
110+
BOOL Wh_ModInit() {
111+
Wh_Log(L"Init");
112+
113+
Wh_SetFunctionHook(
114+
(void*)DwmSetWindowAttribute,
115+
(void*)DwmSetWindowAttribute_hook,
116+
(void**)&DwmSetWindowAttribute_orig
117+
);
118+
119+
return TRUE;
120+
}
121+
122+
void Wh_ModAfterInit() {
123+
Wh_Log(L"AfterInit");
124+
125+
EnumWindows(EnableEnumWindowsCallback, GetCurrentProcessId());
126+
}
127+
128+
void Wh_ModBeforeUninit() {
129+
Wh_Log(L"BeforeUninit");
130+
131+
// Do not force DWMWA_USE_IMMERSIVE_DARK_MODE to FALSE here.
132+
// Disabling the mod should stop overriding VS Code's own value instead of
133+
// forcing a light non-client frame.
134+
}

0 commit comments

Comments
 (0)