]> repos.lx-s.de Git - winmute.git/commitdiff
Rewrote update check thread
authorlx-s <lx-s@users.noreply.github.com>
Wed, 8 Jul 2026 07:34:43 +0000 (09:34 +0200)
committerlx-s <lx-s@users.noreply.github.com>
Wed, 8 Jul 2026 07:34:43 +0000 (09:34 +0200)
WinMute/WinMute.cpp
WinMute/WinMute.h
WinMute/common.h

index 8ebb4cf2da6df022278638828e156aae8add18f7..37b75e2b49a2ec8d80e8edc51d3b195aa3a17424 100644 (file)
@@ -402,44 +402,68 @@ void WinMute::LoadMainMenuText()
 
 void WinMute::CheckForUpdates()
 {
-   auto updateChecker = std::make_unique<UpdateChecker>();
-   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> 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<UpdateInfo>();
+   const bool success = updateChecker.GetUpdateInfo(*updateInfo);
+   if (PostMessageW(hWnd, WM_WINMUTE_UPDATE_CHECK_DONE,
+                    static_cast<WPARAM>(success),
+                    reinterpret_cast<LPARAM>(updateInfo.get()))) {
+      // Ownership has passed to OnUpdateCheckDone
+      updateInfo.release();
+   }
+}
+
+LRESULT WinMute::OnUpdateCheckDone(HWND, WPARAM wParam, LPARAM lParam)
+{
+   const std::unique_ptr<UpdateInfo> updateInfo{
+      reinterpret_cast<UpdateInfo *>(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<wchar_t *>(lParam);
+      // Non-owning: the name is only valid for the duration of this call.
+      const wchar_t *wifiName = reinterpret_cast<const wchar_t *>(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:
index c1f9eb3cd111c133c223e4e17e0b069533c49cb3..10a67f2c54c29323fee27be39f2924dd32d97547 100644 (file)
@@ -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> 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_;
 };
index d766ff2fbac65444f03be736af68ff4f735d64e2..7a2e34af6b1668490a5a7eb47893c99ce57e8df3 100644 (file)
@@ -74,6 +74,7 @@ POSSIBILITY OF SUCH DAMAGE.
 #include <span>
 #include <string>
 #include <string_view>
+#include <thread>
 #include <type_traits>
 #include <unordered_map>
 #include <vector>
@@ -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;