diff --git a/Telegram/SourceFiles/platform/win/main_window_win.cpp b/Telegram/SourceFiles/platform/win/main_window_win.cpp index 0f2d114d1..8c05a1df2 100644 --- a/Telegram/SourceFiles/platform/win/main_window_win.cpp +++ b/Telegram/SourceFiles/platform/win/main_window_win.cpp @@ -112,11 +112,44 @@ MainWindow::MainWindow(not_null 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(static_cast(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() { diff --git a/Telegram/SourceFiles/platform/win/main_window_win.h b/Telegram/SourceFiles/platform/win/main_window_win.h index d534f81e7..b02225111 100644 --- a/Telegram/SourceFiles/platform/win/main_window_win.h +++ b/Telegram/SourceFiles/platform/win/main_window_win.h @@ -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; diff --git a/Telegram/SourceFiles/platform/win/windows_dlls.cpp b/Telegram/SourceFiles/platform/win/windows_dlls.cpp index 2a7278c86..ce24a84a2 100644 --- a/Telegram/SourceFiles/platform/win/windows_dlls.cpp +++ b/Telegram/SourceFiles/platform/win/windows_dlls.cpp @@ -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 diff --git a/Telegram/SourceFiles/platform/win/windows_dlls.h b/Telegram/SourceFiles/platform/win/windows_dlls.h index c76865e78..b297e9d84 100644 --- a/Telegram/SourceFiles/platform/win/windows_dlls.h +++ b/Telegram/SourceFiles/platform/win/windows_dlls.h @@ -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 diff --git a/Telegram/lib_base b/Telegram/lib_base index 01ca681ab..6a78e454e 160000 --- a/Telegram/lib_base +++ b/Telegram/lib_base @@ -1 +1 @@ -Subproject commit 01ca681ab3aecda8c372b1bb77999f3b7b7a52c6 +Subproject commit 6a78e454e5bd61133b3d6c9f8d64fbad00f17618