diff --git a/src/modules/alwaysontop/AlwaysOnTop/AlwaysOnTop.cpp b/src/modules/alwaysontop/AlwaysOnTop/AlwaysOnTop.cpp index a5490d2072..14f25d4a24 100644 --- a/src/modules/alwaysontop/AlwaysOnTop/AlwaysOnTop.cpp +++ b/src/modules/alwaysontop/AlwaysOnTop/AlwaysOnTop.cpp @@ -71,7 +71,8 @@ bool isExcluded(HWND window) auto processPath = get_process_path(window); CharUpperBuffW(processPath.data(), static_cast(processPath.length())); - return check_excluded_app(window, processPath, AlwaysOnTopSettings::settings().excludedApps); + const auto settings = AlwaysOnTopSettings::settings(); + return check_excluded_app(window, processPath, settings->excludedApps); } AlwaysOnTop::AlwaysOnTop(bool useLLKH, DWORD mainThreadId) : @@ -155,7 +156,8 @@ void AlwaysOnTop::SettingsUpdate(SettingId id) break; case SettingId::FrameEnabled: { - if (AlwaysOnTopSettings::settings().enableFrame) + const auto settings = AlwaysOnTopSettings::settings(); + if (settings->enableFrame) { for (auto& iter : m_topmostWindows) { @@ -194,7 +196,8 @@ void AlwaysOnTop::SettingsUpdate(SettingId id) break; case SettingId::ShowInSystemMenu: { - UpdateSystemMenuEventHooks(AlwaysOnTopSettings::settings().showInSystemMenu); + const auto settings = AlwaysOnTopSettings::settings(); + UpdateSystemMenuEventHooks(settings->showInSystemMenu); m_lastSystemMenuWindow = nullptr; UpdateSystemMenuItem(GetForegroundWindow()); } @@ -236,7 +239,7 @@ LRESULT AlwaysOnTop::WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lp void AlwaysOnTop::ProcessCommand(HWND window) { bool gameMode = detect_game_mode(); - if (AlwaysOnTopSettings::settings().blockInGameMode && gameMode) + if (AlwaysOnTopSettings::settings()->blockInGameMode && gameMode) { return; } @@ -276,7 +279,7 @@ void AlwaysOnTop::ProcessCommand(HWND window) } } - if (AlwaysOnTopSettings::settings().enableSound) + if (AlwaysOnTopSettings::settings()->enableSound) { m_sound.Play(soundType); } @@ -323,7 +326,7 @@ void AlwaysOnTop::StartTrackingTopmostWindows() bool AlwaysOnTop::AssignBorder(HWND window) { - if (m_virtualDesktopUtils.IsWindowOnCurrentDesktop(window) && AlwaysOnTopSettings::settings().enableFrame) + if (m_virtualDesktopUtils.IsWindowOnCurrentDesktop(window) && AlwaysOnTopSettings::settings()->enableFrame) { auto border = WindowBorder::Create(window, m_hinstance); if (border) @@ -352,11 +355,13 @@ void AlwaysOnTop::RegisterHotkey() const UnregisterHotKey(m_window, static_cast(HotkeyId::IncreaseOpacity)); UnregisterHotKey(m_window, static_cast(HotkeyId::DecreaseOpacity)); + const auto settings = AlwaysOnTopSettings::settings(); + // Register pin hotkey - RegisterHotKey(m_window, static_cast(HotkeyId::Pin), AlwaysOnTopSettings::settings().hotkey.get_modifiers(), AlwaysOnTopSettings::settings().hotkey.get_code()); + RegisterHotKey(m_window, static_cast(HotkeyId::Pin), settings->hotkey.get_modifiers(), settings->hotkey.get_code()); // Register transparency hotkeys using the same modifiers as the pin hotkey - UINT modifiers = AlwaysOnTopSettings::settings().hotkey.get_modifiers(); + UINT modifiers = settings->hotkey.get_modifiers(); RegisterHotKey(m_window, static_cast(HotkeyId::IncreaseOpacity), modifiers, VK_OEM_PLUS); RegisterHotKey(m_window, static_cast(HotkeyId::DecreaseOpacity), modifiers, VK_OEM_MINUS); } @@ -472,7 +477,7 @@ void AlwaysOnTop::SubscribeToEvents() } } - UpdateSystemMenuEventHooks(AlwaysOnTopSettings::settings().showInSystemMenu); + UpdateSystemMenuEventHooks(AlwaysOnTopSettings::settings()->showInSystemMenu); } void AlwaysOnTop::UpdateSystemMenuEventHooks(bool enable) @@ -525,7 +530,8 @@ void AlwaysOnTop::UpdateSystemMenuItem(HWND window) const noexcept return; } - if (!AlwaysOnTopSettings::settings().showInSystemMenu) + const auto settings = AlwaysOnTopSettings::settings(); + if (!settings->showInSystemMenu) { if (IsAlwaysOnTopMenuCommand(systemMenu)) { @@ -644,7 +650,7 @@ void AlwaysOnTop::HandleWinHookEvent(WinHookEvent* data) noexcept { if (data->idObject == OBJID_SYSMENU && data->hwnd) { - m_lastSystemMenuWindow = AlwaysOnTopSettings::settings().showInSystemMenu ? data->hwnd : nullptr; + m_lastSystemMenuWindow = AlwaysOnTopSettings::settings()->showInSystemMenu ? data->hwnd : nullptr; UpdateSystemMenuItem(data->hwnd); } } @@ -659,7 +665,7 @@ void AlwaysOnTop::HandleWinHookEvent(WinHookEvent* data) noexcept return; case EVENT_OBJECT_INVOKED: { - if (!AlwaysOnTopSettings::settings().showInSystemMenu) + if (!AlwaysOnTopSettings::settings()->showInSystemMenu) { return; } @@ -710,7 +716,7 @@ void AlwaysOnTop::HandleWinHookEvent(WinHookEvent* data) noexcept break; } - if (!AlwaysOnTopSettings::settings().enableFrame || !data->hwnd) + if (!AlwaysOnTopSettings::settings()->enableFrame || !data->hwnd) { return; } @@ -879,7 +885,7 @@ void AlwaysOnTop::StepWindowTransparency(HWND window, int delta) { ApplyWindowAlpha(targetWindow, newTransparency); - if (AlwaysOnTopSettings::settings().enableSound) + if (AlwaysOnTopSettings::settings()->enableSound) { m_sound.Play(delta > 0 ? Sound::Type::IncreaseOpacity : Sound::Type::DecreaseOpacity); } diff --git a/src/modules/alwaysontop/AlwaysOnTop/Settings.cpp b/src/modules/alwaysontop/AlwaysOnTop/Settings.cpp index 0991b1924f..5ce2e82f8a 100644 --- a/src/modules/alwaysontop/AlwaysOnTop/Settings.cpp +++ b/src/modules/alwaysontop/AlwaysOnTop/Settings.cpp @@ -44,12 +44,14 @@ inline COLORREF HexToRGB(std::wstring_view hex, const COLORREF fallbackColor = R } } -AlwaysOnTopSettings::AlwaysOnTopSettings() +AlwaysOnTopSettings::AlwaysOnTopSettings() : + m_settings(std::make_shared()) { m_uiSettings.ColorValuesChanged([&](winrt::Windows::UI::ViewManagement::UISettings const& settings, winrt::Windows::Foundation::IInspectable const& args) { - if (m_settings.frameAccentColor) + const auto currentSettings = AlwaysOnTopSettings::settings(); + if (currentSettings->frameAccentColor) { NotifyObservers(SettingId::FrameAccentColor); } @@ -95,94 +97,97 @@ void AlwaysOnTopSettings::LoadSettings() try { PowerToysSettings::PowerToyValues values = PowerToysSettings::PowerToyValues::load_from_settings_file(NonLocalizable::ModuleKey); + const auto currentSettings = AlwaysOnTopSettings::settings(); + auto updatedSettings = std::make_shared(*currentSettings); + std::vector changedSettings; if (const auto jsonVal = values.get_json(NonLocalizable::HotkeyID)) { auto val = PowerToysSettings::HotkeyObject::from_json(*jsonVal); - if (m_settings.hotkey.get_modifiers() != val.get_modifiers() || m_settings.hotkey.get_key() != val.get_key() || m_settings.hotkey.get_code() != val.get_code()) + if (updatedSettings->hotkey.get_modifiers() != val.get_modifiers() || updatedSettings->hotkey.get_key() != val.get_key() || updatedSettings->hotkey.get_code() != val.get_code()) { - m_settings.hotkey = val; - NotifyObservers(SettingId::Hotkey); + updatedSettings->hotkey = val; + changedSettings.push_back(SettingId::Hotkey); } } if (const auto jsonVal = values.get_bool_value(NonLocalizable::SoundEnabledID)) { auto val = *jsonVal; - if (m_settings.enableSound != val) + if (updatedSettings->enableSound != val) { - m_settings.enableSound = val; - NotifyObservers(SettingId::SoundEnabled); + updatedSettings->enableSound = val; + changedSettings.push_back(SettingId::SoundEnabled); } } if (const auto jsonVal = values.get_bool_value(NonLocalizable::ShowInSystemMenuID)) { auto val = *jsonVal; - if (m_settings.showInSystemMenu != val) + if (updatedSettings->showInSystemMenu != val) { - m_settings.showInSystemMenu = val; - NotifyObservers(SettingId::ShowInSystemMenu); + updatedSettings->showInSystemMenu = val; + changedSettings.push_back(SettingId::ShowInSystemMenu); } } if (const auto jsonVal = values.get_int_value(NonLocalizable::FrameThicknessID)) { auto val = *jsonVal; - if (m_settings.frameThickness != val) + if (updatedSettings->frameThickness != val) { - m_settings.frameThickness = val; - NotifyObservers(SettingId::FrameThickness); + updatedSettings->frameThickness = val; + changedSettings.push_back(SettingId::FrameThickness); } } if (const auto jsonVal = values.get_string_value(NonLocalizable::FrameColorID)) { auto val = HexToRGB(*jsonVal); - if (m_settings.frameColor != val) + if (updatedSettings->frameColor != val) { - m_settings.frameColor = val; - NotifyObservers(SettingId::FrameColor); + updatedSettings->frameColor = val; + changedSettings.push_back(SettingId::FrameColor); } } if (const auto jsonVal = values.get_int_value(NonLocalizable::FrameOpacityID)) { auto val = *jsonVal; - if (m_settings.frameOpacity != val) + if (updatedSettings->frameOpacity != val) { - m_settings.frameOpacity = val; - NotifyObservers(SettingId::FrameOpacity); + updatedSettings->frameOpacity = val; + changedSettings.push_back(SettingId::FrameOpacity); } } if (const auto jsonVal = values.get_bool_value(NonLocalizable::FrameEnabledID)) { auto val = *jsonVal; - if (m_settings.enableFrame != val) + if (updatedSettings->enableFrame != val) { - m_settings.enableFrame = val; - NotifyObservers(SettingId::FrameEnabled); + updatedSettings->enableFrame = val; + changedSettings.push_back(SettingId::FrameEnabled); } } if (const auto jsonVal = values.get_bool_value(NonLocalizable::BlockInGameModeID)) { auto val = *jsonVal; - if (m_settings.blockInGameMode != val) + if (updatedSettings->blockInGameMode != val) { - m_settings.blockInGameMode = val; - NotifyObservers(SettingId::BlockInGameMode); + updatedSettings->blockInGameMode = val; + changedSettings.push_back(SettingId::BlockInGameMode); } } if (const auto jsonVal = values.get_bool_value(NonLocalizable::RoundCornersEnabledID)) { auto val = *jsonVal; - if (m_settings.roundCornersEnabled != val) + if (updatedSettings->roundCornersEnabled != val) { - m_settings.roundCornersEnabled = val; - NotifyObservers(SettingId::RoundCornersEnabled); + updatedSettings->roundCornersEnabled = val; + changedSettings.push_back(SettingId::RoundCornersEnabled); } } @@ -203,20 +208,29 @@ void AlwaysOnTopSettings::LoadSettings() view = left_trim(trim(view)); } - if (m_settings.excludedApps != excludedApps) + if (updatedSettings->excludedApps != excludedApps) { - m_settings.excludedApps = excludedApps; - NotifyObservers(SettingId::ExcludeApps); + updatedSettings->excludedApps = excludedApps; + changedSettings.push_back(SettingId::ExcludeApps); } } if (const auto jsonVal = values.get_bool_value(NonLocalizable::FrameAccentColor)) { auto val = *jsonVal; - if (m_settings.frameAccentColor != val) + if (updatedSettings->frameAccentColor != val) { - m_settings.frameAccentColor = val; - NotifyObservers(SettingId::FrameAccentColor); + updatedSettings->frameAccentColor = val; + changedSettings.push_back(SettingId::FrameAccentColor); + } + } + + if (!changedSettings.empty()) + { + m_settings.store(std::shared_ptr(updatedSettings), std::memory_order_release); + for (const auto changedSetting : changedSettings) + { + NotifyObservers(changedSetting); } } } diff --git a/src/modules/alwaysontop/AlwaysOnTop/Settings.h b/src/modules/alwaysontop/AlwaysOnTop/Settings.h index 76efd3d7b6..f72ce704fb 100644 --- a/src/modules/alwaysontop/AlwaysOnTop/Settings.h +++ b/src/modules/alwaysontop/AlwaysOnTop/Settings.h @@ -1,6 +1,9 @@ #pragma once +#include +#include #include +#include #include #include @@ -34,9 +37,9 @@ class AlwaysOnTopSettings { public: static AlwaysOnTopSettings& instance(); - static inline const Settings& settings() + static inline std::shared_ptr settings() { - return instance().m_settings; + return instance().m_settings.load(std::memory_order_acquire); } void InitFileWatcher(); @@ -52,7 +55,7 @@ private: ~AlwaysOnTopSettings() = default; winrt::Windows::UI::ViewManagement::UISettings m_uiSettings; - Settings m_settings; + std::atomic> m_settings; std::unique_ptr m_settingsFileWatcher; std::unordered_set m_observers; diff --git a/src/modules/alwaysontop/AlwaysOnTop/WindowBorder.cpp b/src/modules/alwaysontop/AlwaysOnTop/WindowBorder.cpp index 258beda57d..9c597944a7 100644 --- a/src/modules/alwaysontop/AlwaysOnTop/WindowBorder.cpp +++ b/src/modules/alwaysontop/AlwaysOnTop/WindowBorder.cpp @@ -23,7 +23,7 @@ std::optional GetFrameRect(HWND window) return std::nullopt; } - int border = AlwaysOnTopSettings::settings().frameThickness; + int border = AlwaysOnTopSettings::settings()->frameThickness; rect.top -= border; rect.left -= border; rect.right += border; @@ -194,8 +194,9 @@ void WindowBorder::UpdateBorderProperties() const RECT frameRect{ 0, 0, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top }; + const auto settings = AlwaysOnTopSettings::settings(); COLORREF color; - if (AlwaysOnTopSettings::settings().frameAccentColor) + if (settings->frameAccentColor) { winrt::Windows::UI::ViewManagement::UISettings settings; auto accentValue = settings.GetColorValue(winrt::Windows::UI::ViewManagement::UIColorType::Accent); @@ -203,14 +204,14 @@ void WindowBorder::UpdateBorderProperties() const } else { - color = AlwaysOnTopSettings::settings().frameColor; + color = settings->frameColor; } - float opacity = AlwaysOnTopSettings::settings().frameOpacity / 100.0f; + float opacity = settings->frameOpacity / 100.0f; float scalingFactor = ScalingUtils::ScalingFactor(m_trackingWindow); - float thickness = AlwaysOnTopSettings::settings().frameThickness * scalingFactor; + float thickness = settings->frameThickness * scalingFactor; float cornerRadius = 0.0; - if (AlwaysOnTopSettings::settings().roundCornersEnabled) + if (settings->roundCornersEnabled) { cornerRadius = WindowCornerUtils::CornersRadius(m_trackingWindow) * scalingFactor; } @@ -268,7 +269,7 @@ LRESULT WindowBorder::WndProc(UINT message, WPARAM wparam, LPARAM lparam) noexce void WindowBorder::SettingsUpdate(SettingId id) { - if (!AlwaysOnTopSettings::settings().enableFrame) + if (!AlwaysOnTopSettings::settings()->enableFrame) { return; }