aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRadAd <adamgates84+github@gmail.com>2019-07-15 15:35:28 +1000
committerRadAd <adamgates84+github@gmail.com>2019-07-15 15:35:28 +1000
commit06c3cab81c97ad295228a3a51bfd689784f448d5 (patch)
tree57b626ec94d86135f39a6934a258cc906d7a89c8
parent18d6af8d54bce0d270e495013370e76910713617 (diff)
downloadRadTerminal-06c3cab81c97ad295228a3a51bfd689784f448d5.tar.gz
RadTerminal-06c3cab81c97ad295228a3a51bfd689784f448d5.zip
Enable dark mode
-rw-r--r--DarkMode.h184
-rw-r--r--RadTerminal.cpp32
-rw-r--r--RadTerminal.vcxproj10
-rw-r--r--RadTerminalFrame.cpp4
4 files changed, 214 insertions, 16 deletions
diff --git a/DarkMode.h b/DarkMode.h
new file mode 100644
index 0000000..207ff6a
--- /dev/null
+++ b/DarkMode.h
@@ -0,0 +1,184 @@
+// https://github.com/ysc3839/win32-darkmode/blob/master/win32-darkmode/DarkMode.h
+
+#pragma once
+#include <Windows.h>
+#include <dwmapi.h>
+//#include "IatHook.h"
+
+enum IMMERSIVE_HC_CACHE_MODE
+{
+ IHCM_USE_CACHED_VALUE,
+ IHCM_REFRESH
+};
+
+// Insider 18334
+enum PreferredAppMode
+{
+ Default,
+ AllowDark,
+ ForceDark,
+ ForceLight,
+ Max
+};
+
+using fnRtlGetNtVersionNumbers = void (WINAPI *)(LPDWORD major, LPDWORD minor, LPDWORD build);
+// 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, removed since 18334
+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
+ // Insider 18290
+using fnShouldSystemUseDarkMode = bool (WINAPI *)(); // ordinal 138
+ // Insider 18334
+using fnSetPreferredAppMode = PreferredAppMode(WINAPI *)(PreferredAppMode appMode); // ordinal 135, since 18334
+using fnIsDarkModeAllowedForApp = bool (WINAPI *)(); // ordinal 139
+
+fnShouldAppsUseDarkMode _ShouldAppsUseDarkMode = nullptr;
+fnAllowDarkModeForWindow _AllowDarkModeForWindow = nullptr;
+fnAllowDarkModeForApp _AllowDarkModeForApp = nullptr;
+fnFlushMenuThemes _FlushMenuThemes = nullptr;
+fnRefreshImmersiveColorPolicyState _RefreshImmersiveColorPolicyState = nullptr;
+fnIsDarkModeAllowedForWindow _IsDarkModeAllowedForWindow = nullptr;
+fnGetIsImmersiveColorUsingHighContrast _GetIsImmersiveColorUsingHighContrast = nullptr;
+fnOpenNcThemeData _OpenNcThemeData = nullptr;
+// Insider 18290
+fnShouldSystemUseDarkMode _ShouldSystemUseDarkMode = nullptr;
+// Insider 18334
+fnSetPreferredAppMode _SetPreferredAppMode = 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;
+ }
+ DwmSetWindowAttribute(hWnd, 19, &dark, sizeof(dark));
+}
+
+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()
+{
+#if 0
+ auto addr = FindDelayLoadThunkInModule(GetModuleHandleW(L"comctl32.dll"), "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);
+ }
+ }
+#endif
+}
+
+void InitDarkMode()
+{
+ fnRtlGetNtVersionNumbers 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 && 17763 <= g_buildNumber && g_buildNumber <= 18362) // Windows 10 1809 10.0.17763 - 1903 10.0.18362
+ {
+ 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 < 18334)
+ _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)));
+
+ if (_OpenNcThemeData &&
+ _RefreshImmersiveColorPolicyState &&
+ _ShouldAppsUseDarkMode &&
+ _AllowDarkModeForWindow &&
+ (_AllowDarkModeForApp || _SetPreferredAppMode) &&
+ //_FlushMenuThemes &&
+ _IsDarkModeAllowedForWindow)
+ {
+ g_darkModeSupported = true;
+
+ AllowDarkModeForApp(true);
+ _RefreshImmersiveColorPolicyState();
+
+ g_darkModeEnabled = _ShouldAppsUseDarkMode() && !IsHighContrast();
+
+ FixDarkScrollBar();
+ }
+ }
+ }
+ }
+}
diff --git a/RadTerminal.cpp b/RadTerminal.cpp
index 05ebfd5..4a9a8f3 100644
--- a/RadTerminal.cpp
+++ b/RadTerminal.cpp
@@ -4,6 +4,7 @@
#include <string>
#include "ProcessUtils.h"
#include "WinUtils.h"
+#include "DarkMode.h"
#include "libtsm\src\tsm\libtsm.h"
#include "libtsm\external\xkbcommon\xkbcommon-keysyms.h"
#include "resource.h"
@@ -64,9 +65,11 @@ void ShowError(HWND hWnd, LPCTSTR msg, HRESULT hr)
ShowError(hWnd, __FUNCTIONW__ TEXT(": ") TEXT(#x), 0); \
}
-HWND CreateRadTerminalFrame(HINSTANCE hInstance, int nCmdShow);
+HWND CreateRadTerminalFrame(HINSTANCE hInstance);
LRESULT CALLBACK RadTerminalWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+HWND ActionNewWindow(HWND hWnd, bool bParseCmdLine);
+
ATOM RegisterRadTerminal(HINSTANCE hInstance)
{
WNDCLASS wc = {};
@@ -87,8 +90,6 @@ ATOM GetRadTerminalAtom(HINSTANCE hInstance)
return g_atom;
}
-HWND ActionNewWindow(HWND hWnd, bool bParseCmdLine);
-
struct RadTerminalCreate
{
int iFontHeight;
@@ -166,16 +167,18 @@ RadTerminalCreate GetDefaultTerminalCreate(bool bParseCmdLine)
int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE, PTSTR pCmdLine, int nCmdShow)
{
+ InitDarkMode();
+
HWND hWnd = NULL;
HWND hWndMDIClient = NULL;
HACCEL hAccel = NULL;
- bool bMDI = false;
+ bool bMDI = true;
CHECK(GetRadTerminalAtom(hInstance), EXIT_FAILURE);
if (bMDI)
{
- hWnd = CreateRadTerminalFrame(hInstance, nCmdShow);
+ hWnd = CreateRadTerminalFrame(hInstance);
CHECK(hWnd, EXIT_FAILURE);
hWndMDIClient = GetMDIClient(hWnd);
@@ -209,10 +212,17 @@ int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE, PTSTR pCmdLine, int nCmdSho
&rtc
);
CHECK(hWnd, EXIT_FAILURE);
+ }
- ShowWindow(hWnd, nCmdShow);
+ if (g_darkModeEnabled)
+ {
+ SetWindowTheme(hWnd, L"DarkMode_Explorer", NULL); // Needed for scrollbar
+ AllowDarkModeForWindow(hWnd, true);
+ RefreshTitleBarThemeColor(hWnd);
}
+ ShowWindow(hWnd, nCmdShow);
+
MSG msg = {};
while (GetMessage(&msg, (HWND) NULL, 0, 0))
{
@@ -294,9 +304,8 @@ void tsm_log(void *data,
va_list args)
{
char buf[1024];
- sprintf_s(buf, "tsm_log: %s:%d %s %s %d\n", strrchr(file, '\\'), line, func, subs, sev);
+ sprintf_s(buf, "tsm_log: %d %s:%d %s %s - ", sev, strrchr(file, '\\'), line, func, subs);
OutputDebugStringA(buf);
- OutputDebugStringA("tsm_log: ");
vsprintf_s(buf, format, args);
OutputDebugStringA(buf);
OutputDebugStringA("\n");
@@ -685,8 +694,13 @@ HWND ActionNewWindow(HWND hWnd, bool bParseCmdLine)
CHECK(hChildWnd != NULL, NULL);
SetWindowLong(hChildWnd, GWL_EXSTYLE, GetWindowExStyle(hChildWnd) | WS_EX_ACCEPTFILES);
+ if (false && g_darkModeEnabled) // TODO Doesn't seem to work MDI child windows
+ {
+ SetWindowTheme(hWnd, L"DarkMode_Explorer", NULL); // Needed for scrollbar
+ AllowDarkModeForWindow(hWnd, true);
+ RefreshTitleBarThemeColor(hWnd);
+ }
- ShowWindow(hChildWnd, SW_SHOW);
return hChildWnd;
}
diff --git a/RadTerminal.vcxproj b/RadTerminal.vcxproj
index b5f092b..7efcf80 100644
--- a/RadTerminal.vcxproj
+++ b/RadTerminal.vcxproj
@@ -78,8 +78,8 @@
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">kernel32.lib;user32.lib;gdi32.lib;uxtheme.lib;%(AdditionalDependencies)</AdditionalDependencies>
- <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">kernel32.lib;user32.lib;gdi32.lib;uxtheme.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">kernel32.lib;user32.lib;gdi32.lib;uxtheme.lib;dwmapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">kernel32.lib;user32.lib;gdi32.lib;uxtheme.lib;dwmapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
@@ -93,8 +93,8 @@
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">kernel32.lib;user32.lib;gdi32.lib;uxtheme.lib;%(AdditionalDependencies)</AdditionalDependencies>
- <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Release|x64'">kernel32.lib;user32.lib;gdi32.lib;uxtheme.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">kernel32.lib;user32.lib;gdi32.lib;uxtheme.lib;dwmapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalDependencies Condition="'$(Configuration)|$(Platform)'=='Release|x64'">kernel32.lib;user32.lib;gdi32.lib;uxtheme.lib;dwmapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
@@ -108,6 +108,8 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
+ <ClInclude Include="DarkMode.h" />
+ <ClInclude Include="IatHook.h" />
<ClInclude Include="ProcessUtils.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="WinUtils.h" />
diff --git a/RadTerminalFrame.cpp b/RadTerminalFrame.cpp
index 9ed7ebf..1d2aeff 100644
--- a/RadTerminalFrame.cpp
+++ b/RadTerminalFrame.cpp
@@ -8,7 +8,7 @@
HWND ActionNewWindow(HWND hWnd, bool bParseCmdLine);
LRESULT CALLBACK RadTerminalMDIFrameProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
-HWND CreateRadTerminalFrame(HINSTANCE hInstance, int nCmdShow)
+HWND CreateRadTerminalFrame(HINSTANCE hInstance)
{
WNDCLASS wcMDIFrame = {};
@@ -36,8 +36,6 @@ HWND CreateRadTerminalFrame(HINSTANCE hInstance, int nCmdShow)
if (hFrame == NULL)
return NULL;
- ShowWindow(hFrame, nCmdShow);
-
return hFrame;
}