Skip to content

Commit

Permalink
refactor: 检测主题更改的逻辑集中在 App 中
Browse files Browse the repository at this point in the history
  • Loading branch information
Blinue committed Dec 16, 2024
1 parent a4fb90f commit 380bed2
Show file tree
Hide file tree
Showing 10 changed files with 129 additions and 137 deletions.
61 changes: 56 additions & 5 deletions src/Magpie/App.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
#include "Win32Helper.h"
#include "Logger.h"
#include "ShortcutService.h"
#include "AppSettings.h"
#include "CommonSharedConstants.h"
#include "ScalingService.h"
#include <CoreWindow.h>
Expand All @@ -39,8 +38,10 @@
#include "IsNullStateTrigger.h"
#include "TextBlockHelper.h"

using namespace Magpie;
using namespace Magpie::Core;
using namespace ::Magpie;
using namespace ::Magpie::Core;
using namespace winrt;
using namespace Windows::UI::ViewManagement;

namespace winrt::Magpie::implementation {

Expand Down Expand Up @@ -122,13 +123,15 @@ bool App::Initialize(const wchar_t* arguments) {
// 初始化 XAML 框架。退出时也不要关闭,如果正在播放动画会崩溃。文档中的清空消息队列的做法无用。
_windowsXamlManager = Hosting::WindowsXamlManager::InitializeForCurrentThread();

if (!Win32Helper::GetOSVersion().IsWin11()) {
if (CoreWindow coreWindow = CoreWindow::GetForCurrentThread()) {
// Win10 中隐藏 DesktopWindowXamlSource 窗口
if (CoreWindow coreWindow = CoreWindow::GetForCurrentThread()) {
if (!Win32Helper::GetOSVersion().IsWin11()) {
HWND hwndDWXS;
coreWindow.as<ICoreWindowInterop>()->get_WindowHandle(&hwndDWXS);
ShowWindow(hwndDWXS, SW_HIDE);
}

_dispatcher = coreWindow.Dispatcher();
}

LocalizationService::Get().EarlyInitialize();
Expand All @@ -153,6 +156,10 @@ bool App::Initialize(const wchar_t* arguments) {
IsNullStateTrigger::RegisterDependencyProperties();
TextBlockHelper::RegisterDependencyProperties();

_themeChangedRevoker = AppSettings::Get().ThemeChanged(
auto_revoke, std::bind_front(&App::_AppSettings_ThemeChanged, this));
_AppSettings_ThemeChanged(AppSettings::Get().Theme());

LocalizationService::Get().Initialize();
ToastService::Get().Initialize();
ShortcutService::Get().Initialize();
Expand Down Expand Up @@ -287,6 +294,50 @@ bool App::_CheckSingleInstance() noexcept {
return true;
}

void App::_AppSettings_ThemeChanged(AppTheme theme) {
_UpdateColorValuesChangedRevoker();
_UpdateTheme();
}

void App::_UpdateColorValuesChangedRevoker() {
if (AppSettings::Get().Theme() == AppTheme::System) {
_colorValuesChangedRevoker = _uiSettings.ColorValuesChanged(
auto_revoke,
[this](const auto&, const auto&) {
_dispatcher.RunAsync(CoreDispatcherPriority::Normal, [this] {
_UpdateTheme();
});
}
);
} else {
_colorValuesChangedRevoker.revoke();
}
}

// 来自 https://learn.microsoft.com/en-us/windows/apps/desktop/modernize/apply-windows-themes#know-when-dark-mode-is-enabled
static bool IsColorLight(const winrt::Windows::UI::Color& clr) noexcept {
return 5 * clr.G + 2 * clr.R + clr.B > 8 * 128;
}

void App::_UpdateTheme() {
AppTheme theme = AppSettings::Get().Theme();

bool isLightTheme = false;
if (theme == AppTheme::System) {
// 前景色是亮色表示当前是深色主题
isLightTheme = !IsColorLight(_uiSettings.GetColorValue(UIColorType::Foreground));
} else {
isLightTheme = theme == AppTheme::Light;
}

if (_isLightTheme == isLightTheme) {
return;
}

_isLightTheme = isLightTheme;
ThemeChanged.Invoke(isLightTheme);
}

void App::_QuitWithoutMainWindow() {
NotifyIconService::Get().Uninitialize();
ScalingService::Get().Uninitialize();
Expand Down
23 changes: 23 additions & 0 deletions src/Magpie/App.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
#include "App.g.h"
#include <winrt/Windows.UI.Xaml.Hosting.h>
#include "MainWindow.h"
#include "AppSettings.h"
#include "Event.h"

namespace winrt::Magpie::implementation {

Expand All @@ -17,6 +19,10 @@ class App : public App_base<App, Markup::IXamlMetadataProvider> {

int Run();

const CoreDispatcher& Dispatcher() const noexcept {
return _dispatcher;
}

void ShowMainWindow() noexcept;

void Quit();
Expand All @@ -35,9 +41,19 @@ class App : public App_base<App, Markup::IXamlMetadataProvider> {
return _mainWindow;
}

bool IsLightTheme() const noexcept { return _isLightTheme; }

::Magpie::Core::MultithreadEvent<bool> ThemeChanged;

private:
bool _CheckSingleInstance() noexcept;

void _AppSettings_ThemeChanged(::Magpie::AppTheme theme);

void _UpdateColorValuesChangedRevoker();

void _UpdateTheme();

void _QuitWithoutMainWindow();

void _MainWindow_Destoryed();
Expand All @@ -52,6 +68,13 @@ class App : public App_base<App, Markup::IXamlMetadataProvider> {

::Magpie::MainWindow _mainWindow;

CoreDispatcher _dispatcher{ nullptr };

::Magpie::Core::EventRevoker _themeChangedRevoker;
Windows::UI::ViewManagement::UISettings _uiSettings;
Windows::UI::ViewManagement::UISettings::ColorValuesChanged_revoker _colorValuesChangedRevoker;
bool _isLightTheme = true;

////////////////////////////////////////////////////
//
// IXamlMetadataProvider 相关
Expand Down
2 changes: 1 addition & 1 deletion src/Magpie/AppSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
#include "resource.h"
#include "App.h"

using namespace Magpie::Core;
using namespace ::Magpie::Core;
using namespace winrt;
using namespace winrt::Magpie;

Expand Down
11 changes: 7 additions & 4 deletions src/Magpie/MainWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
#include "resource.h"
#include "EffectsService.h"
#include "AppSettings.h"
#include "App.h"

using namespace Magpie::Core;
using namespace winrt::Magpie::implementation;

namespace Magpie {

Expand Down Expand Up @@ -43,9 +45,7 @@ bool MainWindow::Create() noexcept {

_Content(winrt::Magpie::RootPage());

Content().ActualThemeChanged([this](winrt::FrameworkElement const&, winrt::IInspectable const&) {
_UpdateTheme();
});
_appThemeChangedRevoker = App::Get().ThemeChanged(winrt::auto_revoke, [this](bool) { _UpdateTheme(); });
_UpdateTheme();

const bool isMaximized = AppSettings::Get().IsMainWindowMaximized();
Expand Down Expand Up @@ -212,12 +212,15 @@ LRESULT MainWindow::_MessageHandler(UINT msg, WPARAM wParam, LPARAM lParam) noex
}
case WM_ACTIVATE:
{
Content().TitleBar().IsWindowActive(LOWORD(wParam) != WA_INACTIVE);
if (Content()) {
Content().TitleBar().IsWindowActive(LOWORD(wParam) != WA_INACTIVE);
}
break;
}
case WM_DESTROY:
{
AppSettings::Get().Save();
_appThemeChangedRevoker.Revoke();
_hwndTitleBar = NULL;
_trackingMouse = false;
break;
Expand Down
2 changes: 2 additions & 0 deletions src/Magpie/MainWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ class MainWindow : public XamlWindowT<MainWindow, winrt::Magpie::RootPage> {

void _ResizeTitleBarWindow() noexcept;

Core::EventRevoker _appThemeChangedRevoker;

HWND _hwndTitleBar = NULL;
HWND _hwndMaximizeButton = NULL;
bool _trackingMouse = false;
Expand Down
85 changes: 26 additions & 59 deletions src/Magpie/RootPage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@
#include "ThemeHelper.h"
#include "ContentDialogHelper.h"
#include "LocalizationService.h"
#include "App.h"

using namespace Magpie;
using namespace Magpie::Core;
using namespace ::Magpie;
using namespace ::Magpie::Core;
using namespace winrt;
using namespace Windows::Graphics::Display;
using namespace Windows::Graphics::Imaging;
Expand All @@ -32,24 +33,6 @@ namespace winrt::Magpie::implementation {
static constexpr uint32_t FIRST_PROFILE_ITEM_IDX = 4;

RootPage::RootPage() {
_themeChangedRevoker = AppSettings::Get().ThemeChanged(
auto_revoke, std::bind_front(&RootPage::_AppSettings_ThemeChanged, this));
_UpdateColorValuesChangedRevoker();

_displayInformation = DisplayInformation::GetForCurrentView();
_dpiChangedRevoker = _displayInformation.DpiChanged(
auto_revoke, [this](DisplayInformation const&, IInspectable const&) { _UpdateIcons(false); });

ProfileService& profileService = ProfileService::Get();
_profileAddedRevoker = profileService.ProfileAdded(
auto_revoke, std::bind_front(&RootPage::_ProfileService_ProfileAdded, this));
_profileRenamedRevoker = profileService.ProfileRenamed(
auto_revoke, std::bind_front(&RootPage::_ProfileService_ProfileRenamed, this));
_profileRemovedRevoker = profileService.ProfileRemoved(
auto_revoke, std::bind_front(&RootPage::_ProfileService_ProfileRemoved, this));
_profileMovedRevoker = profileService.ProfileMoved(
auto_revoke, std::bind_front(&RootPage::_ProfileService_ProfileReordered, this));

// 设置 Language 属性帮助 XAML 选择合适的字体,比如繁体中文使用 Microsoft JhengHei UI,日语使用 Yu Gothic UI
Language(LocalizationService::Get().Language());
}
Expand All @@ -68,8 +51,23 @@ RootPage::~RootPage() {
void RootPage::InitializeComponent() {
RootPageT::InitializeComponent();

_appThemeChangedRevoker = App::Get().ThemeChanged(auto_revoke, [this](bool) { _UpdateTheme(true); });
_UpdateTheme(false);

_displayInformation = DisplayInformation::GetForCurrentView();
_dpiChangedRevoker = _displayInformation.DpiChanged(
auto_revoke, [this](DisplayInformation const&, IInspectable const&) { _UpdateIcons(false); });

ProfileService& profileService = ProfileService::Get();
_profileAddedRevoker = profileService.ProfileAdded(
auto_revoke, std::bind_front(&RootPage::_ProfileService_ProfileAdded, this));
_profileRenamedRevoker = profileService.ProfileRenamed(
auto_revoke, std::bind_front(&RootPage::_ProfileService_ProfileRenamed, this));
_profileRemovedRevoker = profileService.ProfileRemoved(
auto_revoke, std::bind_front(&RootPage::_ProfileService_ProfileRemoved, this));
_profileMovedRevoker = profileService.ProfileMoved(
auto_revoke, std::bind_front(&RootPage::_ProfileService_ProfileReordered, this));

const Win32Helper::OSVersion& osVersion = Win32Helper::GetOSVersion();
if (osVersion.Is22H2OrNewer()) {
// Win11 22H2+ 使用系统的 Mica 背景
Expand Down Expand Up @@ -181,11 +179,10 @@ void RootPage::NavigationView_DisplayModeChanged(MUXC::NavigationView const& nv,
fire_and_forget RootPage::NavigationView_ItemInvoked(MUXC::NavigationView const&, MUXC::NavigationViewItemInvokedEventArgs const& args) {
if (args.InvokedItemContainer() == NewProfileNavigationViewItem()) {
const UINT dpi = (UINT)std::lroundf(_displayInformation.LogicalDpi());
const bool isLightTheme = ActualTheme() == ElementTheme::Light;
_newProfileViewModel.PrepareForOpen(dpi, isLightTheme, Dispatcher());
_newProfileViewModel.PrepareForOpen(dpi, App::Get().IsLightTheme(), App::Get().Dispatcher());

// 同步调用 ShowAt 有时会失败
co_await Dispatcher();
co_await App::Get().Dispatcher();

NewProfileFlyout().ShowAt(NewProfileNavigationViewItem());
}
Expand Down Expand Up @@ -216,28 +213,20 @@ static Color Win32ColorToWinRTColor(COLORREF color) {
}

void RootPage::_UpdateTheme(bool updateIcons) {
AppTheme theme = AppSettings::Get().Theme();

bool isDarkTheme = FALSE;
if (theme == AppTheme::System) {
// 前景色是亮色表示当前是深色主题
isDarkTheme = XamlHelper::IsColorLight(_uiSettings.GetColorValue(UIColorType::Foreground));
} else {
isDarkTheme = theme == AppTheme::Dark;
}
const bool isLightTheme = App::Get().IsLightTheme();

if (IsLoaded() && (ActualTheme() == ElementTheme::Dark) == isDarkTheme) {
if (IsLoaded() && (ActualTheme() == ElementTheme::Light) == isLightTheme) {
// 无需切换
return;
}

if (!Win32Helper::GetOSVersion().Is22H2OrNewer()) {
const Windows::UI::Color bkgColor = Win32ColorToWinRTColor(
isDarkTheme ? ThemeHelper::DARK_TINT_COLOR : ThemeHelper::LIGHT_TINT_COLOR);
isLightTheme ? ThemeHelper::LIGHT_TINT_COLOR : ThemeHelper::DARK_TINT_COLOR);
Background(SolidColorBrush(bkgColor));
}

ElementTheme newTheme = isDarkTheme ? ElementTheme::Dark : ElementTheme::Light;
ElementTheme newTheme = isLightTheme ? ElementTheme::Light : ElementTheme::Dark;
RequestedTheme(newTheme);

XamlHelper::UpdateThemeOfXamlPopups(XamlRoot(), newTheme);
Expand All @@ -251,10 +240,10 @@ void RootPage::_UpdateTheme(bool updateIcons) {
fire_and_forget RootPage::_LoadIcon(MUXC::NavigationViewItem const& item, const Profile& profile) {
weak_ref<MUXC::NavigationViewItem> weakRef(item);

bool preferLightTheme = ActualTheme() == ElementTheme::Light;
bool preferLightTheme = App::Get().IsLightTheme();
bool isPackaged = profile.isPackaged;
std::wstring path = profile.pathRule;
CoreDispatcher dispatcher = Dispatcher();
CoreDispatcher dispatcher = App::Get().Dispatcher();
const uint32_t iconSize = (uint32_t)std::lroundf(16 * _displayInformation.LogicalDpi() / USER_DEFAULT_SCREEN_DPI);

co_await resume_background();
Expand Down Expand Up @@ -309,28 +298,6 @@ fire_and_forget RootPage::_LoadIcon(MUXC::NavigationViewItem const& item, const
}
}

void RootPage::_UpdateColorValuesChangedRevoker() {
if (AppSettings::Get().Theme() == AppTheme::System) {
_colorValuesChangedRevoker = _uiSettings.ColorValuesChanged(
auto_revoke, { this, &RootPage::_UISettings_ColorValuesChanged });
} else {
_colorValuesChangedRevoker.revoke();
}
}

void RootPage::_UISettings_ColorValuesChanged(Windows::UI::ViewManagement::UISettings const&, IInspectable const&) {
Dispatcher().RunAsync(CoreDispatcherPriority::Normal, [weakThis(get_weak())]() {
if (auto strongThis = weakThis.get()) {
strongThis->_UpdateTheme(true);
}
});
}

void RootPage::_AppSettings_ThemeChanged(AppTheme) {
_UpdateColorValuesChangedRevoker();
_UpdateTheme(true);
}

void RootPage::_UpdateIcons(bool skipDesktop) {
IVector<IInspectable> navMenuItems = RootNavigationView().MenuItems();
const std::vector<Profile>& profiles = AppSettings::Get().Profiles();
Expand Down
11 changes: 1 addition & 10 deletions src/Magpie/RootPage.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,6 @@ struct RootPage : RootPageT<RootPage> {

fire_and_forget _LoadIcon(MUXC::NavigationViewItem const& item, const ::Magpie::Profile& profile);

void _UpdateColorValuesChangedRevoker();

void _UISettings_ColorValuesChanged(Windows::UI::ViewManagement::UISettings const&, IInspectable const&);

void _AppSettings_ThemeChanged(::Magpie::AppTheme);

void _UpdateIcons(bool skipDesktop);

void _ProfileService_ProfileAdded(::Magpie::Profile& profile);
Expand All @@ -60,10 +54,7 @@ struct RootPage : RootPageT<RootPage> {

void _ProfileService_ProfileReordered(uint32_t profileIdx, bool isMoveUp);

::Magpie::Core::EventRevoker _themeChangedRevoker;

Windows::UI::ViewManagement::UISettings _uiSettings;
Windows::UI::ViewManagement::UISettings::ColorValuesChanged_revoker _colorValuesChangedRevoker;
::Magpie::Core::EventRevoker _appThemeChangedRevoker;

Magpie::NewProfileViewModel _newProfileViewModel;
::Magpie::Core::EventRevoker _profileAddedRevoker;
Expand Down
Loading

0 comments on commit 380bed2

Please sign in to comment.