-
Notifications
You must be signed in to change notification settings - Fork 8.4k
/
windowtheme.cpp
118 lines (101 loc) · 3.54 KB
/
windowtheme.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "precomp.h"
#include "windowtheme.hpp"
#include <dwmapi.h>
using namespace Microsoft::Console::Interactivity::Win32;
#define DWMWA_USE_IMMERSIVE_DARK_MODE 19
#define DARK_MODE_STRING_NAME L"DarkMode_Explorer"
#define UXTHEME_DLL_NAME L"uxtheme.dll"
#define UXTHEME_SHOULDAPPSUSEDARKMODE_ORDINAL 132
// Routine Description:
// - Constructs window theme class (holding module references for function lookups)
WindowTheme::WindowTheme()
{
// NOTE: Use LoadLibraryExW with LOAD_LIBRARY_SEARCH_SYSTEM32 flag below to avoid unneeded directory traversal.
// This has triggered CPG boot IO warnings in the past.
_module.reset(LoadLibraryExW(UXTHEME_DLL_NAME, nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32));
}
// Routine Description:
// - Attempts to set the dark mode on the given HWND.
// - Will check the system for user preferences and high contrast to see if it's a good idea
// before setting it.
// Arguments:
// - hwnd - Window to apply dark mode to
// Return Value:
// - S_OK or suitable HRESULT from theming or DWM engines.
[[nodiscard]] HRESULT WindowTheme::TrySetDarkMode(HWND hwnd) const noexcept
{
// I have to be a big B BOOL or DwnSetWindowAttribute will be upset (E_INVALIDARG) when I am passed in.
const BOOL isDarkMode = !!_IsDarkMode();
if (isDarkMode)
{
RETURN_IF_FAILED(SetWindowTheme(hwnd, DARK_MODE_STRING_NAME, nullptr));
RETURN_IF_FAILED(DwmSetWindowAttribute(hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE, &isDarkMode, sizeof(isDarkMode)));
}
else
{
RETURN_IF_FAILED(SetWindowTheme(hwnd, L"", nullptr));
RETURN_IF_FAILED(DwmSetWindowAttribute(hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE, &isDarkMode, sizeof(isDarkMode)));
}
return S_OK;
}
// Routine Description:
// - Logical determination of if we should use the dark mode or not.
// - Combines user preferences and high contrast accessibility settings.
// Arguments:
// - <none>
// Return Value:
// - TRUE if dark mode is allowed. FALSE if it is not.
bool WindowTheme::_IsDarkMode() const noexcept
{
if (_ShouldAppsUseDarkMode() && !_IsHighContrast())
{
return true;
}
else
{
return false;
}
}
// Routine Description:
// - Looks up the high contrast state of the system.
// Arguments:
// - <none>
// Return Value:
// - True if the system is in high contrast (shouldn't change theme further.) False otherwise.
bool WindowTheme::_IsHighContrast() const noexcept
{
BOOL fHighContrast = FALSE;
HIGHCONTRAST hc = { sizeof(hc) };
if (SystemParametersInfo(SPI_GETHIGHCONTRAST, sizeof(hc), &hc, 0))
{
fHighContrast = (HCF_HIGHCONTRASTON & hc.dwFlags);
}
return fHighContrast;
}
// Routine Description:
// - Looks up the user preference for dark mode.
// Arguments:
// - <none>
// Return Value:
// - True if the user chose dark mode in settings. False otherwise.
bool WindowTheme::_ShouldAppsUseDarkMode() const noexcept
{
if (_module.get() != nullptr)
{
typedef bool(WINAPI * PfnShouldAppsUseDarkMode)();
static bool tried = false;
static PfnShouldAppsUseDarkMode pfn = nullptr;
if (!tried)
{
pfn = (PfnShouldAppsUseDarkMode)GetProcAddress(_module.get(), MAKEINTRESOURCEA(UXTHEME_SHOULDAPPSUSEDARKMODE_ORDINAL));
}
tried = true;
if (pfn != nullptr)
{
return pfn();
}
}
return false;
}