Use dark Windows title bar for night mode.

This commit is contained in:
John Preston 2020-07-24 16:15:32 +04:00
parent 511067981d
commit c86ced8a1e
5 changed files with 243 additions and 17 deletions

View file

@ -112,11 +112,44 @@ MainWindow::MainWindow(not_null<Window::Controller*> controller)
_shadow->setColor(st::windowShadowFg->c);
}
});
Core::App().settings().nativeWindowFrameChanges(
) | rpl::start_with_next([=] {
initShadows();
validateWindowTheme();
fixMaximizedWindow();
setupNativeWindowFrame();
}
void MainWindow::setupNativeWindowFrame() {
auto nativeFrame = rpl::single(
Core::App().settings().nativeWindowFrame()
) | rpl::then(
Core::App().settings().nativeWindowFrameChanges()
);
using BackgroundUpdate = Window::Theme::BackgroundUpdate;
auto paletteChanges = base::ObservableViewer(
*Window::Theme::Background()
) | rpl::filter([=](const BackgroundUpdate &update) {
return update.type == BackgroundUpdate::Type::ApplyingTheme;
}) | rpl::to_empty;
auto nightMode = rpl::single(
rpl::empty_value()
) | rpl::then(
std::move(paletteChanges)
) | rpl::map([=] {
return Window::Theme::IsNightMode();
}) | rpl::distinct_until_changed();
rpl::combine(
std::move(nativeFrame),
std::move(nightMode)
) | rpl::skip(1) | rpl::start_with_next([=](bool native, bool night) {
const auto nativeChanged = (_wasNativeFrame != native);
if (nativeChanged) {
_wasNativeFrame = native;
initShadows();
}
validateWindowTheme(native, night);
if (nativeChanged) {
fixMaximizedWindow();
}
}, lifetime());
}
@ -136,11 +169,13 @@ void MainWindow::shadowsUpdate(
}
void MainWindow::shadowsActivate() {
_hasActiveFrame = true;
// _shadow->setColor(_shActive);
shadowsUpdate(Ui::Platform::WindowShadow::Change::Activate);
}
void MainWindow::shadowsDeactivate() {
_hasActiveFrame = false;
// _shadow->setColor(_shInactive);
}
@ -395,7 +430,9 @@ void MainWindow::updateCustomMargins() {
}
if (!_themeInited) {
_themeInited = true;
validateWindowTheme();
validateWindowTheme(
Core::App().settings().nativeWindowFrame(),
Window::Theme::IsNightMode());
}
_inUpdateMargins = false;
}
@ -444,17 +481,104 @@ QMargins MainWindow::computeCustomMargins() {
return margins;
}
void MainWindow::validateWindowTheme() {
if (IsWindows8OrGreater()) {
void MainWindow::validateWindowTheme(bool native, bool night) {
if (!Dlls::SetWindowTheme) {
return;
} else if (!IsWindows8OrGreater()) {
const auto empty = native ? nullptr : L" ";
Dlls::SetWindowTheme(ps_hWnd, empty, empty);
QApplication::setStyle(QStyleFactory::create(u"Windows"_q));
} else if (!Platform::IsDarkModeSupported()/*
|| (!Dlls::AllowDarkModeForApp && !Dlls::SetPreferredAppMode)
|| !Dlls::AllowDarkModeForWindow
|| !Dlls::RefreshImmersiveColorPolicyState
|| !Dlls::FlushMenuThemes*/) {
return;
} else if (!native) {
Dlls::SetWindowTheme(ps_hWnd, nullptr, nullptr);
return;
} else if (Dlls::SetWindowTheme != nullptr) {
if (Core::App().settings().nativeWindowFrame()) {
Dlls::SetWindowTheme(ps_hWnd, nullptr, nullptr);
} else {
Dlls::SetWindowTheme(ps_hWnd, L" ", L" ");
}
QApplication::setStyle(QStyleFactory::create(qsl("Windows")));
}
// See "https://github.com/microsoft/terminal/blob/"
// "eb480b6bbbd83a2aafbe62992d360838e0ab9da5/"
// "src/interactivity/win32/windowtheme.cpp#L43-L63"
auto darkValue = BOOL(night ? TRUE : FALSE);
const auto updateStyle = [&] {
static const auto kSystemVersion = QOperatingSystemVersion::current();
if (kSystemVersion.microVersion() < 18362) {
SetPropW(
ps_hWnd,
L"UseImmersiveDarkModeColors",
reinterpret_cast<HANDLE>(static_cast<INT_PTR>(darkValue)));
} else if (Dlls::SetWindowCompositionAttribute) {
Dlls::WINDOWCOMPOSITIONATTRIBDATA data = {
Dlls::WINDOWCOMPOSITIONATTRIB::WCA_USEDARKMODECOLORS,
&darkValue,
sizeof(darkValue)
};
Dlls::SetWindowCompositionAttribute(ps_hWnd, &data);
} else if (Dlls::DwmSetWindowAttribute) {
static constexpr auto DWMWA_USE_IMMERSIVE_DARK_MODE_0 = DWORD(19);
static constexpr auto DWMWA_USE_IMMERSIVE_DARK_MODE = DWORD(20);
const auto set = [&](DWORD attribute) {
return Dlls::DwmSetWindowAttribute(
ps_hWnd,
attribute,
&darkValue,
sizeof(darkValue));
};
if (FAILED(set(DWMWA_USE_IMMERSIVE_DARK_MODE))) {
set(DWMWA_USE_IMMERSIVE_DARK_MODE_0);
}
}
};
updateStyle();
// See "https://osdn.net/projects/tortoisesvn/scm/svn/blobs/28812/"
// "trunk/src/TortoiseIDiff/MainWindow.cpp"
//
// But for now it works event with a small part of that.
//
//const auto updateWindowTheme = [&] {
// const auto set = [&](LPCWSTR name) {
// return Dlls::SetWindowTheme(ps_hWnd, name, nullptr);
// };
// if (!night || FAILED(set(L"DarkMode_Explorer"))) {
// set(L"Explorer");
// }
//};
//
//if (night) {
// if (Dlls::SetPreferredAppMode) {
// Dlls::SetPreferredAppMode(Dlls::PreferredAppMode::AllowDark);
// } else {
// Dlls::AllowDarkModeForApp(TRUE);
// }
// Dlls::AllowDarkModeForWindow(ps_hWnd, TRUE);
// updateWindowTheme();
// updateStyle();
// Dlls::FlushMenuThemes();
// Dlls::RefreshImmersiveColorPolicyState();
//} else {
// updateWindowTheme();
// Dlls::AllowDarkModeForWindow(ps_hWnd, FALSE);
// updateStyle();
// Dlls::FlushMenuThemes();
// Dlls::RefreshImmersiveColorPolicyState();
// if (Dlls::SetPreferredAppMode) {
// Dlls::SetPreferredAppMode(Dlls::PreferredAppMode::Default);
// } else {
// Dlls::AllowDarkModeForApp(FALSE);
// }
//}
// Didn't find any other way to definitely repaint with the new style.
SendMessage(ps_hWnd, WM_NCACTIVATE, _hasActiveFrame ? 0 : 1, 0);
SendMessage(ps_hWnd, WM_NCACTIVATE, _hasActiveFrame ? 1 : 0, 0);
}
void MainWindow::fixMaximizedWindow() {

View file

@ -90,9 +90,10 @@ protected:
QTimer psUpdatedPositionTimer;
private:
void setupNativeWindowFrame();
void updateIconCounters();
QMargins computeCustomMargins();
void validateWindowTheme();
void validateWindowTheme(bool native, bool night);
void psDestroyIcons();
void fixMaximizedWindow();
@ -102,6 +103,8 @@ private:
bool _themeInited = false;
bool _inUpdateMargins = false;
bool _wasNativeFrame = false;
bool _hasActiveFrame = false;
HWND ps_hWnd = nullptr;
HWND ps_tbHider_hWnd = nullptr;

View file

@ -41,6 +41,7 @@ void init() {
u"dwmapi.dll"_q,
u"rstrtmgr.dll"_q,
u"psapi.dll"_q,
u"user32.dll"_q,
};
for (const auto &lib : list) {
SafeLoadLibrary(lib);
@ -48,6 +49,11 @@ void init() {
}
f_SetWindowTheme SetWindowTheme;
//f_RefreshImmersiveColorPolicyState RefreshImmersiveColorPolicyState;
//f_AllowDarkModeForApp AllowDarkModeForApp;
//f_SetPreferredAppMode SetPreferredAppMode;
//f_AllowDarkModeForWindow AllowDarkModeForWindow;
//f_FlushMenuThemes FlushMenuThemes;
f_OpenAs_RunDLL OpenAs_RunDLL;
f_SHOpenWithDialog SHOpenWithDialog;
f_SHAssocEnumHandlers SHAssocEnumHandlers;
@ -63,12 +69,14 @@ f_WindowsDeleteString WindowsDeleteString;
f_PropVariantToString PropVariantToString;
f_PSStringFromPropertyKey PSStringFromPropertyKey;
f_DwmIsCompositionEnabled DwmIsCompositionEnabled;
f_DwmSetWindowAttribute DwmSetWindowAttribute;
f_RmStartSession RmStartSession;
f_RmRegisterResources RmRegisterResources;
f_RmGetList RmGetList;
f_RmShutdown RmShutdown;
f_RmEndSession RmEndSession;
f_GetProcessMemoryInfo GetProcessMemoryInfo;
f_SetWindowCompositionAttribute SetWindowCompositionAttribute;
void start() {
init();
@ -84,6 +92,21 @@ void start() {
const auto LibUxTheme = SafeLoadLibrary(u"uxtheme.dll"_q);
LoadMethod(LibUxTheme, "SetWindowTheme", SetWindowTheme);
//if (IsWindows10OrGreater()) {
// static const auto kSystemVersion = QOperatingSystemVersion::current();
// static const auto kMinor = kSystemVersion.minorVersion();
// static const auto kBuild = kSystemVersion.microVersion();
// if (kMinor > 0 || (kMinor == 0 && kBuild >= 17763)) {
// if (kBuild < 18362) {
// LoadMethod(LibUxTheme, "AllowDarkModeForApp", AllowDarkModeForApp, 135);
// } else {
// LoadMethod(LibUxTheme, "SetPreferredAppMode", SetPreferredAppMode, 135);
// }
// LoadMethod(LibUxTheme, "AllowDarkModeForWindow", AllowDarkModeForWindow, 133);
// LoadMethod(LibUxTheme, "RefreshImmersiveColorPolicyState", RefreshImmersiveColorPolicyState, 104);
// LoadMethod(LibUxTheme, "FlushMenuThemes", FlushMenuThemes, 136);
// }
//}
if (IsWindowsVistaOrGreater()) {
const auto LibWtsApi32 = SafeLoadLibrary(u"wtsapi32.dll"_q);
@ -103,6 +126,7 @@ void start() {
const auto LibDwmApi = SafeLoadLibrary(u"dwmapi.dll"_q);
LoadMethod(LibDwmApi, "DwmIsCompositionEnabled", DwmIsCompositionEnabled);
LoadMethod(LibDwmApi, "DwmSetWindowAttribute", DwmSetWindowAttribute);
const auto LibRstrtMgr = SafeLoadLibrary(u"rstrtmgr.dll"_q);
LoadMethod(LibRstrtMgr, "RmStartSession", RmStartSession);
@ -114,6 +138,9 @@ void start() {
const auto LibPsApi = SafeLoadLibrary(u"psapi.dll"_q);
LoadMethod(LibPsApi, "GetProcessMemoryInfo", GetProcessMemoryInfo);
const auto LibUser32 = SafeLoadLibrary(u"user32.dll"_q);
LoadMethod(LibUser32, "SetWindowCompositionAttribute", SetWindowCompositionAttribute);
}
} // namespace Dlls

View file

@ -37,6 +37,29 @@ using f_SetWindowTheme = HRESULT(FAR STDAPICALLTYPE*)(
LPCWSTR pszSubIdList);
extern f_SetWindowTheme SetWindowTheme;
//using f_RefreshImmersiveColorPolicyState = void(FAR STDAPICALLTYPE*)();
//extern f_RefreshImmersiveColorPolicyState RefreshImmersiveColorPolicyState;
//
//using f_AllowDarkModeForApp = BOOL(FAR STDAPICALLTYPE*)(BOOL allow);
//extern f_AllowDarkModeForApp AllowDarkModeForApp;
//
//enum class PreferredAppMode {
// Default,
// AllowDark,
// ForceDark,
// ForceLight,
// Max
//};
//
//using f_SetPreferredAppMode = PreferredAppMode(FAR STDAPICALLTYPE*)(PreferredAppMode appMode);
//extern f_SetPreferredAppMode SetPreferredAppMode;
//
//using f_AllowDarkModeForWindow = BOOL(FAR STDAPICALLTYPE*)(HWND hwnd, BOOL allow);
//extern f_AllowDarkModeForWindow AllowDarkModeForWindow;
//
//using f_FlushMenuThemes = void(FAR STDAPICALLTYPE*)();
//extern f_FlushMenuThemes FlushMenuThemes;
// SHELL32.DLL
using f_SHAssocEnumHandlers = HRESULT(FAR STDAPICALLTYPE*)(
PCWSTR pszExtra,
@ -128,6 +151,13 @@ using f_DwmIsCompositionEnabled = HRESULT(FAR STDAPICALLTYPE*)(
_Out_ BOOL* pfEnabled);
extern f_DwmIsCompositionEnabled DwmIsCompositionEnabled;
using f_DwmSetWindowAttribute = HRESULT(FAR STDAPICALLTYPE*)(
HWND hwnd,
DWORD dwAttribute,
_In_reads_bytes_(cbAttribute) LPCVOID pvAttribute,
DWORD cbAttribute);
extern f_DwmSetWindowAttribute DwmSetWindowAttribute;
// RSTRTMGR.DLL
using f_RmStartSession = DWORD(FAR STDAPICALLTYPE*)(
@ -172,5 +202,47 @@ using f_GetProcessMemoryInfo = BOOL(FAR STDAPICALLTYPE*)(
DWORD cb);
extern f_GetProcessMemoryInfo GetProcessMemoryInfo;
// USER32.DLL
enum class 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 f_SetWindowCompositionAttribute = BOOL(WINAPI *)(HWND hWnd, WINDOWCOMPOSITIONATTRIBDATA*);
extern f_SetWindowCompositionAttribute SetWindowCompositionAttribute;
} // namespace Dlls
} // namespace Platform

@ -1 +1 @@
Subproject commit 01ca681ab3aecda8c372b1bb77999f3b7b7a52c6
Subproject commit 6a78e454e5bd61133b3d6c9f8d64fbad00f17618