mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-23 13:30:02 +00:00
Merge pull request #16704 from hrydgard/darkmode
Windows Dark Mode: initial support
This commit is contained in:
commit
b04dd81cba
@ -1,5 +1,3 @@
|
||||
// NOTE: Apologies for the quality of this code, this is really from pre-opensource Dolphin - that is, 2003.
|
||||
|
||||
#include "Core/Config.h"
|
||||
#include "Core/MemMap.h"
|
||||
#include "Windows/resource.h"
|
||||
@ -13,6 +11,7 @@
|
||||
#include "Windows/Debugger/Debugger_Disasm.h"
|
||||
#include "Windows/Debugger/Debugger_VFPUDlg.h"
|
||||
#include "Windows/Debugger/DebuggerShared.h"
|
||||
// #include "Windows/W32Util/DarkMode.h"
|
||||
|
||||
#include "Windows/main.h"
|
||||
#include "Windows/Debugger/CtrlRegisterList.h"
|
||||
@ -350,10 +349,8 @@ BOOL CDisasm::DlgProc(UINT message, WPARAM wParam, LPARAM lParam)
|
||||
switch(message)
|
||||
{
|
||||
case WM_INITDIALOG:
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
// DarkModeInitDialog(m_hDlg);
|
||||
return TRUE;
|
||||
|
||||
case WM_NOTIFY:
|
||||
switch (wParam)
|
||||
@ -692,7 +689,7 @@ BOOL CDisasm::DlgProc(UINT message, WPARAM wParam, LPARAM lParam)
|
||||
}
|
||||
break;
|
||||
}
|
||||
return FALSE;
|
||||
return 0; // DarkModeDlgProc(m_hDlg, message, wParam, lParam);
|
||||
}
|
||||
|
||||
void CDisasm::updateThreadLabel(bool clear)
|
||||
|
@ -1,5 +1,3 @@
|
||||
// NOTE: Apologies for the quality of this code, this is really from pre-opensource Dolphin - that is, 2003.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Windows/W32Util/DialogManager.h"
|
||||
|
@ -56,6 +56,8 @@
|
||||
#include "Windows/GPU/WindowsGLContext.h"
|
||||
#include "Windows/GEDebugger/GEDebugger.h"
|
||||
#endif
|
||||
#include "Windows/W32Util/DarkMode.h"
|
||||
#include "Windows/W32Util/UAHMenuBar.h"
|
||||
#include "Windows/Debugger/Debugger_Disasm.h"
|
||||
#include "Windows/Debugger/Debugger_MemoryDlg.h"
|
||||
|
||||
@ -177,7 +179,7 @@ namespace MainWindow
|
||||
|
||||
WNDCLASSEX wcdisp;
|
||||
memset(&wcdisp, 0, sizeof(wcdisp));
|
||||
// Display Window
|
||||
// Display Window (contained in main window)
|
||||
wcdisp.cbSize = sizeof(WNDCLASSEX);
|
||||
wcdisp.style = CS_HREDRAW | CS_VREDRAW;
|
||||
wcdisp.lpfnWndProc = (WNDPROC)DisplayProc;
|
||||
@ -728,13 +730,52 @@ namespace MainWindow
|
||||
return 0;
|
||||
}
|
||||
|
||||
RECT MapRectFromClientToWndCoords(HWND hwnd, const RECT & r)
|
||||
{
|
||||
RECT wnd_coords = r;
|
||||
|
||||
// map to screen
|
||||
MapWindowPoints(hwnd, NULL, reinterpret_cast<POINT *>(&wnd_coords), 2);
|
||||
|
||||
RECT scr_coords;
|
||||
GetWindowRect(hwnd, &scr_coords);
|
||||
|
||||
// map to window coords by substracting the window coord origin in
|
||||
// screen coords.
|
||||
OffsetRect(&wnd_coords, -scr_coords.left, -scr_coords.top);
|
||||
|
||||
return wnd_coords;
|
||||
}
|
||||
|
||||
RECT GetNonclientMenuBorderRect(HWND hwnd)
|
||||
{
|
||||
RECT r;
|
||||
GetClientRect(hwnd, &r);
|
||||
r = MapRectFromClientToWndCoords(hwnd, r);
|
||||
int y = r.top - 1;
|
||||
return {
|
||||
r.left,
|
||||
y,
|
||||
r.right,
|
||||
y + 1
|
||||
};
|
||||
}
|
||||
|
||||
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
LRESULT darkResult = 0;
|
||||
if (UAHDarkModeWndProc(hWnd, message, wParam, lParam, &darkResult)) {
|
||||
return darkResult;
|
||||
}
|
||||
|
||||
switch (message) {
|
||||
case WM_CREATE:
|
||||
if (!DoesVersionMatchWindows(6, 0, 0, 0, true)) {
|
||||
// Remove the D3D11 choice on versions below XP
|
||||
RemoveMenu(GetMenu(hWnd), ID_OPTIONS_DIRECT3D11, MF_BYCOMMAND);
|
||||
}
|
||||
if (g_darkModeSupported) {
|
||||
SendMessageW(hWnd, WM_THEMECHANGED, 0, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_USER_GET_BASE_POINTER:
|
||||
@ -749,6 +790,26 @@ namespace MainWindow
|
||||
}
|
||||
break;
|
||||
|
||||
// Hack to kill the white line underneath the menubar.
|
||||
// From https://stackoverflow.com/questions/57177310/how-to-paint-over-white-line-between-menu-bar-and-client-area-of-window
|
||||
case WM_NCPAINT:
|
||||
case WM_NCACTIVATE:
|
||||
{
|
||||
if (!IsDarkModeEnabled() || IsIconic(hWnd)) {
|
||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
}
|
||||
|
||||
auto result = DefWindowProc(hWnd, message, wParam, lParam);
|
||||
// Paint over the line with pure black. Could also try to figure out the dark theme color.
|
||||
HDC hdc = GetWindowDC(hWnd);
|
||||
RECT r = GetNonclientMenuBorderRect(hWnd);
|
||||
HBRUSH red = CreateSolidBrush(RGB(0, 0, 0));
|
||||
FillRect(hdc, &r, red);
|
||||
DeleteObject(red);
|
||||
ReleaseDC(hWnd, hdc);
|
||||
return result;
|
||||
}
|
||||
|
||||
case WM_GETMINMAXINFO:
|
||||
{
|
||||
MINMAXINFO *minmax = reinterpret_cast<MINMAXINFO *>(lParam);
|
||||
@ -804,7 +865,7 @@ namespace MainWindow
|
||||
|
||||
case WM_ERASEBKGND:
|
||||
// This window is always covered by DisplayWindow. No reason to erase.
|
||||
return 1;
|
||||
return 0;
|
||||
|
||||
case WM_MOVE:
|
||||
SavePosition();
|
||||
@ -1048,6 +1109,23 @@ namespace MainWindow
|
||||
}
|
||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
}
|
||||
break;
|
||||
case WM_SETTINGCHANGE:
|
||||
{
|
||||
if (g_darkModeSupported && IsColorSchemeChangeMessage(lParam))
|
||||
SendMessageW(hWnd, WM_THEMECHANGED, 0, 0);
|
||||
}
|
||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
|
||||
case WM_THEMECHANGED:
|
||||
{
|
||||
if (g_darkModeSupported)
|
||||
{
|
||||
_AllowDarkModeForWindow(hWnd, g_darkModeEnabled);
|
||||
RefreshTitleBarThemeColor(hWnd);
|
||||
}
|
||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
}
|
||||
|
||||
default:
|
||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include "Windows/W32Util/Misc.h"
|
||||
#include "Windows/InputBox.h"
|
||||
#include "Windows/main.h"
|
||||
#include "Windows/W32Util/DarkMode.h"
|
||||
|
||||
#include "Core/HLE/sceUmd.h"
|
||||
#include "Core/SaveState.h"
|
||||
@ -65,7 +66,7 @@ namespace MainWindow {
|
||||
static bool menuShaderInfoLoaded = false;
|
||||
std::vector<ShaderInfo> menuShaderInfo;
|
||||
|
||||
LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM);
|
||||
LRESULT CALLBACK AboutDlgProc(HWND, UINT, WPARAM, LPARAM);
|
||||
|
||||
void SetIngameMenuItemStates(HMENU menu, const GlobalUIState state) {
|
||||
UINT menuEnable = state == UISTATE_INGAME || state == UISTATE_EXCEPTION ? MF_ENABLED : MF_GRAYED;
|
||||
@ -936,7 +937,7 @@ namespace MainWindow {
|
||||
|
||||
case ID_HELP_ABOUT:
|
||||
DialogManager::EnableAll(FALSE);
|
||||
DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
|
||||
DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)AboutDlgProc);
|
||||
DialogManager::EnableAll(TRUE);
|
||||
break;
|
||||
|
||||
@ -1267,24 +1268,31 @@ namespace MainWindow {
|
||||
}
|
||||
|
||||
// Message handler for about box.
|
||||
LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
LRESULT CALLBACK AboutDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
switch (message) {
|
||||
case WM_INITDIALOG:
|
||||
{
|
||||
W32Util::CenterWindow(hDlg);
|
||||
HWND versionBox = GetDlgItem(hDlg, IDC_VERSION);
|
||||
std::string windowText = System_GetPropertyBool(SYSPROP_APP_GOLD) ? "PPSSPP Gold " : "PPSSPP ";
|
||||
windowText.append(PPSSPP_GIT_VERSION);
|
||||
SetWindowText(versionBox, ConvertUTF8ToWString(windowText).c_str());
|
||||
}
|
||||
return TRUE;
|
||||
|
||||
case WM_COMMAND:
|
||||
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
|
||||
EndDialog(hDlg, LOWORD(wParam));
|
||||
case WM_INITDIALOG:
|
||||
{
|
||||
W32Util::CenterWindow(hDlg);
|
||||
HWND versionBox = GetDlgItem(hDlg, IDC_VERSION);
|
||||
std::string windowText = System_GetPropertyBool(SYSPROP_APP_GOLD) ? "PPSSPP Gold " : "PPSSPP ";
|
||||
windowText.append(PPSSPP_GIT_VERSION);
|
||||
SetWindowText(versionBox, ConvertUTF8ToWString(windowText).c_str());
|
||||
DarkModeInitDialog(hDlg);
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_COMMAND:
|
||||
{
|
||||
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
|
||||
EndDialog(hDlg, LOWORD(wParam));
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
default:
|
||||
return DarkModeDlgProc(hDlg, message, wParam, lParam);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -248,7 +248,7 @@
|
||||
<AdditionalOptions>$(EXTERNAL_COMPILE_OPTIONS)</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;opengl32.lib;glu32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>uxtheme.lib;mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;opengl32.lib;glu32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>../ffmpeg/Windows/x86/lib</AdditionalLibraryDirectories>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
@ -287,7 +287,7 @@
|
||||
<AdditionalOptions>$(EXTERNAL_COMPILE_OPTIONS)</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;opengl32.lib;glu32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>uxtheme.lib;mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;opengl32.lib;glu32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>../ffmpeg/Windows/x86_64/lib</AdditionalLibraryDirectories>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>$(OutDir)$(ProjectName).pdb</ProgramDatabaseFile>
|
||||
@ -322,7 +322,7 @@
|
||||
<AdditionalOptions>$(EXTERNAL_COMPILE_OPTIONS)</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;oleaut32.lib;comdlg32.lib;shell32.lib;user32.lib;gdi32.lib;advapi32.lib;ole32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>uxtheme.lib;mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;oleaut32.lib;comdlg32.lib;shell32.lib;user32.lib;gdi32.lib;advapi32.lib;ole32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>../ffmpeg/Windows/aarch64/lib</AdditionalLibraryDirectories>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>$(OutDir)$(ProjectName).pdb</ProgramDatabaseFile>
|
||||
@ -355,7 +355,7 @@
|
||||
<AdditionalOptions>$(EXTERNAL_COMPILE_OPTIONS)</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;oleaut32.lib;comdlg32.lib;shell32.lib;user32.lib;gdi32.lib;advapi32.lib;ole32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>uxtheme.lib;mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;oleaut32.lib;comdlg32.lib;shell32.lib;user32.lib;gdi32.lib;advapi32.lib;ole32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>../ffmpeg/Windows/arm/lib</AdditionalLibraryDirectories>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>$(OutDir)$(ProjectName).pdb</ProgramDatabaseFile>
|
||||
@ -392,7 +392,7 @@
|
||||
<AdditionalOptions>$(EXTERNAL_COMPILE_OPTIONS)</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;opengl32.lib;glu32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>uxtheme.lib;mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;opengl32.lib;glu32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>../ffmpeg/Windows/x86/lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
@ -440,7 +440,7 @@
|
||||
<AdditionalOptions>$(EXTERNAL_COMPILE_OPTIONS)</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;opengl32.lib;glu32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>uxtheme.lib;mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;opengl32.lib;glu32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>../ffmpeg/Windows/x86_64/lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
@ -482,7 +482,7 @@
|
||||
<AdditionalOptions>$(EXTERNAL_COMPILE_OPTIONS)</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;oleaut32.lib;comdlg32.lib;shell32.lib;user32.lib;gdi32.lib;advapi32.lib;ole32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>uxtheme.lib;mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;oleaut32.lib;comdlg32.lib;shell32.lib;user32.lib;gdi32.lib;advapi32.lib;ole32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>../ffmpeg/Windows/aarch64/lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
@ -522,7 +522,7 @@
|
||||
<AdditionalOptions>$(EXTERNAL_COMPILE_OPTIONS)</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;oleaut32.lib;comdlg32.lib;shell32.lib;user32.lib;gdi32.lib;advapi32.lib;ole32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>uxtheme.lib;mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;oleaut32.lib;comdlg32.lib;shell32.lib;user32.lib;gdi32.lib;advapi32.lib;ole32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>../ffmpeg/Windows/arm/lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
@ -917,6 +917,7 @@
|
||||
<ClCompile Include="TouchInputHandler.cpp" />
|
||||
<ClCompile Include="GPU\WindowsVulkanContext.cpp" />
|
||||
<ClCompile Include="W32Util\ContextMenu.cpp" />
|
||||
<ClCompile Include="W32Util\DarkMode.cpp" />
|
||||
<ClCompile Include="W32Util\DialogManager.cpp" />
|
||||
<ClCompile Include="W32Util\Misc.cpp">
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)%(Filename)2.obj</ObjectFileName>
|
||||
@ -939,6 +940,7 @@
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="W32Util\UAHMenuBar.cpp" />
|
||||
<ClCompile Include="WASAPIStream.cpp" />
|
||||
<ClCompile Include="WindowsAudio.cpp" />
|
||||
<ClCompile Include="WindowsHost.cpp" />
|
||||
@ -1484,7 +1486,9 @@
|
||||
<ClInclude Include="TouchInputHandler.h" />
|
||||
<ClInclude Include="GPU\WindowsVulkanContext.h" />
|
||||
<ClInclude Include="W32Util\ContextMenu.h" />
|
||||
<ClInclude Include="W32Util\DarkMode.h" />
|
||||
<ClInclude Include="W32Util\DialogManager.h" />
|
||||
<ClInclude Include="W32Util\IatHook.h" />
|
||||
<ClInclude Include="W32Util\Misc.h" />
|
||||
<ClInclude Include="W32Util\ShellUtil.h" />
|
||||
<ClInclude Include="W32Util\TabControl.h" />
|
||||
@ -1492,6 +1496,7 @@
|
||||
<ClInclude Include="MainWindow.h" />
|
||||
<ClInclude Include="DSoundStream.h" />
|
||||
<ClInclude Include="GPU\WindowsGLContext.h" />
|
||||
<ClInclude Include="W32Util\UAHMenuBar.h" />
|
||||
<ClInclude Include="WASAPIStream.h" />
|
||||
<ClInclude Include="WindowsAudio.h" />
|
||||
<ClInclude Include="WindowsHost.h" />
|
||||
|
@ -59,6 +59,9 @@
|
||||
<Filter Include="Build\CMake">
|
||||
<UniqueIdentifier>{8f39c005-9738-41c5-a8d8-cfc05bf178e8}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Windows\Darkmode">
|
||||
<UniqueIdentifier>{e6f1a7f6-807b-484e-9595-bdb58ecaa2ae}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Debugger\CtrlDisAsmView.cpp">
|
||||
@ -271,6 +274,12 @@
|
||||
<ClCompile Include="..\libretro\LibretroGLCoreContext.cpp">
|
||||
<Filter>Other Platforms\libretro</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="W32Util\DarkMode.cpp">
|
||||
<Filter>Windows\W32Util</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="W32Util\UAHMenuBar.cpp">
|
||||
<Filter>Windows\W32Util</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Debugger\CtrlDisAsmView.h">
|
||||
@ -553,6 +562,15 @@
|
||||
<ClInclude Include="..\ios\iCade\iCadeReaderView.h">
|
||||
<Filter>Other Platforms\iOS\iCade</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="W32Util\DarkMode.h">
|
||||
<Filter>Windows\W32Util</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="W32Util\IatHook.h">
|
||||
<Filter>Windows\W32Util</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="W32Util\UAHMenuBar.h">
|
||||
<Filter>Windows\W32Util</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="icon1.ico">
|
||||
|
229
Windows/W32Util/DarkMode.cpp
Normal file
229
Windows/W32Util/DarkMode.cpp
Normal file
@ -0,0 +1,229 @@
|
||||
#include "IatHook.h"
|
||||
#include "DarkMode.h"
|
||||
|
||||
fnSetWindowCompositionAttribute _SetWindowCompositionAttribute = nullptr;
|
||||
fnShouldAppsUseDarkMode _ShouldAppsUseDarkMode = nullptr;
|
||||
fnAllowDarkModeForWindow _AllowDarkModeForWindow = nullptr;
|
||||
fnAllowDarkModeForApp _AllowDarkModeForApp = nullptr;
|
||||
fnFlushMenuThemes _FlushMenuThemes = nullptr;
|
||||
fnRefreshImmersiveColorPolicyState _RefreshImmersiveColorPolicyState = nullptr;
|
||||
fnIsDarkModeAllowedForWindow _IsDarkModeAllowedForWindow = nullptr;
|
||||
fnGetIsImmersiveColorUsingHighContrast _GetIsImmersiveColorUsingHighContrast = nullptr;
|
||||
fnOpenNcThemeData _OpenNcThemeData = nullptr;
|
||||
// 1903 18362
|
||||
fnShouldSystemUseDarkMode _ShouldSystemUseDarkMode = nullptr;
|
||||
fnSetPreferredAppMode _SetPreferredAppMode = nullptr;
|
||||
fnSetWindowTheme _SetWindowTheme = nullptr;
|
||||
|
||||
bool g_darkModeSupported = false;
|
||||
bool g_darkModeEnabled = false;
|
||||
DWORD g_buildNumber = 0;
|
||||
|
||||
bool AllowDarkModeForWindow(HWND hWnd, bool allow)
|
||||
{
|
||||
if (g_darkModeSupported)
|
||||
return _AllowDarkModeForWindow(hWnd, allow);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsHighContrast()
|
||||
{
|
||||
HIGHCONTRASTW highContrast = { sizeof(highContrast) };
|
||||
if (SystemParametersInfoW(SPI_GETHIGHCONTRAST, sizeof(highContrast), &highContrast, FALSE))
|
||||
return highContrast.dwFlags & HCF_HIGHCONTRASTON;
|
||||
return false;
|
||||
}
|
||||
|
||||
void RefreshTitleBarThemeColor(HWND hWnd)
|
||||
{
|
||||
BOOL dark = FALSE;
|
||||
if (_IsDarkModeAllowedForWindow(hWnd) &&
|
||||
_ShouldAppsUseDarkMode() &&
|
||||
!IsHighContrast())
|
||||
{
|
||||
dark = TRUE;
|
||||
}
|
||||
if (g_buildNumber < 18362)
|
||||
SetPropW(hWnd, L"UseImmersiveDarkModeColors", reinterpret_cast<HANDLE>(static_cast<INT_PTR>(dark)));
|
||||
else if (_SetWindowCompositionAttribute)
|
||||
{
|
||||
WINDOWCOMPOSITIONATTRIBDATA data = { WCA_USEDARKMODECOLORS, &dark, sizeof(dark) };
|
||||
_SetWindowCompositionAttribute(hWnd, &data);
|
||||
}
|
||||
}
|
||||
|
||||
bool IsColorSchemeChangeMessage(LPARAM lParam)
|
||||
{
|
||||
bool is = false;
|
||||
if (lParam && CompareStringOrdinal(reinterpret_cast<LPCWCH>(lParam), -1, L"ImmersiveColorSet", -1, TRUE) == CSTR_EQUAL)
|
||||
{
|
||||
_RefreshImmersiveColorPolicyState();
|
||||
is = true;
|
||||
}
|
||||
_GetIsImmersiveColorUsingHighContrast(IHCM_REFRESH);
|
||||
return is;
|
||||
}
|
||||
|
||||
bool IsColorSchemeChangeMessage(UINT message, LPARAM lParam)
|
||||
{
|
||||
if (message == WM_SETTINGCHANGE)
|
||||
return IsColorSchemeChangeMessage(lParam);
|
||||
return false;
|
||||
}
|
||||
|
||||
void AllowDarkModeForApp(bool allow)
|
||||
{
|
||||
if (_AllowDarkModeForApp)
|
||||
_AllowDarkModeForApp(allow);
|
||||
else if (_SetPreferredAppMode)
|
||||
_SetPreferredAppMode(allow ? AllowDark : Default);
|
||||
}
|
||||
|
||||
void FixDarkScrollBar()
|
||||
{
|
||||
// Disable this, doesn't look good.
|
||||
return;
|
||||
|
||||
HMODULE hComctl = LoadLibraryExW(L"comctl32.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
|
||||
if (hComctl)
|
||||
{
|
||||
auto addr = FindDelayLoadThunkInModule(hComctl, "uxtheme.dll", 49); // OpenNcThemeData
|
||||
if (addr)
|
||||
{
|
||||
DWORD oldProtect;
|
||||
if (VirtualProtect(addr, sizeof(IMAGE_THUNK_DATA), PAGE_READWRITE, &oldProtect))
|
||||
{
|
||||
auto MyOpenThemeData = [](HWND hWnd, LPCWSTR classList) -> HTHEME {
|
||||
if (wcscmp(classList, L"ScrollBar") == 0)
|
||||
{
|
||||
hWnd = nullptr;
|
||||
classList = L"Explorer::ScrollBar";
|
||||
}
|
||||
return _OpenNcThemeData(hWnd, classList);
|
||||
};
|
||||
|
||||
addr->u1.Function = reinterpret_cast<ULONG_PTR>(static_cast<fnOpenNcThemeData>(MyOpenThemeData));
|
||||
VirtualProtect(addr, sizeof(IMAGE_THUNK_DATA), oldProtect, &oldProtect);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DarkModeInitDialog(HWND hDlg) {
|
||||
if (g_darkModeSupported) {
|
||||
_SetWindowTheme(GetDlgItem(hDlg, IDOK), L"Explorer", nullptr);
|
||||
SendMessageW(hDlg, WM_THEMECHANGED, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
LRESULT DarkModeDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
constexpr COLORREF darkBkColor = 0x383838;
|
||||
constexpr COLORREF darkTextColor = 0xFFFFFF;
|
||||
static HBRUSH hbrBkgnd = nullptr;
|
||||
|
||||
switch (message) {
|
||||
case WM_CTLCOLORDLG:
|
||||
case WM_CTLCOLORSTATIC:
|
||||
{
|
||||
if (g_darkModeSupported && g_darkModeEnabled)
|
||||
{
|
||||
HDC hdc = reinterpret_cast<HDC>(wParam);
|
||||
SetTextColor(hdc, darkTextColor);
|
||||
SetBkColor(hdc, darkBkColor);
|
||||
if (!hbrBkgnd)
|
||||
hbrBkgnd = CreateSolidBrush(darkBkColor);
|
||||
return reinterpret_cast<INT_PTR>(hbrBkgnd);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WM_SETTINGCHANGE:
|
||||
{
|
||||
if (g_darkModeSupported && IsColorSchemeChangeMessage(lParam))
|
||||
SendMessageW(hDlg, WM_THEMECHANGED, 0, 0);
|
||||
break;
|
||||
}
|
||||
case WM_THEMECHANGED:
|
||||
{
|
||||
if (g_darkModeSupported)
|
||||
{
|
||||
_AllowDarkModeForWindow(hDlg, g_darkModeEnabled);
|
||||
RefreshTitleBarThemeColor(hDlg);
|
||||
|
||||
HWND hButton = GetDlgItem(hDlg, IDOK);
|
||||
_AllowDarkModeForWindow(hButton, g_darkModeEnabled);
|
||||
SendMessageW(hButton, WM_THEMECHANGED, 0, 0);
|
||||
|
||||
UpdateWindow(hDlg);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool IsDarkModeEnabled() {
|
||||
return g_darkModeEnabled;
|
||||
}
|
||||
|
||||
constexpr bool CheckBuildNumber(DWORD buildNumber)
|
||||
{
|
||||
// TODO: This is BS.
|
||||
|
||||
return (buildNumber == 17763 || // 1809
|
||||
buildNumber == 18362 || // 1903
|
||||
buildNumber == 18363 || // 1909
|
||||
buildNumber >= 19041); // Windows 11
|
||||
}
|
||||
|
||||
void InitDarkMode()
|
||||
{
|
||||
auto RtlGetNtVersionNumbers = reinterpret_cast<fnRtlGetNtVersionNumbers>(GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "RtlGetNtVersionNumbers"));
|
||||
if (RtlGetNtVersionNumbers)
|
||||
{
|
||||
DWORD major, minor;
|
||||
RtlGetNtVersionNumbers(&major, &minor, &g_buildNumber);
|
||||
g_buildNumber &= ~0xF0000000;
|
||||
if (major == 10 && minor == 0 && CheckBuildNumber(g_buildNumber))
|
||||
{
|
||||
HMODULE hUxtheme = LoadLibraryExW(L"uxtheme.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
|
||||
if (hUxtheme)
|
||||
{
|
||||
_OpenNcThemeData = reinterpret_cast<fnOpenNcThemeData>(GetProcAddress(hUxtheme, MAKEINTRESOURCEA(49)));
|
||||
_RefreshImmersiveColorPolicyState = reinterpret_cast<fnRefreshImmersiveColorPolicyState>(GetProcAddress(hUxtheme, MAKEINTRESOURCEA(104)));
|
||||
_GetIsImmersiveColorUsingHighContrast = reinterpret_cast<fnGetIsImmersiveColorUsingHighContrast>(GetProcAddress(hUxtheme, MAKEINTRESOURCEA(106)));
|
||||
_ShouldAppsUseDarkMode = reinterpret_cast<fnShouldAppsUseDarkMode>(GetProcAddress(hUxtheme, MAKEINTRESOURCEA(132)));
|
||||
_AllowDarkModeForWindow = reinterpret_cast<fnAllowDarkModeForWindow>(GetProcAddress(hUxtheme, MAKEINTRESOURCEA(133)));
|
||||
|
||||
auto ord135 = GetProcAddress(hUxtheme, MAKEINTRESOURCEA(135));
|
||||
if (g_buildNumber < 18362)
|
||||
_AllowDarkModeForApp = reinterpret_cast<fnAllowDarkModeForApp>(ord135);
|
||||
else
|
||||
_SetPreferredAppMode = reinterpret_cast<fnSetPreferredAppMode>(ord135);
|
||||
|
||||
//_FlushMenuThemes = reinterpret_cast<fnFlushMenuThemes>(GetProcAddress(hUxtheme, MAKEINTRESOURCEA(136)));
|
||||
_IsDarkModeAllowedForWindow = reinterpret_cast<fnIsDarkModeAllowedForWindow>(GetProcAddress(hUxtheme, MAKEINTRESOURCEA(137)));
|
||||
|
||||
_SetWindowCompositionAttribute = reinterpret_cast<fnSetWindowCompositionAttribute>(GetProcAddress(GetModuleHandleW(L"user32.dll"), "SetWindowCompositionAttribute"));
|
||||
_SetWindowTheme = reinterpret_cast<fnSetWindowTheme>(GetProcAddress(hUxtheme, "SetWindowTheme"));
|
||||
|
||||
if (_OpenNcThemeData &&
|
||||
_RefreshImmersiveColorPolicyState &&
|
||||
_ShouldAppsUseDarkMode &&
|
||||
_AllowDarkModeForWindow &&
|
||||
(_AllowDarkModeForApp || _SetPreferredAppMode) &&
|
||||
//_FlushMenuThemes &&
|
||||
_IsDarkModeAllowedForWindow)
|
||||
{
|
||||
g_darkModeSupported = true;
|
||||
|
||||
AllowDarkModeForApp(true);
|
||||
_RefreshImmersiveColorPolicyState();
|
||||
|
||||
g_darkModeEnabled = _ShouldAppsUseDarkMode() && !IsHighContrast();
|
||||
|
||||
FixDarkScrollBar();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
110
Windows/W32Util/DarkMode.h
Normal file
110
Windows/W32Util/DarkMode.h
Normal file
@ -0,0 +1,110 @@
|
||||
#pragma once
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define NOMINMAX
|
||||
#include <Windows.h>
|
||||
#include <CommCtrl.h>
|
||||
#include <Uxtheme.h>
|
||||
#include <WindowsX.h>
|
||||
#include <Vssym32.h>
|
||||
|
||||
#include "IatHook.h"
|
||||
|
||||
enum IMMERSIVE_HC_CACHE_MODE
|
||||
{
|
||||
IHCM_USE_CACHED_VALUE,
|
||||
IHCM_REFRESH
|
||||
};
|
||||
|
||||
// 1903 18362
|
||||
enum PreferredAppMode
|
||||
{
|
||||
Default,
|
||||
AllowDark,
|
||||
ForceDark,
|
||||
ForceLight,
|
||||
Max
|
||||
};
|
||||
|
||||
enum WINDOWCOMPOSITIONATTRIB
|
||||
{
|
||||
WCA_UNDEFINED = 0,
|
||||
WCA_NCRENDERING_ENABLED = 1,
|
||||
WCA_NCRENDERING_POLICY = 2,
|
||||
WCA_TRANSITIONS_FORCEDISABLED = 3,
|
||||
WCA_ALLOW_NCPAINT = 4,
|
||||
WCA_CAPTION_BUTTON_BOUNDS = 5,
|
||||
WCA_NONCLIENT_RTL_LAYOUT = 6,
|
||||
WCA_FORCE_ICONIC_REPRESENTATION = 7,
|
||||
WCA_EXTENDED_FRAME_BOUNDS = 8,
|
||||
WCA_HAS_ICONIC_BITMAP = 9,
|
||||
WCA_THEME_ATTRIBUTES = 10,
|
||||
WCA_NCRENDERING_EXILED = 11,
|
||||
WCA_NCADORNMENTINFO = 12,
|
||||
WCA_EXCLUDED_FROM_LIVEPREVIEW = 13,
|
||||
WCA_VIDEO_OVERLAY_ACTIVE = 14,
|
||||
WCA_FORCE_ACTIVEWINDOW_APPEARANCE = 15,
|
||||
WCA_DISALLOW_PEEK = 16,
|
||||
WCA_CLOAK = 17,
|
||||
WCA_CLOAKED = 18,
|
||||
WCA_ACCENT_POLICY = 19,
|
||||
WCA_FREEZE_REPRESENTATION = 20,
|
||||
WCA_EVER_UNCLOAKED = 21,
|
||||
WCA_VISUAL_OWNER = 22,
|
||||
WCA_HOLOGRAPHIC = 23,
|
||||
WCA_EXCLUDED_FROM_DDA = 24,
|
||||
WCA_PASSIVEUPDATEMODE = 25,
|
||||
WCA_USEDARKMODECOLORS = 26,
|
||||
WCA_LAST = 27
|
||||
};
|
||||
|
||||
struct WINDOWCOMPOSITIONATTRIBDATA
|
||||
{
|
||||
WINDOWCOMPOSITIONATTRIB Attrib;
|
||||
PVOID pvData;
|
||||
SIZE_T cbData;
|
||||
};
|
||||
|
||||
using fnRtlGetNtVersionNumbers = void (WINAPI *)(LPDWORD major, LPDWORD minor, LPDWORD build);
|
||||
using fnSetWindowCompositionAttribute = BOOL (WINAPI *)(HWND hWnd, WINDOWCOMPOSITIONATTRIBDATA*);
|
||||
// 1809 17763
|
||||
using fnShouldAppsUseDarkMode = bool (WINAPI *)(); // ordinal 132
|
||||
using fnAllowDarkModeForWindow = bool (WINAPI *)(HWND hWnd, bool allow); // ordinal 133
|
||||
using fnAllowDarkModeForApp = bool (WINAPI *)(bool allow); // ordinal 135, in 1809
|
||||
using fnFlushMenuThemes = void (WINAPI *)(); // ordinal 136
|
||||
using fnRefreshImmersiveColorPolicyState = void (WINAPI *)(); // ordinal 104
|
||||
using fnIsDarkModeAllowedForWindow = bool (WINAPI *)(HWND hWnd); // ordinal 137
|
||||
using fnGetIsImmersiveColorUsingHighContrast = bool (WINAPI *)(IMMERSIVE_HC_CACHE_MODE mode); // ordinal 106
|
||||
using fnOpenNcThemeData = HTHEME(WINAPI *)(HWND hWnd, LPCWSTR pszClassList); // ordinal 49
|
||||
// 1903 18362
|
||||
using fnShouldSystemUseDarkMode = bool (WINAPI *)(); // ordinal 138
|
||||
using fnSetPreferredAppMode = PreferredAppMode (WINAPI *)(PreferredAppMode appMode); // ordinal 135, in 1903
|
||||
using fnIsDarkModeAllowedForApp = bool (WINAPI *)(); // ordinal 139
|
||||
using fnSetWindowTheme = void (WINAPI*)(HWND, LPCWSTR, LPCWSTR);
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
extern fnSetWindowCompositionAttribute _SetWindowCompositionAttribute;
|
||||
extern fnShouldAppsUseDarkMode _ShouldAppsUseDarkMode;
|
||||
extern fnAllowDarkModeForWindow _AllowDarkModeForWindow;
|
||||
extern fnAllowDarkModeForApp _AllowDarkModeForApp;
|
||||
extern fnFlushMenuThemes _FlushMenuThemes;
|
||||
extern fnRefreshImmersiveColorPolicyState _RefreshImmersiveColorPolicyState;
|
||||
extern fnIsDarkModeAllowedForWindow _IsDarkModeAllowedForWindow;
|
||||
extern fnGetIsImmersiveColorUsingHighContrast _GetIsImmersiveColorUsingHighContrast;
|
||||
extern fnOpenNcThemeData _OpenNcThemeData;
|
||||
// 1903 18362
|
||||
extern fnShouldSystemUseDarkMode _ShouldSystemUseDarkMode;
|
||||
extern fnSetPreferredAppMode _SetPreferredAppMode;
|
||||
extern fnSetWindowTheme _SetWindowTheme;
|
||||
|
||||
extern bool g_darkModeSupported;
|
||||
extern bool g_darkModeEnabled;
|
||||
|
||||
void InitDarkMode();
|
||||
bool AllowDarkModeForWindow(HWND hWnd, bool allow);
|
||||
void RefreshTitleBarThemeColor(HWND hWnd);
|
||||
bool IsColorSchemeChangeMessage(LPARAM lParam);
|
||||
bool IsDarkModeEnabled();
|
||||
|
||||
void DarkModeInitDialog(HWND hDlg);
|
||||
LRESULT DarkModeDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
|
91
Windows/W32Util/IatHook.h
Normal file
91
Windows/W32Util/IatHook.h
Normal file
@ -0,0 +1,91 @@
|
||||
// This file contains code from
|
||||
// https://github.com/stevemk14ebr/PolyHook_2_0/blob/master/sources/IatHook.cpp
|
||||
// which is licensed under the MIT License.
|
||||
// See PolyHook_2_0-LICENSE for more information.
|
||||
|
||||
#pragma once
|
||||
|
||||
template <typename T, typename T1, typename T2>
|
||||
constexpr T RVA2VA(T1 base, T2 rva)
|
||||
{
|
||||
return reinterpret_cast<T>(reinterpret_cast<ULONG_PTR>(base) + rva);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr T DataDirectoryFromModuleBase(void *moduleBase, size_t entryID)
|
||||
{
|
||||
auto dosHdr = reinterpret_cast<PIMAGE_DOS_HEADER>(moduleBase);
|
||||
auto ntHdr = RVA2VA<PIMAGE_NT_HEADERS>(moduleBase, dosHdr->e_lfanew);
|
||||
auto dataDir = ntHdr->OptionalHeader.DataDirectory;
|
||||
return RVA2VA<T>(moduleBase, dataDir[entryID].VirtualAddress);
|
||||
}
|
||||
|
||||
inline PIMAGE_THUNK_DATA FindAddressByName(void *moduleBase, PIMAGE_THUNK_DATA impName, PIMAGE_THUNK_DATA impAddr, const char *funcName)
|
||||
{
|
||||
for (; impName->u1.Ordinal; ++impName, ++impAddr)
|
||||
{
|
||||
if (IMAGE_SNAP_BY_ORDINAL(impName->u1.Ordinal))
|
||||
continue;
|
||||
|
||||
auto import = RVA2VA<PIMAGE_IMPORT_BY_NAME>(moduleBase, impName->u1.AddressOfData);
|
||||
if (strcmp(import->Name, funcName) != 0)
|
||||
continue;
|
||||
return impAddr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline PIMAGE_THUNK_DATA FindAddressByOrdinal(void *moduleBase, PIMAGE_THUNK_DATA impName, PIMAGE_THUNK_DATA impAddr, uint16_t ordinal)
|
||||
{
|
||||
for (; impName->u1.Ordinal; ++impName, ++impAddr)
|
||||
{
|
||||
if (IMAGE_SNAP_BY_ORDINAL(impName->u1.Ordinal) && IMAGE_ORDINAL(impName->u1.Ordinal) == ordinal)
|
||||
return impAddr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline PIMAGE_THUNK_DATA FindIatThunkInModule(void *moduleBase, const char *dllName, const char *funcName)
|
||||
{
|
||||
auto imports = DataDirectoryFromModuleBase<PIMAGE_IMPORT_DESCRIPTOR>(moduleBase, IMAGE_DIRECTORY_ENTRY_IMPORT);
|
||||
for (; imports->Name; ++imports)
|
||||
{
|
||||
if (_stricmp(RVA2VA<LPCSTR>(moduleBase, imports->Name), dllName) != 0)
|
||||
continue;
|
||||
|
||||
auto origThunk = RVA2VA<PIMAGE_THUNK_DATA>(moduleBase, imports->OriginalFirstThunk);
|
||||
auto thunk = RVA2VA<PIMAGE_THUNK_DATA>(moduleBase, imports->FirstThunk);
|
||||
return FindAddressByName(moduleBase, origThunk, thunk, funcName);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline PIMAGE_THUNK_DATA FindDelayLoadThunkInModule(void *moduleBase, const char *dllName, const char *funcName)
|
||||
{
|
||||
auto imports = DataDirectoryFromModuleBase<PIMAGE_DELAYLOAD_DESCRIPTOR>(moduleBase, IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT);
|
||||
for (; imports->DllNameRVA; ++imports)
|
||||
{
|
||||
if (_stricmp(RVA2VA<LPCSTR>(moduleBase, imports->DllNameRVA), dllName) != 0)
|
||||
continue;
|
||||
|
||||
auto impName = RVA2VA<PIMAGE_THUNK_DATA>(moduleBase, imports->ImportNameTableRVA);
|
||||
auto impAddr = RVA2VA<PIMAGE_THUNK_DATA>(moduleBase, imports->ImportAddressTableRVA);
|
||||
return FindAddressByName(moduleBase, impName, impAddr, funcName);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline PIMAGE_THUNK_DATA FindDelayLoadThunkInModule(void *moduleBase, const char *dllName, uint16_t ordinal)
|
||||
{
|
||||
auto imports = DataDirectoryFromModuleBase<PIMAGE_DELAYLOAD_DESCRIPTOR>(moduleBase, IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT);
|
||||
for (; imports->DllNameRVA; ++imports)
|
||||
{
|
||||
if (_stricmp(RVA2VA<LPCSTR>(moduleBase, imports->DllNameRVA), dllName) != 0)
|
||||
continue;
|
||||
|
||||
auto impName = RVA2VA<PIMAGE_THUNK_DATA>(moduleBase, imports->ImportNameTableRVA);
|
||||
auto impAddr = RVA2VA<PIMAGE_THUNK_DATA>(moduleBase, imports->ImportAddressTableRVA);
|
||||
return FindAddressByOrdinal(moduleBase, impName, impAddr, ordinal);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
110
Windows/W32Util/UAHMenuBar.cpp
Normal file
110
Windows/W32Util/UAHMenuBar.cpp
Normal file
@ -0,0 +1,110 @@
|
||||
#include "Common/CommonWindows.h"
|
||||
|
||||
#include <Uxtheme.h>
|
||||
#include <vsstyle.h>
|
||||
|
||||
#include "Windows/W32Util/UAHMenuBar.h"
|
||||
|
||||
static HTHEME g_menuTheme = nullptr;
|
||||
|
||||
// processes messages related to UAH / custom menubar drawing.
|
||||
// return true if handled, false to continue with normal processing in your wndproc
|
||||
bool UAHDarkModeWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT *lr)
|
||||
{
|
||||
switch (message)
|
||||
{
|
||||
case WM_UAHDRAWMENU:
|
||||
{
|
||||
UAHMENU *pUDM = (UAHMENU *)lParam;
|
||||
RECT rc = { 0 };
|
||||
|
||||
// get the menubar rect
|
||||
{
|
||||
MENUBARINFO mbi = { sizeof(mbi) };
|
||||
GetMenuBarInfo(hWnd, OBJID_MENU, 0, &mbi);
|
||||
|
||||
RECT rcWindow;
|
||||
GetWindowRect(hWnd, &rcWindow);
|
||||
|
||||
// the rcBar is offset by the window rect
|
||||
rc = mbi.rcBar;
|
||||
OffsetRect(&rc, -rcWindow.left, -rcWindow.top);
|
||||
|
||||
rc.top -= 1;
|
||||
}
|
||||
|
||||
if (!g_menuTheme) {
|
||||
g_menuTheme = OpenThemeData(hWnd, L"Menu");
|
||||
}
|
||||
|
||||
DrawThemeBackground(g_menuTheme, pUDM->hdc, MENU_POPUPITEM, MPI_NORMAL, &rc, nullptr);
|
||||
return true;
|
||||
}
|
||||
case WM_UAHDRAWMENUITEM:
|
||||
{
|
||||
UAHDRAWMENUITEM *pUDMI = (UAHDRAWMENUITEM *)lParam;
|
||||
|
||||
// get the menu item string
|
||||
wchar_t menuString[256] = { 0 };
|
||||
MENUITEMINFO mii = { sizeof(mii), MIIM_STRING };
|
||||
{
|
||||
mii.dwTypeData = menuString;
|
||||
mii.cch = (sizeof(menuString) / 2) - 1;
|
||||
|
||||
GetMenuItemInfo(pUDMI->um.hmenu, pUDMI->umi.iPosition, TRUE, &mii);
|
||||
}
|
||||
|
||||
// get the item state for drawing
|
||||
|
||||
DWORD dwFlags = DT_CENTER | DT_SINGLELINE | DT_VCENTER;
|
||||
|
||||
int iTextStateID = 0;
|
||||
int iBackgroundStateID = 0;
|
||||
{
|
||||
if ((pUDMI->dis.itemState & ODS_INACTIVE) | (pUDMI->dis.itemState & ODS_DEFAULT)) {
|
||||
// normal display
|
||||
iTextStateID = MPI_NORMAL;
|
||||
iBackgroundStateID = MPI_NORMAL;
|
||||
}
|
||||
if (pUDMI->dis.itemState & ODS_HOTLIGHT) {
|
||||
// hot tracking
|
||||
iTextStateID = MPI_HOT;
|
||||
iBackgroundStateID = MPI_HOT;
|
||||
}
|
||||
if (pUDMI->dis.itemState & ODS_SELECTED) {
|
||||
// clicked -- MENU_POPUPITEM has no state for this, though MENU_BARITEM does
|
||||
iTextStateID = MPI_HOT;
|
||||
iBackgroundStateID = MPI_HOT;
|
||||
}
|
||||
if ((pUDMI->dis.itemState & ODS_GRAYED) || (pUDMI->dis.itemState & ODS_DISABLED)) {
|
||||
// disabled / grey text
|
||||
iTextStateID = MPI_DISABLED;
|
||||
iBackgroundStateID = MPI_DISABLED;
|
||||
}
|
||||
if (pUDMI->dis.itemState & ODS_NOACCEL) {
|
||||
dwFlags |= DT_HIDEPREFIX;
|
||||
}
|
||||
}
|
||||
|
||||
if (!g_menuTheme) {
|
||||
g_menuTheme = OpenThemeData(hWnd, L"Menu");
|
||||
}
|
||||
|
||||
DrawThemeBackground(g_menuTheme, pUDMI->um.hdc, MENU_POPUPITEM, iBackgroundStateID, &pUDMI->dis.rcItem, nullptr);
|
||||
DrawThemeText(g_menuTheme, pUDMI->um.hdc, MENU_POPUPITEM, iTextStateID, menuString, mii.cch, dwFlags, 0, &pUDMI->dis.rcItem);
|
||||
|
||||
return true;
|
||||
}
|
||||
case WM_THEMECHANGED:
|
||||
{
|
||||
if (g_menuTheme) {
|
||||
CloseThemeData(g_menuTheme);
|
||||
g_menuTheme = nullptr;
|
||||
}
|
||||
// continue processing in main wndproc
|
||||
return false;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
74
Windows/W32Util/UAHMenuBar.h
Normal file
74
Windows/W32Util/UAHMenuBar.h
Normal file
@ -0,0 +1,74 @@
|
||||
#pragma once
|
||||
|
||||
// MIT license, see LICENSE
|
||||
// Copyright(c) 2021 adzm / Adam D. Walling
|
||||
|
||||
// processes messages related to UAH / custom menubar drawing.
|
||||
// return true if handled, false to continue with normal processing in your wndproc
|
||||
bool UAHDarkModeWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT* lr);
|
||||
|
||||
// window messages related to menu bar drawing
|
||||
#define WM_UAHDESTROYWINDOW 0x0090 // handled by DefWindowProc
|
||||
#define WM_UAHDRAWMENU 0x0091 // lParam is UAHMENU
|
||||
#define WM_UAHDRAWMENUITEM 0x0092 // lParam is UAHDRAWMENUITEM
|
||||
#define WM_UAHINITMENU 0x0093 // handled by DefWindowProc
|
||||
#define WM_UAHMEASUREMENUITEM 0x0094 // lParam is UAHMEASUREMENUITEM
|
||||
#define WM_UAHNCPAINTMENUPOPUP 0x0095 // handled by DefWindowProc
|
||||
|
||||
// describes the sizes of the menu bar or menu item
|
||||
typedef union tagUAHMENUITEMMETRICS
|
||||
{
|
||||
// cx appears to be 14 / 0xE less than rcItem's width!
|
||||
// cy 0x14 seems stable, i wonder if it is 4 less than rcItem's height which is always 24 atm
|
||||
struct {
|
||||
DWORD cx;
|
||||
DWORD cy;
|
||||
} rgsizeBar[2];
|
||||
struct {
|
||||
DWORD cx;
|
||||
DWORD cy;
|
||||
} rgsizePopup[4];
|
||||
} UAHMENUITEMMETRICS;
|
||||
|
||||
// not really used in our case but part of the other structures
|
||||
typedef struct tagUAHMENUPOPUPMETRICS
|
||||
{
|
||||
DWORD rgcx[4];
|
||||
DWORD fUpdateMaxWidths : 2; // from kernel symbols, padded to full dword
|
||||
} UAHMENUPOPUPMETRICS;
|
||||
|
||||
// hmenu is the main window menu; hdc is the context to draw in
|
||||
typedef struct tagUAHMENU
|
||||
{
|
||||
HMENU hmenu;
|
||||
HDC hdc;
|
||||
DWORD dwFlags; // no idea what these mean, in my testing it's either 0x00000a00 or sometimes 0x00000a10
|
||||
} UAHMENU;
|
||||
|
||||
// menu items are always referred to by iPosition here
|
||||
typedef struct tagUAHMENUITEM
|
||||
{
|
||||
int iPosition; // 0-based position of menu item in menubar
|
||||
UAHMENUITEMMETRICS umim;
|
||||
UAHMENUPOPUPMETRICS umpm;
|
||||
} UAHMENUITEM;
|
||||
|
||||
// the DRAWITEMSTRUCT contains the states of the menu items, as well as
|
||||
// the position index of the item in the menu, which is duplicated in
|
||||
// the UAHMENUITEM's iPosition as well
|
||||
typedef struct UAHDRAWMENUITEM
|
||||
{
|
||||
DRAWITEMSTRUCT dis; // itemID looks uninitialized
|
||||
UAHMENU um;
|
||||
UAHMENUITEM umi;
|
||||
} UAHDRAWMENUITEM;
|
||||
|
||||
// the MEASUREITEMSTRUCT is intended to be filled with the size of the item
|
||||
// height appears to be ignored, but width can be modified
|
||||
typedef struct tagUAHMEASUREMENUITEM
|
||||
{
|
||||
MEASUREITEMSTRUCT mis;
|
||||
UAHMENU um;
|
||||
UAHMENUITEM umi;
|
||||
} UAHMEASUREMENUITEM;
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include "Common/Thread/ThreadUtil.h"
|
||||
#include "Common/Data/Encoding/Utf8.h"
|
||||
#include "Common/Net/Resolve.h"
|
||||
#include "W32Util/DarkMode.h"
|
||||
|
||||
#include "Core/Config.h"
|
||||
#include "Core/ConfigValues.h"
|
||||
@ -553,6 +554,8 @@ static void WinMainInit() {
|
||||
// FMA3 support in the 2013 CRT is broken on Vista and Windows 7 RTM (fixed in SP1). Just disable it.
|
||||
_set_FMA3_enable(0);
|
||||
#endif
|
||||
|
||||
InitDarkMode();
|
||||
}
|
||||
|
||||
static void WinMainCleanup() {
|
||||
|
Loading…
Reference in New Issue
Block a user