From: lx-s Date: Wed, 8 Jul 2026 07:34:43 +0000 (+0200) Subject: Rewrote update check thread X-Git-Tag: 2.6.0.0~96 X-Git-Url: https://repos.lx-s.de/gitweb/?a=commitdiff_plain;h=49bda0ddf3d7464e02d536430c739265a4862365;p=winmute.git Rewrote update check thread --- diff --git a/WinMute/WinMute.cpp b/WinMute/WinMute.cpp index 8ebb4cf..37b75e2 100644 --- a/WinMute/WinMute.cpp +++ b/WinMute/WinMute.cpp @@ -402,44 +402,68 @@ void WinMute::LoadMainMenuText() void WinMute::CheckForUpdates() { - auto updateChecker = std::make_unique(); - if (!updateChecker || - !updateChecker->IsUpdateCheckEnabled(settings_)) { + const UpdateChecker updateChecker; + if (!updateChecker.IsUpdateCheckEnabled(settings_)) { return; } - std::thread updateThread(&WinMute::CheckForUpdatesAsync, this, std::move(updateChecker)); - updateThread.detach(); + if (updateThread_.joinable()) { // Check still running + return; + } + // The worker only uses its own locals and the raw window handle; the + // result is marshalled back to the UI thread via + // WM_WINMUTE_UPDATE_CHECK_DONE and handled in OnUpdateCheckDone. As a + // std::jthread member, the thread is joined before this object dies. + updateThread_ = std::jthread(&WinMute::CheckForUpdatesAsync, hWnd_); } -void WinMute::CheckForUpdatesAsync(std::unique_ptr updateChecker) +void WinMute::CheckForUpdatesAsync(HWND hWnd) { - const bool betaUpdates = settings_.QueryValue(SettingsKey::CHECK_FOR_BETA_UPDATE) != 0; - if (!updateChecker) { - return; + const UpdateChecker updateChecker; + auto updateInfo = std::make_unique(); + const bool success = updateChecker.GetUpdateInfo(*updateInfo); + if (PostMessageW(hWnd, WM_WINMUTE_UPDATE_CHECK_DONE, + static_cast(success), + reinterpret_cast(updateInfo.get()))) { + // Ownership has passed to OnUpdateCheckDone + updateInfo.release(); + } +} + +LRESULT WinMute::OnUpdateCheckDone(HWND, WPARAM wParam, LPARAM lParam) +{ + const std::unique_ptr updateInfo{ + reinterpret_cast(lParam) }; + if (updateThread_.joinable()) { + updateThread_.join(); } - if (!updateChecker->GetUpdateInfo(updateInfo_)) { + if (wParam == 0 || !updateInfo) { wmTray_.ShowPopup( i18n_.GetTranslationW("popup.error.update-check-failed.title"), i18n_.GetTranslationW("popup.error.update-check-failed.text")); - } else if (updateInfo_.beta.shouldUpdate && betaUpdates) { - const std::wstring popupTitle = std::vformat( + return 0; + } + updateInfo_ = *updateInfo; + const bool betaUpdates = settings_.QueryValue(SettingsKey::CHECK_FOR_BETA_UPDATE) != 0; + if (updateInfo_.beta.shouldUpdate && betaUpdates) { + const std::wstring popupTitle = SafeVFormat( i18n_.GetTranslationW("popup.update-available-beta.title"), - std::make_wformat_args(updateInfo_.beta.version)); - const std::wstring popupText = std::vformat( + updateInfo_.beta.version); + const std::wstring popupText = SafeVFormat( i18n_.GetTranslationW("popup.update-available-beta.text"), - std::make_wformat_args(updateInfo_.currentVersion)); + updateInfo_.currentVersion); updateTray_.Show(); updateTray_.ShowPopup(popupTitle, popupText); } else if (updateInfo_.stable.shouldUpdate) { - const std::wstring popupTitle = std::vformat( + const std::wstring popupTitle = SafeVFormat( i18n_.GetTranslationW("popup.update-available.title"), - std::make_wformat_args(updateInfo_.stable.version)); - const std::wstring popupText = std::vformat( + updateInfo_.stable.version); + const std::wstring popupText = SafeVFormat( i18n_.GetTranslationW("popup.update-available.text"), - std::make_wformat_args(updateInfo_.currentVersion)); + updateInfo_.currentVersion); updateTray_.Show(); updateTray_.ShowPopup(popupTitle, popupText); } + return 0; } LRESULT WinMute::OnCommand(HWND hWnd, WPARAM wParam, LPARAM) @@ -523,7 +547,7 @@ LRESULT WinMute::OnCommand(HWND hWnd, WPARAM wParam, LPARAM) } case ID_TRAYMENU_MUTEONLOGOUT: { bool checked = false; - ToggleMenuCheck(ID_TRAYMENU_MUTEONBLUETOOTH, &checked); + ToggleMenuCheck(ID_TRAYMENU_MUTEONLOGOUT, &checked); muteCtrl_.SetMuteOnLogout(checked); settings_.SetValue(SettingsKey::MUTE_ON_LOGOUT, checked); break; @@ -652,20 +676,20 @@ LRESULT WinMute::OnWifiStatusChange(HWND, WPARAM wParam, LPARAM lParam) if (settings_.QueryValue(SettingsKey::NOTIFICATIONS_ENABLED)) { std::wstring popupMsg; - wchar_t *wifiName = reinterpret_cast(lParam); + // Non-owning: the name is only valid for the duration of this call. + const wchar_t *wifiName = reinterpret_cast(lParam); if (settings_.QueryValue(SettingsKey::MUTE_ON_WLAN_ALLOWLIST)) { - popupMsg = std::vformat( + popupMsg = SafeVFormat( i18n_.GetTranslationW("popup.wlan-not-on-mute-list.text"), - std::make_wformat_args(wifiName)); + wifiName); } else { - popupMsg = std::vformat( + popupMsg = SafeVFormat( i18n_.GetTranslationW("popup.wlan-is-on-mute-list.text"), - std::make_wformat_args(wifiName)); + wifiName); } wmTray_.ShowPopup( i18n_.GetTranslationW("popup.workstation-muted.title"), popupMsg); - delete[] wifiName; } muteCtrl_.SetMute(true); @@ -722,6 +746,8 @@ LRESULT CALLBACK WinMute::WindowProc( return OnDeviceChange(hWnd, msg, wParam, lParam); case WM_WIFISTATUSCHANGED: return OnWifiStatusChange(hWnd, wParam, lParam); + case WM_WINMUTE_UPDATE_CHECK_DONE: + return OnUpdateCheckDone(hWnd, wParam, lParam); case WM_SETTINGCHANGE: return OnSettingChange(hWnd, wParam, lParam); default: diff --git a/WinMute/WinMute.h b/WinMute/WinMute.h index c1f9eb3..10a67f2 100644 --- a/WinMute/WinMute.h +++ b/WinMute/WinMute.h @@ -51,7 +51,6 @@ public: // for internal use LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); - void CheckForUpdatesAsync(std::unique_ptr updateChecker); private: HWND hWnd_; HMENU hTrayMenu_; @@ -96,8 +95,15 @@ private: LRESULT OnPowerBroadcast(HWND hWnd, WPARAM wParam, LPARAM lParam); LRESULT OnWifiStatusChange(HWND hWnd, WPARAM wParam, LPARAM lParam); LRESULT OnUpdatePopup(HWND hWnd, WPARAM wParam, LPARAM lParam); - + LRESULT OnUpdateCheckDone(HWND hWnd, WPARAM wParam, LPARAM lParam); + LRESULT OnDeviceChange(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); LRESULT OnQuietHours(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); LRESULT OnAudioServiceShutdown(HWND hWnd, WPARAM wParam, LPARAM lParam); + + // Runs on updateThread_; must only touch its own locals and post the + // result to hWnd. Declared last so it is joined (destroyed) before any + // other member goes away. + static void CheckForUpdatesAsync(HWND hWnd); + std::jthread updateThread_; }; diff --git a/WinMute/common.h b/WinMute/common.h index d766ff2..7a2e34a 100644 --- a/WinMute/common.h +++ b/WinMute/common.h @@ -74,6 +74,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include #include #include @@ -138,3 +139,5 @@ constexpr int WM_SAVESETTINGS = WM_USER + 300; constexpr int WM_WINMUTE_UPDATE_POPUP = WM_USER + 301; constexpr int WM_LOG_UPDATED = WM_USER + 302; constexpr int WM_WINMUTE_AUDIO_SERVICE_SHUTDOWN = WM_USER + 303; +/* wParam = success. lParam = UpdateInfo*, ownership passes to the receiver */ +constexpr int WM_WINMUTE_UPDATE_CHECK_DONE = WM_USER + 304;