Skip to content

Commit b9a5d34

Browse files
SyntevoAlexniraj-modi
authored andcommitted
Bug 576613 - [win32][DarkTheme] Support Windows 11
This is how Dark Theme's dark scrollbars developed so far: 444560 - initial implementation 562043 - reworked to better approach, but due to using undocumented Windows APIs, this needs to ensure (for safety) that undocumented APIs are still there. This patch also makes popup menus dark. 568108 - added support for undocumented APIs in Win10 21H1 preview this - adds support for undocumented APIs in Win11 The goal of this patch is to keep dark menus/scrollbars working in Win11. Hopefully one day Windows will have public APIs for dark theme. Change-Id: Idc0fff6e0a6a0a33c506619b836f833590878bfe Signed-off-by: Alexandr Miloslavskiy <alexandr.miloslavskiy@syntevo.com> Reviewed-on: https://git.eclipse.org/r/c/platform/eclipse.platform.swt/+/186454 Tested-by: Platform Bot <platform-bot@eclipse.org> Tested-by: Niraj Modi <niraj.modi@in.ibm.com> Reviewed-by: Niraj Modi <niraj.modi@in.ibm.com>
1 parent 9c13f66 commit b9a5d34

File tree

1 file changed

+84
-15
lines changed
  • bundles/org.eclipse.swt/Eclipse SWT PI/win32/library

1 file changed

+84
-15
lines changed

bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/os_custom.c

Lines changed: 84 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,15 @@ BOOL Validate_AllowDarkModeForWindow(const BYTE* functionPtr)
5858

5959
#ifdef _M_X64
6060
/* Win10 builds from 20236 */
61-
if ((functionPtr[0x52] == 0xBA) && // mov edx,
62-
(*(const DWORD*)(functionPtr + 0x53) == 0xA91E)) // 0A91Eh
61+
if ((functionPtr[0x52] == 0xBA) && // mov edx,
62+
(*(const DWORD*)(functionPtr + 0x53) == 0xA91E)) // 0A91Eh
6363
{
6464
return TRUE;
6565
}
6666

6767
/* Win10 builds from 17763 to 19041 */
68-
if ((functionPtr[0x15] == 0xBA) && // mov edx,
69-
(*(const DWORD*)(functionPtr + 0x16) == 0xA91E)) // 0A91Eh
68+
if ((functionPtr[0x15] == 0xBA) && // mov edx,
69+
(*(const DWORD*)(functionPtr + 0x16) == 0xA91E)) // 0A91Eh
7070
{
7171
return TRUE;
7272
}
@@ -102,27 +102,86 @@ TYPE_AllowDarkModeForWindow Locate_AllowDarkModeForWindow()
102102
return (TYPE_AllowDarkModeForWindow)candidate;
103103
}
104104

