CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: hrydgard/ppsspp
Path: blob/master/Windows/W32Util/DarkMode.cpp
Views: 1401
1
#include "IatHook.h"
2
#include "DarkMode.h"
3
4
fnSetWindowCompositionAttribute _SetWindowCompositionAttribute = nullptr;
5
fnShouldAppsUseDarkMode _ShouldAppsUseDarkMode = nullptr;
6
fnAllowDarkModeForWindow _AllowDarkModeForWindow = nullptr;
7
fnAllowDarkModeForApp _AllowDarkModeForApp = nullptr;
8
fnFlushMenuThemes _FlushMenuThemes = nullptr;
9
fnRefreshImmersiveColorPolicyState _RefreshImmersiveColorPolicyState = nullptr;
10
fnIsDarkModeAllowedForWindow _IsDarkModeAllowedForWindow = nullptr;
11
fnGetIsImmersiveColorUsingHighContrast _GetIsImmersiveColorUsingHighContrast = nullptr;
12
fnOpenNcThemeData _OpenNcThemeData = nullptr;
13
// 1903 18362
14
fnShouldSystemUseDarkMode _ShouldSystemUseDarkMode = nullptr;
15
fnSetPreferredAppMode _SetPreferredAppMode = nullptr;
16
fnSetWindowTheme _SetWindowTheme = nullptr;
17
18
bool g_darkModeSupported = false;
19
bool g_darkModeEnabled = false;
20
DWORD g_buildNumber = 0;
21
22
bool AllowDarkModeForWindow(HWND hWnd, bool allow)
23
{
24
if (g_darkModeSupported)
25
return _AllowDarkModeForWindow(hWnd, allow);
26
return false;
27
}
28
29
bool IsHighContrast()
30
{
31
HIGHCONTRASTW highContrast = { sizeof(highContrast) };
32
if (SystemParametersInfoW(SPI_GETHIGHCONTRAST, sizeof(highContrast), &highContrast, FALSE))
33
return highContrast.dwFlags & HCF_HIGHCONTRASTON;
34
return false;
35
}
36
37
void RefreshTitleBarThemeColor(HWND hWnd)
38
{
39
BOOL dark = FALSE;
40
if (_IsDarkModeAllowedForWindow(hWnd) &&
41
_ShouldAppsUseDarkMode() &&
42
!IsHighContrast())
43
{
44
dark = TRUE;
45
}
46
if (g_buildNumber < 18362)
47
SetPropW(hWnd, L"UseImmersiveDarkModeColors", reinterpret_cast<HANDLE>(static_cast<INT_PTR>(dark)));
48
else if (_SetWindowCompositionAttribute)
49
{
50
WINDOWCOMPOSITIONATTRIBDATA data = { WCA_USEDARKMODECOLORS, &dark, sizeof(dark) };
51
_SetWindowCompositionAttribute(hWnd, &data);
52
}
53
}
54
55
bool IsColorSchemeChangeMessage(LPARAM lParam)
56
{
57
bool is = false;
58
if (lParam && CompareStringOrdinal(reinterpret_cast<LPCWCH>(lParam), -1, L"ImmersiveColorSet", -1, TRUE) == CSTR_EQUAL)
59
{
60
_RefreshImmersiveColorPolicyState();
61
is = true;
62
}
63
_GetIsImmersiveColorUsingHighContrast(IHCM_REFRESH);
64
return is;
65
}
66
67
bool IsColorSchemeChangeMessage(UINT message, LPARAM lParam)
68
{
69
if (message == WM_SETTINGCHANGE)
70
return IsColorSchemeChangeMessage(lParam);
71
return false;
72
}
73
74
void AllowDarkModeForApp(bool allow)
75
{
76
if (_AllowDarkModeForApp)
77
_AllowDarkModeForApp(allow);
78
else if (_SetPreferredAppMode)
79
_SetPreferredAppMode(allow ? AllowDark : Default);
80
}
81
82
void FixDarkScrollBar()
83
{
84
// Disable this, doesn't look good.
85
return;
86
87
HMODULE hComctl = LoadLibraryExW(L"comctl32.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
88
if (hComctl)
89
{
90
auto addr = FindDelayLoadThunkInModule(hComctl, "uxtheme.dll", 49); // OpenNcThemeData
91
if (addr)
92
{
93
DWORD oldProtect;
94
if (VirtualProtect(addr, sizeof(IMAGE_THUNK_DATA), PAGE_READWRITE, &oldProtect))
95
{
96
auto MyOpenThemeData = [](HWND hWnd, LPCWSTR classList) -> HTHEME {
97
if (wcscmp(classList, L"ScrollBar") == 0)
98
{
99
hWnd = nullptr;
100
classList = L"Explorer::ScrollBar";
101
}
102
return _OpenNcThemeData(hWnd, classList);
103
};
104
105
addr->u1.Function = reinterpret_cast<ULONG_PTR>(static_cast<fnOpenNcThemeData>(MyOpenThemeData));
106
VirtualProtect(addr, sizeof(IMAGE_THUNK_DATA), oldProtect, &oldProtect);
107
}
108
}
109
}
110
}
111
112
void DarkModeInitDialog(HWND hDlg) {
113
if (g_darkModeSupported) {
114
_SetWindowTheme(GetDlgItem(hDlg, IDOK), L"Explorer", nullptr);
115
SendMessageW(hDlg, WM_THEMECHANGED, 0, 0);
116
}
117
}
118
119
LRESULT DarkModeDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) {
120
constexpr COLORREF darkBkColor = 0x383838;
121
constexpr COLORREF darkTextColor = 0xFFFFFF;
122
static HBRUSH hbrBkgnd = nullptr;
123
124
switch (message) {
125
case WM_CTLCOLORDLG:
126
case WM_CTLCOLORSTATIC:
127
{
128
if (g_darkModeSupported && g_darkModeEnabled)
129
{
130
HDC hdc = reinterpret_cast<HDC>(wParam);
131
SetTextColor(hdc, darkTextColor);
132
SetBkColor(hdc, darkBkColor);
133
if (!hbrBkgnd)
134
hbrBkgnd = CreateSolidBrush(darkBkColor);
135
return reinterpret_cast<INT_PTR>(hbrBkgnd);
136
}
137
break;
138
}
139
case WM_SETTINGCHANGE:
140
{
141
if (g_darkModeSupported && IsColorSchemeChangeMessage(lParam))
142
SendMessageW(hDlg, WM_THEMECHANGED, 0, 0);
143
break;
144
}
145
case WM_THEMECHANGED:
146
{
147
if (g_darkModeSupported)
148
{
149
_AllowDarkModeForWindow(hDlg, g_darkModeEnabled);
150
RefreshTitleBarThemeColor(hDlg);
151
152
HWND hButton = GetDlgItem(hDlg, IDOK);
153
_AllowDarkModeForWindow(hButton, g_darkModeEnabled);
154
SendMessageW(hButton, WM_THEMECHANGED, 0, 0);
155
156
UpdateWindow(hDlg);
157
}
158
break;
159
}
160
}
161
return FALSE;
162
}
163
164
bool IsDarkModeEnabled() {
165
return g_darkModeEnabled;
166
}
167
168
constexpr bool CheckBuildNumber(DWORD buildNumber)
169
{
170
// TODO: This is BS.
171
172
return (buildNumber == 17763 || // 1809
173
buildNumber == 18362 || // 1903
174
buildNumber == 18363 || // 1909
175
buildNumber >= 19041); // Windows 11
176
}
177
178
void InitDarkMode()
179
{
180
auto RtlGetNtVersionNumbers = reinterpret_cast<fnRtlGetNtVersionNumbers>(GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "RtlGetNtVersionNumbers"));
181
if (RtlGetNtVersionNumbers)
182
{
183
DWORD major, minor;
184
RtlGetNtVersionNumbers(&major, &minor, &g_buildNumber);
185
g_buildNumber &= ~0xF0000000;
186
if (major == 10 && minor == 0 && CheckBuildNumber(g_buildNumber))
187
{
188
HMODULE hUxtheme = LoadLibraryExW(L"uxtheme.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
189
if (hUxtheme)
190
{
191
_OpenNcThemeData = reinterpret_cast<fnOpenNcThemeData>(GetProcAddress(hUxtheme, MAKEINTRESOURCEA(49)));
192
_RefreshImmersiveColorPolicyState = reinterpret_cast<fnRefreshImmersiveColorPolicyState>(GetProcAddress(hUxtheme, MAKEINTRESOURCEA(104)));
193
_GetIsImmersiveColorUsingHighContrast = reinterpret_cast<fnGetIsImmersiveColorUsingHighContrast>(GetProcAddress(hUxtheme, MAKEINTRESOURCEA(106)));
194
_ShouldAppsUseDarkMode = reinterpret_cast<fnShouldAppsUseDarkMode>(GetProcAddress(hUxtheme, MAKEINTRESOURCEA(132)));
195
_AllowDarkModeForWindow = reinterpret_cast<fnAllowDarkModeForWindow>(GetProcAddress(hUxtheme, MAKEINTRESOURCEA(133)));
196
197
auto ord135 = GetProcAddress(hUxtheme, MAKEINTRESOURCEA(135));
198
if (g_buildNumber < 18362)
199
_AllowDarkModeForApp = reinterpret_cast<fnAllowDarkModeForApp>(ord135);
200
else
201
_SetPreferredAppMode = reinterpret_cast<fnSetPreferredAppMode>(ord135);
202
203
//_FlushMenuThemes = reinterpret_cast<fnFlushMenuThemes>(GetProcAddress(hUxtheme, MAKEINTRESOURCEA(136)));
204
_IsDarkModeAllowedForWindow = reinterpret_cast<fnIsDarkModeAllowedForWindow>(GetProcAddress(hUxtheme, MAKEINTRESOURCEA(137)));
205
206
_SetWindowCompositionAttribute = reinterpret_cast<fnSetWindowCompositionAttribute>(GetProcAddress(GetModuleHandleW(L"user32.dll"), "SetWindowCompositionAttribute"));
207
_SetWindowTheme = reinterpret_cast<fnSetWindowTheme>(GetProcAddress(hUxtheme, "SetWindowTheme"));
208
209
if (_OpenNcThemeData &&
210
_RefreshImmersiveColorPolicyState &&
211
_ShouldAppsUseDarkMode &&
212
_AllowDarkModeForWindow &&
213
(_AllowDarkModeForApp || _SetPreferredAppMode) &&
214
//_FlushMenuThemes &&
215
_IsDarkModeAllowedForWindow)
216
{
217
g_darkModeSupported = true;
218
219
AllowDarkModeForApp(true);
220
_RefreshImmersiveColorPolicyState();
221
222
g_darkModeEnabled = _ShouldAppsUseDarkMode() && !IsHighContrast();
223
224
FixDarkScrollBar();
225
}
226
}
227
}
228
}
229
}
230
231