105+
BOOL Validate_AllowDarkModeForWindowWithTelemetryId(const BYTE* functionPtr)
106+
{
107+
#ifdef _M_X64
108+
/* This function is rather long, but it uses an ATOM value of 0xA91E which is unlikely to change */
109+
110+
/* Win10 builds from 21301 */
111+
if ((functionPtr[0x31] == 0xBA) && // mov edx,
112+
(*(const DWORD*)(functionPtr + 0x32) == 0xA91E)) // 0A91Eh
113+
{
114+
return TRUE;
115+
}
116+
117+
return FALSE;
118+
#else
119+
#error Unsupported processor type
120+
#endif
121+
}
122+
123+
typedef BOOL (WINAPI* TYPE_AllowDarkModeForWindowWithTelemetryId)(HWND a_HWND, BOOL a_Allow, int a_TelemetryID);
124+
TYPE_AllowDarkModeForWindowWithTelemetryId Locate_AllowDarkModeForWindowWithTelemetryId()
125+
{
126+
const HMODULE hUxtheme = GetModuleHandle(L"uxtheme.dll");
127+
if (!hUxtheme)
128+
return 0;
129+
130+
/*
131+
* Function is only exported by ordinal.
132+
* Hopefully one day Microsoft will finally export it by name.
133+
*/
134+
const BYTE* candidate = (const BYTE*)GetProcAddress(hUxtheme, MAKEINTRESOURCEA(140));
135+
if (!candidate)
136+
return 0;
137+
138+
/*
139+
* In next Windows version, some other function can end up having this ordinal.
140+
* Compare function's code to known signature to make sure.
141+
*/
142+
if (!Validate_AllowDarkModeForWindowWithTelemetryId(candidate))
143+
return 0;
144+
145+
return (TYPE_AllowDarkModeForWindowWithTelemetryId)candidate;
146+
}
147+
105148
#ifndef NO_AllowDarkModeForWindow
106149
JNIEXPORT jboolean JNICALL OS_NATIVE(AllowDarkModeForWindow)
107150
(JNIEnv* env, jclass that, jlong arg0, jboolean arg1)
108151
{
109152
/* Cache the search result for performance reasons */
110153
static TYPE_AllowDarkModeForWindow fn_AllowDarkModeForWindow = 0;
154+
static TYPE_AllowDarkModeForWindowWithTelemetryId fn_AllowDarkModeForWindowWithTelemetryId = 0;
111155
static int isInitialized = 0;
112156
if (!isInitialized)
113157
{
114158
fn_AllowDarkModeForWindow = Locate_AllowDarkModeForWindow();
159+
fn_AllowDarkModeForWindowWithTelemetryId = Locate_AllowDarkModeForWindowWithTelemetryId();
115160
isInitialized = 1;
116161
}
117162

118-
if (!fn_AllowDarkModeForWindow)
119-
return 0;
163+
if (fn_AllowDarkModeForWindow)
164+
{
165+
jboolean rc = 0;
166+
OS_NATIVE_ENTER(env, that, AllowDarkModeForWindow_FUNC);
167+
rc = (jboolean)fn_AllowDarkModeForWindow((HWND)arg0, arg1);
168+
OS_NATIVE_EXIT(env, that, AllowDarkModeForWindow_FUNC);
169+
return rc;
170+
}
120171

121-
jboolean rc = 0;
122-
OS_NATIVE_ENTER(env, that, AllowDarkModeForWindow_FUNC);
123-
rc = (jboolean)fn_AllowDarkModeForWindow((HWND)arg0, arg1);
124-
OS_NATIVE_EXIT(env, that, AllowDarkModeForWindow_FUNC);
125-
return rc;
172+
// In Win11, 'AllowDarkModeForWindow' is a thin wrapper for 'AllowDarkModeForWindowWithTelemetryId'.
173+
// It's hard to verify the wrapper, but it's easy enough to verify the target.
174+
// For this reason, call 'AllowDarkModeForWindowWithTelemetryId' here.
175+
if (fn_AllowDarkModeForWindowWithTelemetryId)
176+
{
177+
jboolean rc = 0;
178+
OS_NATIVE_ENTER(env, that, AllowDarkModeForWindow_FUNC);
179+
rc = (jboolean)fn_AllowDarkModeForWindowWithTelemetryId((HWND)arg0, arg1, 0);
180+
OS_NATIVE_EXIT(env, that, AllowDarkModeForWindow_FUNC);
181+
return rc;
182+
}
183+
184+
return 0;
126185
}
127186
#endif
128187

@@ -139,9 +198,9 @@ BOOL Validate_SetPreferredAppMode(const BYTE* functionPtr)
139198
return FALSE;
140199

141200
return
142-
(functionPtr[0x00] == 0x8B) && (functionPtr[0x01] == 0x05) && // mov eax,dword ptr [uxtheme!g_preferredAppMode]
143-
(functionPtr[0x06] == 0x87) && (functionPtr[0x07] == 0x0D) && // xchg ecx,dword ptr [uxtheme!g_preferredAppMode]
144-
(functionPtr[0x0C] == 0xC3); // ret
201+
(functionPtr[0x00] == 0x8B) && (functionPtr[0x01] == 0x05) && // mov eax,dword ptr [uxtheme!g_preferredAppMode]
202+
(functionPtr[0x06] == 0x87) && (functionPtr[0x07] == 0x0D) && // xchg ecx,dword ptr [uxtheme!g_preferredAppMode]
203+
(functionPtr[0x0C] == 0xC3); // ret
145204
#else
146205
#error Unsupported processor type
147206
#endif
@@ -196,6 +255,16 @@ JNIEXPORT jint JNICALL OS_NATIVE(SetPreferredAppMode)
196255
}
197256
#endif
198257

258+
jboolean isDarkThemeAvailable() {
259+
if (!Locate_SetPreferredAppMode())
260+
return JNI_FALSE;
261+
262+
if (!Locate_AllowDarkModeForWindow() && !Locate_AllowDarkModeForWindowWithTelemetryId())
263+
return JNI_FALSE;
264+
265+
return JNI_TRUE;
266+
}
267+
199268
#ifndef NO_IsDarkModeAvailable
200269
JNIEXPORT jboolean JNICALL OS_NATIVE(IsDarkModeAvailable)
201270
(JNIEnv* env, jclass that)
@@ -205,7 +274,7 @@ JNIEXPORT jboolean JNICALL OS_NATIVE(IsDarkModeAvailable)
205274
static int isInitialized = 0;
206275
if (!isInitialized)
207276
{
208-
isAvailable = (Locate_SetPreferredAppMode() && Locate_AllowDarkModeForWindow());
277+
isAvailable = isDarkThemeAvailable();
209278
isInitialized = 1;
210279
}
211280

0 commit comments

Comments
 (0)