]> repos.lx-s.de Git - winmute.git/commitdiff
Added mute on lid close structure #55
authorlx-s <lx-s@users.noreply.github.com>
Thu, 9 Jul 2026 16:14:30 +0000 (18:14 +0200)
committerlx-s <lx-s@users.noreply.github.com>
Thu, 9 Jul 2026 16:14:30 +0000 (18:14 +0200)
14 files changed:
Translations/lang-de.json
Translations/lang-en.json
WinMute/MuteControl.cpp
WinMute/MuteControl.h
WinMute/Settings_MuteDlg.cpp
WinMute/UpdateChecker.h
WinMute/WMSettings.cpp
WinMute/WMSettings.h
WinMute/WinMute.cpp
WinMute/WinMute.h
WinMute/WinMute.rc
WinMute/WinMute.vcxproj
WinMute/common.h
WinMute/resource.h

index d2df353bb4c7820ca91f3abcb34910416b508560..6ee040f46c7ffa756700252696de66ba15869893 100644 (file)
@@ -81,6 +81,7 @@
   "settings.mute.mute-with-restore.title": "Stummschalten mit Lautstärkewiederherstellung, wenn...",
   "settings.mute.mute-with-restore.when-workstation-is-locked": "... der PC gesperrt wird",
   "settings.mute.mute-with-restore.when-screen-turns-off": "... der Bildschirm in Standby geht",
+  "settings.mute.mute-with-restore.when-lid-closes": "... der Laptop zugeklappt wird",
   "settings.mute.mute-with-restore.restore-volume": "Lautstärke danach wiederherstellen",
   "settings.mute.mute-with-restore.restore-volume-delay-label": "Sekunden Verzögerung vor dem Stummschalten.",
   "settings.mute.mute-without-restore.title": "Stummschalten ohne Lautstärkenwiederherstellung, wenn...",
index 3f6bb7d34ecaea970f0850f4c8f9ce76d0bb7a6a..678568376b674b707aac669818126e215d2714c0 100644 (file)
@@ -91,6 +91,7 @@
   "settings.mute.mute-with-restore.title": "Mute with volume restore, when...",
   "settings.mute.mute-with-restore.when-workstation-is-locked": "... the computer is locked",
   "settings.mute.mute-with-restore.when-screen-turns-off": "... the screen turns off",
+  "settings.mute.mute-with-restore.when-lid-closes": "... the laptop lid closes",
   "settings.mute.mute-with-restore.restore-volume": "Restore volume afterwards",
   "settings.mute.mute-with-restore.restore-volume-delay-label": "seconds delay before muting.",
   "settings.mute.mute-without-restore.title": "Mute without volume restore, when...",
index 800e74e40721948caa8eae831973c65c66feae7b..7b962aa2b8849bd4d37e91c32a3d481f88066f47 100644 (file)
@@ -31,11 +31,13 @@ POSSIBILITY OF SUCH DAMAGE.
 -----------------------------------------------------------------------------
 */
 
+#include "MuteControl.h"
+
 #include "common.h"
 
 extern HINSTANCE hglobInstance;
 
-static constexpr int BLUETOOTH_RECONNECT_UNMUTE_DELAY = 5000; // Milliseconds
+static constexpr int BLUETOOTH_RECONNECT_UNMUTE_DELAY = 5000;  // Milliseconds
 static constexpr int MUTE_DELAY_MAGIC_VALUE = 0x198604;
 
 // Fixed timer IDs: SetTimer with an ID of 0 returns a value that is not
@@ -43,487 +45,441 @@ static constexpr int MUTE_DELAY_MAGIC_VALUE = 0x198604;
 static constexpr UINT_PTR DELAYED_MUTE_TIMER_ID = 190501;
 static constexpr UINT_PTR BLUETOOTH_UNMUTE_TIMER_ID = 190502;
 
-static const wchar_t *MUTECONTROL_CLASS_NAME = L"WinMuteMuteControl";
+static const wchar_t* MUTECONTROL_CLASS_NAME = L"WinMuteMuteControl";
 
 void CALLBACK DelayedMuteTimerProc(HWND hWnd, UINT, UINT_PTR, DWORD)
 {
-   MuteControl *muteCtrl = reinterpret_cast<MuteControl *>(GetWindowLongPtrW(hWnd, GWLP_USERDATA));
-   if (muteCtrl != nullptr)
-   {
-      muteCtrl->MuteDelayed(MUTE_DELAY_MAGIC_VALUE);
-   }
-}
-
-static void CALLBACK BluetoothUnmuteTimerProc(HWND hWnd, UINT, UINT_PTR id, DWORD)
-{
-   KillTimer(hWnd, id);
-   MuteControl *muteCtrl = reinterpret_cast<MuteControl *>(GetWindowLongPtrW(hWnd, GWLP_USERDATA));
-   if (muteCtrl != nullptr)
-   {
-      muteCtrl->CompleteVolumeRestore();
-   }
-}
-
-static LRESULT CALLBACK MuteControlWndProc(
-    HWND hWnd,
-    UINT msg,
-    WPARAM wParam,
-    LPARAM lParam)
-{
-   auto wm = reinterpret_cast<MuteControl *>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
-   switch (msg)
-   {
-   case WM_NCCREATE:
-   {
-      LPCREATESTRUCTW cs = reinterpret_cast<LPCREATESTRUCTW>(lParam);
-      SetWindowLongPtrW(hWnd, GWLP_USERDATA,
-                        reinterpret_cast<LONG_PTR>(cs->lpCreateParams));
-      return TRUE;
-   }
-   default:
-      break;
-   }
-   return (wm)
-              ? wm->WindowProc(hWnd, msg, wParam, lParam)
-              : DefWindowProcW(hWnd, msg, wParam, lParam);
+    MuteControl* muteCtrl =
+        reinterpret_cast<MuteControl*>(GetWindowLongPtrW(hWnd, GWLP_USERDATA));
+    if (muteCtrl != nullptr) {
+        muteCtrl->MuteDelayed(MUTE_DELAY_MAGIC_VALUE);
+    }
+}
+
+static void CALLBACK BluetoothUnmuteTimerProc(HWND hWnd, UINT, UINT_PTR id,
+                                              DWORD)
+{
+    KillTimer(hWnd, id);
+    MuteControl* muteCtrl =
+        reinterpret_cast<MuteControl*>(GetWindowLongPtrW(hWnd, GWLP_USERDATA));
+    if (muteCtrl != nullptr) {
+        muteCtrl->CompleteVolumeRestore();
+    }
+}
+
+static LRESULT CALLBACK MuteControlWndProc(HWND hWnd, UINT msg, WPARAM wParam,
+                                           LPARAM lParam)
+{
+    auto wm =
+        reinterpret_cast<MuteControl*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
+    switch (msg) {
+        case WM_NCCREATE: {
+            LPCREATESTRUCTW cs = reinterpret_cast<LPCREATESTRUCTW>(lParam);
+            SetWindowLongPtrW(hWnd, GWLP_USERDATA,
+                              reinterpret_cast<LONG_PTR>(cs->lpCreateParams));
+            return TRUE;
+        }
+        default:
+            break;
+    }
+    return (wm) ? wm->WindowProc(hWnd, msg, wParam, lParam)
+                : DefWindowProcW(hWnd, msg, wParam, lParam);
 }
 
 MuteControl::MuteControl()
 {
-   MuteConfig initMuteConf;
-   initMuteConf.active = false;
-   initMuteConf.shouldMute = false;
-   for (int i = 0; i < MuteTypeCount; ++i)
-   {
-      muteConfig_.push_back(initMuteConf);
-   }
+    MuteConfig initMuteConf;
+    initMuteConf.active = false;
+    initMuteConf.shouldMute = false;
+    for (int i = 0; i < MuteTypeCount; ++i) {
+        muteConfig_.push_back(initMuteConf);
+    }
 }
 
 MuteControl::~MuteControl()
 {
-   if (hMuteCtrlWnd_ != nullptr)
-   {
-      DestroyWindow(hMuteCtrlWnd_);
-      hMuteCtrlWnd_ = nullptr;
-   }
-   UnregisterClassW(MUTECONTROL_CLASS_NAME, hglobInstance);
-}
-
-bool MuteControl::Init(HWND hParent, const TrayIcon *trayIcon)
-{
-   WNDCLASSEXW wndClass{0};
-   wndClass.cbSize = sizeof(wndClass);
-   wndClass.lpfnWndProc = MuteControlWndProc;
-   wndClass.hInstance = hglobInstance;
-   wndClass.lpszClassName = MUTECONTROL_CLASS_NAME;
-   if (!RegisterClassExW(&wndClass))
-   {
-      WMLog::GetInstance().LogWinError(L"RegisterClassEx");
-      return false;
-   }
-   hMuteCtrlWnd_ = CreateWindowEx(
-       WS_EX_TOOLWINDOW,
-       MUTECONTROL_CLASS_NAME,
-       L"",
-       0,
-       0, 0, 0, 0,
-       nullptr,
-       nullptr,
-       hglobInstance,
-       this);
-   if (hMuteCtrlWnd_ == nullptr)
-   {
-      WMLog::GetInstance().LogWinError(L"CreateWindowEx");
-      UnregisterClassW(MUTECONTROL_CLASS_NAME, hglobInstance);
-      return false;
-   }
-   winAudio_ = std::make_unique<VistaAudio>();
-   if (!winAudio_->Init(hParent))
-   {
-      DestroyWindow(hMuteCtrlWnd_);
-      hMuteCtrlWnd_ = nullptr;
-      UnregisterClassW(MUTECONTROL_CLASS_NAME, hglobInstance);
-      return false;
-   }
-
-   trayIcon_ = trayIcon;
-   return true;
-}
-
-LRESULT CALLBACK MuteControl::WindowProc(
-    HWND hWnd,
-    UINT msg,
-    WPARAM wParam,
-    LPARAM lParam)
-{
-   return DefWindowProc(hWnd, msg, wParam, lParam);
+    if (hMuteCtrlWnd_ != nullptr) {
+        DestroyWindow(hMuteCtrlWnd_);
+        hMuteCtrlWnd_ = nullptr;
+    }
+    UnregisterClassW(MUTECONTROL_CLASS_NAME, hglobInstance);
+}
+
+bool MuteControl::Init(HWND hParent, const TrayIcon* trayIcon)
+{
+    WNDCLASSEXW wndClass{0};
+    wndClass.cbSize = sizeof(wndClass);
+    wndClass.lpfnWndProc = MuteControlWndProc;
+    wndClass.hInstance = hglobInstance;
+    wndClass.lpszClassName = MUTECONTROL_CLASS_NAME;
+    if (!RegisterClassExW(&wndClass)) {
+        WMLog::GetInstance().LogWinError(L"RegisterClassEx");
+        return false;
+    }
+    hMuteCtrlWnd_ =
+        CreateWindowEx(WS_EX_TOOLWINDOW, MUTECONTROL_CLASS_NAME, L"", 0, 0, 0,
+                       0, 0, nullptr, nullptr, hglobInstance, this);
+    if (hMuteCtrlWnd_ == nullptr) {
+        WMLog::GetInstance().LogWinError(L"CreateWindowEx");
+        UnregisterClassW(MUTECONTROL_CLASS_NAME, hglobInstance);
+        return false;
+    }
+    winAudio_ = std::make_unique<VistaAudio>();
+    if (!winAudio_->Init(hParent)) {
+        DestroyWindow(hMuteCtrlWnd_);
+        hMuteCtrlWnd_ = nullptr;
+        UnregisterClassW(MUTECONTROL_CLASS_NAME, hglobInstance);
+        return false;
+    }
+
+    trayIcon_ = trayIcon;
+    return true;
+}
+
+LRESULT CALLBACK MuteControl::WindowProc(HWND hWnd, UINT msg, WPARAM wParam,
+                                         LPARAM lParam)
+{
+    return DefWindowProc(hWnd, msg, wParam, lParam);
 }
 
 void MuteControl::SetMute(bool mute)
 {
-   WMLog::GetInstance().LogInfo(L"Manual muting: {}", mute ? L"on" : L"off");
-   winAudio_->SetMute(mute);
+    WMLog::GetInstance().LogInfo(L"Manual muting: {}", mute ? L"on" : L"off");
+    winAudio_->SetMute(mute);
 }
 
 void MuteControl::SaveMuteStatus()
 {
-   const bool alreadySaved = std::any_of(
-       muteConfig_.begin(),
-       muteConfig_.end(),
-       [](const MuteConfig &conf)
-       {
-          return conf.shouldMute && conf.active;
-       });
+    const bool alreadySaved = std::any_of(
+        muteConfig_.begin(), muteConfig_.end(),
+        [](const MuteConfig& conf) { return conf.shouldMute && conf.active; });
 
-   if (alreadySaved)
-   {
-      WMLog::GetInstance().LogInfo(L"Muting event already active. Skipping status save");
-   }
-   else
-   {
-      WMLog::GetInstance().LogInfo(L"Saving mute status");
-      winAudio_->SaveMuteStatus();
-   }
+    if (alreadySaved) {
+        WMLog::GetInstance().LogInfo(
+            L"Muting event already active. Skipping status save");
+    } else {
+        WMLog::GetInstance().LogInfo(L"Saving mute status");
+        winAudio_->SaveMuteStatus();
+    }
 }
 
-void MuteControl::ShowNotification(const std::wstring &title, const std::wstring &text)
+void MuteControl::ShowNotification(const std::wstring& title,
+                                   const std::wstring& text)
 {
-   if (notificationsEnabled_ && trayIcon_ != nullptr)
-   {
-      trayIcon_->ShowPopup(title, text);
-   }
+    if (notificationsEnabled_ && trayIcon_ != nullptr) {
+        trayIcon_->ShowPopup(title, text);
+    }
 }
 
 void MuteControl::SetNotifications(bool enable)
 {
-   notificationsEnabled_ = enable;
+    notificationsEnabled_ = enable;
 }
 
 void MuteControl::MuteDelayed(int magic)
 {
-   if (magic != MUTE_DELAY_MAGIC_VALUE || delayedMuteTimerId_ == 0)
-   {
-      return;
-   }
-   WMLog::GetInstance().LogInfo(L"Muting workstation after delay");
-   MuteNow();
-   KillTimer(hMuteCtrlWnd_, delayedMuteTimerId_);
-   delayedMuteTimerId_ = 0;
+    if (magic != MUTE_DELAY_MAGIC_VALUE || delayedMuteTimerId_ == 0) {
+        return;
+    }
+    WMLog::GetInstance().LogInfo(L"Muting workstation after delay");
+    MuteNow();
+    KillTimer(hMuteCtrlWnd_, delayedMuteTimerId_);
+    delayedMuteTimerId_ = 0;
 }
 
 bool MuteControl::StartDelayedMute()
 {
-   if (SetTimer(
-           hMuteCtrlWnd_,
-           DELAYED_MUTE_TIMER_ID,
-           muteDelaySeconds_ * 1000,
-           DelayedMuteTimerProc) == 0)
-   {
-      WMLog::GetInstance().LogWinError(L"SetTimer", GetLastError());
-      delayedMuteTimerId_ = 0;
-   }
-   else
-   {
-      delayedMuteTimerId_ = DELAYED_MUTE_TIMER_ID;
-   }
-   return delayedMuteTimerId_ != 0;
+    if (SetTimer(hMuteCtrlWnd_, DELAYED_MUTE_TIMER_ID, muteDelaySeconds_ * 1000,
+                 DelayedMuteTimerProc) == 0)
+    {
+        WMLog::GetInstance().LogWinError(L"SetTimer", GetLastError());
+        delayedMuteTimerId_ = 0;
+    } else {
+        delayedMuteTimerId_ = DELAYED_MUTE_TIMER_ID;
+    }
+    return delayedMuteTimerId_ != 0;
 }
 
 void MuteControl::RestoreVolume(bool withDelay)
 {
-   WMLog &log = WMLog::GetInstance();
-   if (!restoreVolume_)
-   {
-      log.LogInfo(L"Volume Restore has been disabled");
-      return;
-   }
-   const bool restore = !std::any_of(
-       muteConfig_.begin(),
-       muteConfig_.end(),
-       [](const MuteConfig &conf)
-       {
-          return conf.shouldMute && conf.active;
-       });
-   if (!restore)
-   {
-      log.LogInfo(L"Skipping restore since other mute event is currently active");
-   }
-   else if (delayedMuteTimerId_ != 0)
-   {
-      KillTimer(hMuteCtrlWnd_, delayedMuteTimerId_);
-      delayedMuteTimerId_ = 0;
-      log.LogInfo(L"Skipping restore, since delayed mute was not triggered yet");
-   }
-   else if (withDelay)
-   {
-      log.LogInfo(L"Restoring previous mute state after Bluetooth delay");
-      ShowNotification(
-          WMi18n::GetInstance().GetTranslationW("popup.volume-restored.title"),
-          WMi18n::GetInstance().GetTranslationW("popup.volume-restored.text"));
-      if (SetTimer(
-              hMuteCtrlWnd_,
-              BLUETOOTH_UNMUTE_TIMER_ID,
-              BLUETOOTH_RECONNECT_UNMUTE_DELAY,
-              BluetoothUnmuteTimerProc) == 0)
-      {
-         log.LogWinError(L"SetTimer (Bluetooth unmute delay)");
-         bluetoothUnmuteTimerId_ = 0;
-         CompleteVolumeRestore(); // fall back to immediate restore
-      }
-      else
-      {
-         bluetoothUnmuteTimerId_ = BLUETOOTH_UNMUTE_TIMER_ID;
-      }
-   }
-   else
-   {
-      log.LogInfo(L"Restoring previous mute state");
-      ShowNotification(
-          WMi18n::GetInstance().GetTranslationW("popup.volume-restored.title"),
-          WMi18n::GetInstance().GetTranslationW("popup.volume-restored.text"));
-      CompleteVolumeRestore();
-   }
+    WMLog& log = WMLog::GetInstance();
+    if (!restoreVolume_) {
+        log.LogInfo(L"Volume Restore has been disabled");
+        return;
+    }
+    const bool restore = !std::any_of(
+        muteConfig_.begin(), muteConfig_.end(),
+        [](const MuteConfig& conf) { return conf.shouldMute && conf.active; });
+    if (!restore) {
+        log.LogInfo(
+            L"Skipping restore since other mute event is currently active");
+    } else if (delayedMuteTimerId_ != 0) {
+        KillTimer(hMuteCtrlWnd_, delayedMuteTimerId_);
+        delayedMuteTimerId_ = 0;
+        log.LogInfo(
+            L"Skipping restore, since delayed mute was not triggered yet");
+    } else if (withDelay) {
+        log.LogInfo(L"Restoring previous mute state after Bluetooth delay");
+        ShowNotification(WMi18n::GetInstance().GetTranslationW(
+                             "popup.volume-restored.title"),
+                         WMi18n::GetInstance().GetTranslationW(
+                             "popup.volume-restored.text"));
+        if (SetTimer(hMuteCtrlWnd_, BLUETOOTH_UNMUTE_TIMER_ID,
+                     BLUETOOTH_RECONNECT_UNMUTE_DELAY,
+                     BluetoothUnmuteTimerProc) == 0)
+        {
+            log.LogWinError(L"SetTimer (Bluetooth unmute delay)");
+            bluetoothUnmuteTimerId_ = 0;
+            CompleteVolumeRestore();  // fall back to immediate restore
+        } else {
+            bluetoothUnmuteTimerId_ = BLUETOOTH_UNMUTE_TIMER_ID;
+        }
+    } else {
+        log.LogInfo(L"Restoring previous mute state");
+        ShowNotification(WMi18n::GetInstance().GetTranslationW(
+                             "popup.volume-restored.title"),
+                         WMi18n::GetInstance().GetTranslationW(
+                             "popup.volume-restored.text"));
+        CompleteVolumeRestore();
+    }
 }
 
 void MuteControl::CompleteVolumeRestore()
 {
-   bluetoothUnmuteTimerId_ = 0;
-   winAudio_->RestoreMuteStatus();
-   if (mediaConfig_.tryResume)
-   {
-      // Only resumes if a previous RequestPause actually paused the session.
-      mediaController_.RequestResume();
-   }
+    bluetoothUnmuteTimerId_ = 0;
+    winAudio_->RestoreMuteStatus();
+    if (mediaConfig_.tryResume) {
+        // Only resumes if a previous RequestPause actually paused the session.
+        mediaController_.RequestResume();
+    }
 }
 
 void MuteControl::SetRestoreVolume(bool enable)
 {
-   restoreVolume_ = enable;
+    restoreVolume_ = enable;
 }
 
 void MuteControl::SetMuteDelay(int delaySeconds)
 {
-   muteDelaySeconds_ = delaySeconds;
+    muteDelaySeconds_ = delaySeconds;
 }
 
 void MuteControl::SetMuteOnWorkstationLock(bool enable)
 {
-   muteConfig_[MuteTypeWorkstationLock].shouldMute = enable;
+    muteConfig_[MuteTypeWorkstationLock].shouldMute = enable;
 }
 
 void MuteControl::SetMuteOnLogout(bool enable)
 {
-   muteConfig_[MuteTypeLogout].shouldMute = enable;
+    muteConfig_[MuteTypeLogout].shouldMute = enable;
 }
 
 void MuteControl::SetMuteOnSuspend(bool enable)
 {
-   muteConfig_[MuteTypeSuspend].shouldMute = enable;
+    muteConfig_[MuteTypeSuspend].shouldMute = enable;
 }
 
 void MuteControl::SetMuteOnShutdown(bool enable)
 {
-   muteConfig_[MuteTypeShutdown].shouldMute = enable;
+    muteConfig_[MuteTypeShutdown].shouldMute = enable;
 }
 
 void MuteControl::SetMuteOnRemoteSession(bool enable)
 {
-   muteConfig_[MuteTypeRemoteSession].shouldMute = enable;
+    muteConfig_[MuteTypeRemoteSession].shouldMute = enable;
 }
 
 void MuteControl::SetMuteOnDisplayStandby(bool enable)
 {
-   muteConfig_[MuteTypeDisplayStandby].shouldMute = enable;
+    muteConfig_[MuteTypeDisplayStandby].shouldMute = enable;
 }
 
+void MuteControl::SetMuteOnLidClose(bool enable)
+{
+    muteConfig_[MuteTypeLidClose].shouldMute = enable;
+}
 void MuteControl::SetMuteOnBluetoothDisconnect(bool enable)
 {
-   muteConfig_[MuteTypeBluetoothDisconnect].shouldMute = enable;
+    muteConfig_[MuteTypeBluetoothDisconnect].shouldMute = enable;
 }
 
 void MuteControl::SetMuteTryPauseMedia(bool enable)
 {
-   mediaConfig_.tryPause = enable;
+    mediaConfig_.tryPause = enable;
 }
 
 void MuteControl::SetMuteTryResumeMedia(bool enable)
 {
-   mediaConfig_.tryResume = enable;
+    mediaConfig_.tryResume = enable;
 }
 
 bool MuteControl::GetRestoreVolume()
 {
-   return restoreVolume_;
+    return restoreVolume_;
 }
 
 bool MuteControl::GetMuteOnWorkstationLock() const
 {
-   return muteConfig_[MuteTypeWorkstationLock].shouldMute;
+    return muteConfig_[MuteTypeWorkstationLock].shouldMute;
 }
 
 bool MuteControl::GetMuteOnRemoteSession() const
 {
-   return muteConfig_[MuteTypeRemoteSession].shouldMute;
+    return muteConfig_[MuteTypeRemoteSession].shouldMute;
 }
 
 bool MuteControl::GetMuteOnDisplayStandby() const
 {
-   return muteConfig_[MuteTypeDisplayStandby].shouldMute;
+    return muteConfig_[MuteTypeDisplayStandby].shouldMute;
+}
+
+bool MuteControl::GetMuteOnLidClose() const
+{
+    return muteConfig_[MuteTypeLidClose].shouldMute;
 }
 
 bool MuteControl::GetMuteOnBluetoothDisconnect() const
 {
-   return muteConfig_[MuteTypeBluetoothDisconnect].shouldMute;
+    return muteConfig_[MuteTypeBluetoothDisconnect].shouldMute;
 }
 
 bool MuteControl::GetMuteOnLogout() const
 {
-   return muteConfig_[MuteTypeLogout].shouldMute;
+    return muteConfig_[MuteTypeLogout].shouldMute;
 }
 
 bool MuteControl::GetMuteOnSuspend() const
 {
-   return muteConfig_[MuteTypeSuspend].shouldMute;
+    return muteConfig_[MuteTypeSuspend].shouldMute;
 }
 
 bool MuteControl::GetMuteOnShutdown() const
 {
-   return muteConfig_[MuteTypeShutdown].shouldMute;
+    return muteConfig_[MuteTypeShutdown].shouldMute;
 }
 
 void MuteControl::MuteNow()
 {
-   WMLog::GetInstance().LogInfo(L"Muting workstation");
-   ShowNotification(
-       WMi18n::GetInstance().GetTranslationW("popup.muting-workstation.title"),
-       WMi18n::GetInstance().GetTranslationW("popup.muting-workstation.text"));
-   winAudio_->SetMute(true);
-   if (mediaConfig_.tryPause)
-   {
-      mediaController_.RequestPause();
-   }
-}
-
-void MuteControl::NotifyRestoreCondition(MuteType type, bool active, bool withDelay)
-{
-   if (active)
-   {
-      SaveMuteStatus();
-      muteConfig_[type].active = active;
-      if (muteConfig_[type].shouldMute)
-      {
-         if (muteDelaySeconds_ == 0)
-         {
-            MuteNow();
-         }
-         else
-         {
-            WMLog::GetInstance().LogInfo(L"Starting delayed mute timer...");
-            StartDelayedMute();
-         }
-      }
-   }
-   else
-   {
-      if (muteConfig_[type].active)
-      {
-         muteConfig_[type].active = false;
-         if (muteConfig_[type].shouldMute)
-         {
-            RestoreVolume(withDelay);
-         }
-      }
-   }
+    WMLog::GetInstance().LogInfo(L"Muting workstation");
+    ShowNotification(
+        WMi18n::GetInstance().GetTranslationW("popup.muting-workstation.title"),
+        WMi18n::GetInstance().GetTranslationW("popup.muting-workstation.text"));
+    winAudio_->SetMute(true);
+    if (mediaConfig_.tryPause) {
+        mediaController_.RequestPause();
+    }
+}
+
+void MuteControl::NotifyRestoreCondition(MuteType type, bool active,
+                                         bool withDelay)
+{
+    if (active) {
+        SaveMuteStatus();
+        muteConfig_[type].active = active;
+        if (muteConfig_[type].shouldMute) {
+            if (muteDelaySeconds_ == 0) {
+                MuteNow();
+            } else {
+                WMLog::GetInstance().LogInfo(L"Starting delayed mute timer...");
+                StartDelayedMute();
+            }
+        }
+    } else {
+        if (muteConfig_[type].active) {
+            muteConfig_[type].active = false;
+            if (muteConfig_[type].shouldMute) {
+                RestoreVolume(withDelay);
+            }
+        }
+    }
 }
 
 void MuteControl::NotifyWorkstationLock(bool active)
 {
-   WMLog::GetInstance().LogInfo(L"Mute Event: Workstation Lock {}",
-                                active ? L"start" : L"stop");
-   NotifyRestoreCondition(MuteTypeWorkstationLock, active);
+    WMLog::GetInstance().LogInfo(L"Mute Event: Workstation Lock {}",
+                                 active ? L"start" : L"stop");
+    NotifyRestoreCondition(MuteTypeWorkstationLock, active);
 }
 
 void MuteControl::NotifyRemoteSession(bool active)
 {
-   WMLog::GetInstance().LogInfo(L"Mute Event: Remote Session {}",
-                                active ? L"start" : L"stop");
-   NotifyRestoreCondition(MuteTypeRemoteSession, active);
+    WMLog::GetInstance().LogInfo(L"Mute Event: Remote Session {}",
+                                 active ? L"start" : L"stop");
+    NotifyRestoreCondition(MuteTypeRemoteSession, active);
 }
 
 void MuteControl::NotifyDisplayStandby(bool active)
 {
-   if (displayWasOffOnce_ || active)
-   {
-      WMLog::GetInstance().LogInfo(L"Mute Event: Display Standby {}",
-                                   active ? L"start" : L"stop");
-      NotifyRestoreCondition(MuteTypeDisplayStandby, active);
-      displayWasOffOnce_ = true;
-   }
+    if (displayWasOffOnce_ || active) {
+        WMLog::GetInstance().LogInfo(L"Mute Event: Display Standby {}",
+                                     active ? L"start" : L"stop");
+        NotifyRestoreCondition(MuteTypeDisplayStandby, active);
+        displayWasOffOnce_ = true;
+    }
+}
+
+void MuteControl::NotifyLidClosed(bool active)
+{
+    WMLog::GetInstance().LogInfo(L"Mute Event: Lid Close {}",
+                                 active ? L"start" : L"stop");
+    NotifyRestoreCondition(MuteTypeLidClose, active);
 }
 
 void MuteControl::NotifyBluetoothConnected(bool connected)
 {
-   WMLog::GetInstance().LogInfo(
-       L"Mute Event: Bluetooth audio device {}",
-       connected ? L"connected" : L"disconnected");
-   NotifyRestoreCondition(MuteTypeBluetoothDisconnect, !connected, true);
+    WMLog::GetInstance().LogInfo(L"Mute Event: Bluetooth audio device {}",
+                                 connected ? L"connected" : L"disconnected");
+    NotifyRestoreCondition(MuteTypeBluetoothDisconnect, !connected, true);
 }
 
 void MuteControl::NotifyLogout()
 {
-   WMLog::GetInstance().LogInfo(L"Mute Event: Logout start");
-   if (muteConfig_[MuteTypeLogout].shouldMute)
-   {
-      winAudio_->SetMute(true);
-   }
+    WMLog::GetInstance().LogInfo(L"Mute Event: Logout start");
+    if (muteConfig_[MuteTypeLogout].shouldMute) {
+        winAudio_->SetMute(true);
+    }
 }
 
-void MuteControl::NotifySuspend(bool /*active*/)
+void MuteControl::NotifySuspend(bool [[maybe_unused]] active)
 {
-   WMLog::GetInstance().LogInfo(L"Mute Event: Suspend start");
-   if (muteConfig_[MuteTypeSuspend].shouldMute)
-   {
-      winAudio_->SetMute(true);
-   }
+    WMLog::GetInstance().LogInfo(L"Mute Event: Suspend start");
+    if (muteConfig_[MuteTypeSuspend].shouldMute) {
+        winAudio_->SetMute(true);
+    }
 }
 
 void MuteControl::NotifyShutdown()
 {
-   WMLog::GetInstance().LogInfo(L"Mute Event: Shutdown start");
-   if (muteConfig_[MuteTypeShutdown].shouldMute)
-   {
-      winAudio_->SetMute(true);
-   }
+    WMLog::GetInstance().LogInfo(L"Mute Event: Shutdown start");
+    if (muteConfig_[MuteTypeShutdown].shouldMute) {
+        winAudio_->SetMute(true);
+    }
 }
 
 void MuteControl::NotifyQuietHours(bool active)
 {
-   if (active)
-   {
-      // SaveMuteStatus() must stay the only save here: calling
-      // winAudio_->SaveMuteStatus() directly would overwrite the state
-      // remembered by an already-active mute event (e.g. workstation lock)
-      // with the currently muted state.
-      SaveMuteStatus();
-      WMLog::GetInstance().LogInfo(L"Mute Event: Quiet Hours started");
-      winAudio_->SetMute(true);
-   }
-   else
-   {
-      WMLog::GetInstance().LogInfo(L"Mute Event: Quiet Hours ended");
-      RestoreVolume();
-   }
+    if (active) {
+        // SaveMuteStatus() must stay the only save here: calling
+        // winAudio_->SaveMuteStatus() directly would overwrite the state
+        // remembered by an already-active mute event (e.g. workstation lock)
+        // with the currently muted state.
+        SaveMuteStatus();
+        WMLog::GetInstance().LogInfo(L"Mute Event: Quiet Hours started");
+        winAudio_->SetMute(true);
+    } else {
+        WMLog::GetInstance().LogInfo(L"Mute Event: Quiet Hours ended");
+        RestoreVolume();
+    }
 }
 
 void MuteControl::SetManagedEndpoints(
-    const std::vector<std::wstring> &endpoints,
-    bool isAllowList)
+    const std::vector<std::wstring>& endpoints, bool isAllowList)
 {
-   winAudio_->MuteSpecificEndpoints(true);
-   winAudio_->SetManagedEndpoints(endpoints, isAllowList);
+    winAudio_->MuteSpecificEndpoints(true);
+    winAudio_->SetManagedEndpoints(endpoints, isAllowList);
 }
 
 void MuteControl::ClearManagedEndpoints()
 {
-   winAudio_->MuteSpecificEndpoints(false);
+    winAudio_->MuteSpecificEndpoints(false);
 }
index cb81cce988c21e414b94c06f08f22ed3fcfe5367..05b7adb031697da21580da196fcfb04249de6179 100644 (file)
@@ -36,110 +36,115 @@ POSSIBILITY OF SUCH DAMAGE.
 #include "common.h"
 
 class MuteControl {
-public:
-   MuteControl();
-   ~MuteControl();
-   MuteControl(const MuteControl&) = delete;
-   MuteControl& operator=(const MuteControl&) = delete;
-
-   bool Init(HWND hParent, const TrayIcon* trayIcon);
-
-   void SetNotifications(bool enable);
-
-   void SetMute(bool mute);
-
-   void SetRestoreVolume(bool enable);
-
-   void SetMuteDelay(int delaySeconds);
-
-   void SetMuteOnWorkstationLock(bool enable);
-   void SetMuteOnRemoteSession(bool enable);
-   void SetMuteOnDisplayStandby(bool enable);
-   void SetMuteOnBluetoothDisconnect(bool enable);
-
-   void SetMuteTryPauseMedia(bool enable);
-   void SetMuteTryResumeMedia(bool enable);
-
-   void SetMuteOnLogout(bool enable);
-   void SetMuteOnSuspend(bool enable);
-   void SetMuteOnShutdown(bool enable);
-
-   bool GetRestoreVolume();
-
-   bool GetMuteOnWorkstationLock()  const;
-   bool GetMuteOnRemoteSession()  const;
-   bool GetMuteOnDisplayStandby()  const;
-   bool GetMuteOnBluetoothDisconnect() const;
-
-   bool GetMuteOnLogout() const;
-   bool GetMuteOnSuspend() const;
-   bool GetMuteOnShutdown() const;
-
-   void NotifyWorkstationLock(bool active);
-   void NotifyRemoteSession(bool active);
-   void NotifyDisplayStandby(bool active);
-   void NotifyBluetoothConnected(bool connected);
-
-   void NotifyLogout();
-   void NotifySuspend(bool active);
-   void NotifyShutdown();
-
-   void NotifyQuietHours(bool active);
-
-   void SetManagedEndpoints(
-      const std::vector<std::wstring>& endpoints,
-      bool isAllowList);
-   void ClearManagedEndpoints();
-
-   LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
-
-   // Should only be called internally
-   void MuteDelayed(int magic);
-   void CompleteVolumeRestore();
-private:
-   enum MuteType
-   {
-      // With restore
-      MuteTypeWorkstationLock = 0,
-      MuteTypeRemoteSession,
-      MuteTypeDisplayStandby,
-      MuteTypeBluetoothDisconnect,
-
-      // Without restore
-      MuteTypeLogout,
-      MuteTypeSuspend,
-      MuteTypeShutdown,
-      MuteTypeCount // Meta
-   };
-   struct MuteConfig {
-      bool shouldMute;
-      bool active;
-   };
-   struct MediaConfig {
-      bool tryPause = false;
-      bool tryResume = false;
-   } mediaConfig_;
-   std::vector<MuteConfig> muteConfig_;
-   bool restoreVolume_ = false;
-   bool notificationsEnabled_ = false;
-   int muteDelaySeconds_ = 0;
-   UINT_PTR delayedMuteTimerId_ = 0;
-   UINT_PTR bluetoothUnmuteTimerId_ = 0;
-   std::unique_ptr<WinAudio> winAudio_;
-   MediaPlaybackController mediaController_;
-   HWND hMuteCtrlWnd_ = nullptr;
-
-   // Since a power message is sent right after registering
-   // We skip the first "was on" message
-   bool displayWasOffOnce_ = false;
-
-   const TrayIcon* trayIcon_ = nullptr;
-
-   void NotifyRestoreCondition(MuteType type, bool active, bool withDelay = false);
-   void SaveMuteStatus();
-   void RestoreVolume(bool withDelay = false);
-   void ShowNotification(const std::wstring& title, const std::wstring& text);
-   bool StartDelayedMute();
-
-   void MuteNow();
+   public:
+    MuteControl();
+    ~MuteControl();
+    MuteControl(const MuteControl&) = delete;
+    MuteControl& operator=(const MuteControl&) = delete;
+
+    bool Init(HWND hParent, const TrayIcon* trayIcon);
+
+    void SetNotifications(bool enable);
+
+    void SetMute(bool mute);
+
+    void SetRestoreVolume(bool enable);
+
+    void SetMuteDelay(int delaySeconds);
+
+    void SetMuteOnWorkstationLock(bool enable);
+    void SetMuteOnRemoteSession(bool enable);
+    void SetMuteOnDisplayStandby(bool enable);
+    void SetMuteOnLidClose(bool enable);
+    void SetMuteOnBluetoothDisconnect(bool enable);
+
+    void SetMuteTryPauseMedia(bool enable);
+    void SetMuteTryResumeMedia(bool enable);
+
+    void SetMuteOnLogout(bool enable);
+    void SetMuteOnSuspend(bool enable);
+    void SetMuteOnShutdown(bool enable);
+
+    bool GetRestoreVolume();
+
+    bool GetMuteOnWorkstationLock() const;
+    bool GetMuteOnRemoteSession() const;
+    bool GetMuteOnDisplayStandby() const;
+    bool GetMuteOnLidClose() const;
+    bool GetMuteOnBluetoothDisconnect() const;
+
+    bool GetMuteOnLogout() const;
+    bool GetMuteOnSuspend() const;
+    bool GetMuteOnShutdown() const;
+
+    void NotifyWorkstationLock(bool active);
+    void NotifyRemoteSession(bool active);
+    void NotifyDisplayStandby(bool active);
+    void NotifyLidClosed(bool active);
+    void NotifyBluetoothConnected(bool connected);
+
+    void NotifyLogout();
+    void NotifySuspend(bool active);
+    void NotifyShutdown();
+
+    void NotifyQuietHours(bool active);
+
+    void SetManagedEndpoints(const std::vector<std::wstring>& endpoints,
+                             bool isAllowList);
+    void ClearManagedEndpoints();
+
+    LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam,
+                                LPARAM lParam);
+
+    // Should only be called internally
+    void MuteDelayed(int magic);
+    void CompleteVolumeRestore();
+
+   private:
+    enum MuteType {
+        // With restore
+        MuteTypeWorkstationLock = 0,
+        MuteTypeRemoteSession,
+        MuteTypeDisplayStandby,
+        MuteTypeLidClose,
+        MuteTypeBluetoothDisconnect,
+
+        // Without restore
+        MuteTypeLogout,
+        MuteTypeSuspend,
+        MuteTypeShutdown,
+        MuteTypeCount  // Meta
+    };
+    struct MuteConfig {
+        bool shouldMute;
+        bool active;
+    };
+    struct MediaConfig {
+        bool tryPause = false;
+        bool tryResume = false;
+    } mediaConfig_;
+    std::vector<MuteConfig> muteConfig_;
+    bool restoreVolume_ = false;
+    bool notificationsEnabled_ = false;
+    int muteDelaySeconds_ = 0;
+    UINT_PTR delayedMuteTimerId_ = 0;
+    UINT_PTR bluetoothUnmuteTimerId_ = 0;
+    std::unique_ptr<WinAudio> winAudio_;
+    MediaPlaybackController mediaController_;
+    HWND hMuteCtrlWnd_ = nullptr;
+
+    // Since a power message is sent right after registering
+    // We skip the first "was on" message
+    bool displayWasOffOnce_ = false;
+
+    const TrayIcon* trayIcon_ = nullptr;
+
+    void NotifyRestoreCondition(MuteType type, bool active,
+                                bool withDelay = false);
+    void SaveMuteStatus();
+    void RestoreVolume(bool withDelay = false);
+    void ShowNotification(const std::wstring& title, const std::wstring& text);
+    bool StartDelayedMute();
+
+    void MuteNow();
 };
index 452d4db0beafbc64281e50a336c0354bce79c98d..75c4170022c2f6255ca373a7906b711b0f4fc77b 100644 (file)
@@ -59,6 +59,7 @@ static void LoadMuteDlgTranslation(HWND hDlg)
    i18n.SetItemText(hDlg, IDC_GROUP_MUTE_WITH_RESTORE, "settings.mute.mute-with-restore.title");
    i18n.SetItemText(hDlg, IDC_MUTE_WHEN_WS_LOCKED, "settings.mute.mute-with-restore.when-workstation-is-locked");
    i18n.SetItemText(hDlg, IDC_MUTE_WHEN_SCREEN_OFF, "settings.mute.mute-with-restore.when-screen-turns-off");
+   i18n.SetItemText(hDlg, IDC_MUTE_WHEN_LID_CLOSE, "settings.mute.mute-with-restore.when-lid-closes");
    i18n.SetItemText(hDlg, IDC_RESTOREVOLUME, "settings.mute.mute-with-restore.restore-volume");
    i18n.SetItemText(hDlg, IDC_DELAY_MUTING_LABEL, "settings.mute.mute-with-restore.restore-volume-delay-label");
 
@@ -90,6 +91,7 @@ INT_PTR CALLBACK Settings_MuteDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM
 
       HWND hMuteOnLock = GetDlgItem(hDlg, IDC_MUTE_WHEN_WS_LOCKED);
       HWND hMuteOnScreenOff = GetDlgItem(hDlg, IDC_MUTE_WHEN_SCREEN_OFF);
+      HWND hMuteOnLidClose = GetDlgItem(hDlg, IDC_MUTE_WHEN_LID_CLOSE);
       HWND hMuteOnRDP = GetDlgItem(hDlg, IDC_MUTE_WHEN_RDP_SESSION);
       HWND hRestoreVolume = GetDlgItem(hDlg, IDC_RESTOREVOLUME);
 
@@ -114,6 +116,7 @@ INT_PTR CALLBACK Settings_MuteDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM
       // With restore
       SetCheckButton(hMuteOnLock, *settings, SettingsKey::MUTE_ON_LOCK);
       SetCheckButton(hMuteOnScreenOff, *settings, SettingsKey::MUTE_ON_DISPLAYSTANDBY);
+      SetCheckButton(hMuteOnLidClose, *settings, SettingsKey::MUTE_ON_LIDCLOSE);
       SetCheckButton(hMuteOnRDP, *settings, SettingsKey::MUTE_ON_RDP);
       SetCheckButton(hRestoreVolume, *settings, SettingsKey::RESTORE_AUDIO);
 
@@ -152,6 +155,7 @@ INT_PTR CALLBACK Settings_MuteDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM
 
       HWND hMuteOnLock = GetDlgItem(hDlg, IDC_MUTE_WHEN_WS_LOCKED);
       HWND hMuteOnScreenOff = GetDlgItem(hDlg, IDC_MUTE_WHEN_SCREEN_OFF);
+      HWND hMuteOnLidClose = GetDlgItem(hDlg, IDC_MUTE_WHEN_LID_CLOSE);
       HWND hMuteOnRDP = GetDlgItem(hDlg, IDC_MUTE_WHEN_RDP_SESSION);
       HWND hRestoreVolume = GetDlgItem(hDlg, IDC_RESTOREVOLUME);
 
@@ -171,6 +175,8 @@ INT_PTR CALLBACK Settings_MuteDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM
       // With restore
       SetOption(hMuteOnLock, *settings, SettingsKey::MUTE_ON_LOCK);
       SetOption(hMuteOnScreenOff, *settings, SettingsKey::MUTE_ON_DISPLAYSTANDBY);
+      SetOption(hMuteOnLidClose, *settings, SettingsKey::MUTE_ON_LIDCLOSE);
+      
       SetOption(hMuteOnRDP, *settings, SettingsKey::MUTE_ON_RDP);
       SetOption(hRestoreVolume, *settings, SettingsKey::RESTORE_AUDIO);
 
index 6acf7d3efc80a1fdf0549094dc43c5304e3b5df8..a35017932a0554baf94d50f662aa944bfac704a6 100644 (file)
@@ -35,6 +35,8 @@ POSSIBILITY OF SUCH DAMAGE.
 
 #include "WMSettings.h"
 
+#include <nlohmann/json.hpp>
+
 enum class UpdateCheckInterval : int {
    DISABLED = 0,
    ON_STARTUP = 1,
index 3959f5c615785273aab4e744b965c7415575a3ea..c4db1a41f4b20f88e96fb5c74ea4719eb3dc181b 100644 (file)
@@ -62,6 +62,9 @@ static const wchar_t* KeyToStr(SettingsKey key)
         case SettingsKey::MUTE_ON_DISPLAYSTANDBY:
             keyStr = L"MuteOnDisplayStandby";
             break;
+        case SettingsKey::MUTE_ON_LIDCLOSE:
+            keyStr = L"MuteOnLidClose";
+            break;
         case SettingsKey::MUTE_ON_RDP:
             keyStr = L"MuteOnRDP";
             break;
@@ -147,6 +150,8 @@ static DWORD GetDefaultSetting(SettingsKey key)
             return 1;
         case SettingsKey::MUTE_ON_DISPLAYSTANDBY:
             return 1;
+        case SettingsKey::MUTE_ON_LIDCLOSE:
+            return 0;
         case SettingsKey::MUTE_ON_RDP:
             return 0;
         case SettingsKey::RESTORE_AUDIO:
index 89ef259b07a2ed1995b15f1c4c40ee09ddf0a355..7b1a99d54cfd21e521854c91ff89dc8697c478ca 100644 (file)
@@ -36,80 +36,82 @@ POSSIBILITY OF SUCH DAMAGE.
 #include "common.h"
 
 enum MuteEndPointMode {
-   MUTE_ENDPOINT_MODE_INDIVIDUAL_ALLOW_LIST = 0,
-   MUTE_ENDPOINT_MODE_INDIVIDUAL_BLOCK_LIST = 1
+    MUTE_ENDPOINT_MODE_INDIVIDUAL_ALLOW_LIST = 0,
+    MUTE_ENDPOINT_MODE_INDIVIDUAL_BLOCK_LIST = 1
 };
 
 enum class SettingsKey {
-     SETTINGS_VERSION
-   , MUTE_ON_LOCK
-   , MUTE_ON_DISPLAYSTANDBY
-   , MUTE_ON_RDP
-   , RESTORE_AUDIO
-   , MUTE_ON_SUSPEND
-   , MUTE_ON_SHUTDOWN
-   , MUTE_ON_LOGOUT
-   , MUTE_ON_BLUETOOTH
-   , MUTE_ON_BLUETOOTH_DEVICELIST
-   , MUTE_ON_WLAN
-   , MUTE_ON_WLAN_ALLOWLIST
-   , MUTE_INDIVIDUAL_ENDPOINTS
-   // 1 = mute specific (allowlist), 2 = mute specific (blocklist)
-   , MUTE_INDIVIDUAL_ENDPOINTS_MODE
-   , MUTE_DELAY
-   , MUTE_TRY_PAUSE_MEDIA
-   , MUTE_TRY_RESUME_MEDIA
-   , QUIETHOURS_ENABLE
-   , QUIETHOURS_FORCEUNMUTE
-   , QUIETHOURS_NOTIFICATIONS
-   , QUIETHOURS_START_V0_DEPRECATED // Settings v0 to v1. Migrated to Subkey
-   , QUIETHOURS_END_V0_DEPRECATED   // Settings v0 to v1. Migrated to Subkey
-   , NOTIFICATIONS_ENABLED
-   , LOGGING_ENABLED
-   , APP_LANGUAGE
-   , CHECK_FOR_UPDATE
-   , CHECK_FOR_BETA_UPDATE
+    SETTINGS_VERSION,
+    MUTE_ON_LOCK,
+    MUTE_ON_DISPLAYSTANDBY,
+    MUTE_ON_LIDCLOSE,
+    MUTE_ON_RDP,
+    RESTORE_AUDIO,
+    MUTE_ON_SUSPEND,
+    MUTE_ON_SHUTDOWN,
+    MUTE_ON_LOGOUT,
+    MUTE_ON_BLUETOOTH,
+    MUTE_ON_BLUETOOTH_DEVICELIST,
+    MUTE_ON_WLAN,
+    MUTE_ON_WLAN_ALLOWLIST,
+    MUTE_INDIVIDUAL_ENDPOINTS,
+    // 1 = mute specific (allowlist), 2 = mute specific (blocklist)
+    MUTE_INDIVIDUAL_ENDPOINTS_MODE,
+    MUTE_DELAY,
+    MUTE_TRY_PAUSE_MEDIA,
+    MUTE_TRY_RESUME_MEDIA,
+    QUIETHOURS_ENABLE,
+    QUIETHOURS_FORCEUNMUTE,
+    QUIETHOURS_NOTIFICATIONS,
+    QUIETHOURS_START_V0_DEPRECATED,  // Settings v0 to v1. Migrated to Subkey
+    QUIETHOURS_END_V0_DEPRECATED,    // Settings v0 to v1. Migrated to Subkey
+    NOTIFICATIONS_ENABLED,
+    LOGGING_ENABLED,
+    APP_LANGUAGE,
+    CHECK_FOR_UPDATE,
+    CHECK_FOR_BETA_UPDATE
 };
 
 class WMSettings {
-public:
-   WMSettings();
-   ~WMSettings();
+   public:
+    WMSettings();
+    ~WMSettings();
 
-   WMSettings(const WMSettings&) = delete;
-   WMSettings& operator=(const WMSettings&) = delete;
+    WMSettings(const WMSettings&) = delete;
+    WMSettings& operator=(const WMSettings&) = delete;
 
-   bool Init();
-   void Unload() noexcept;
+    bool Init();
+    void Unload() noexcept;
 
-   bool IsAutostartEnabled();
-   void EnableAutostart(bool enable);
+    bool IsAutostartEnabled();
+    void EnableAutostart(bool enable);
 
-   bool StoreWifiNetworks(std::vector<std::wstring>& networks);
-   std::vector<std::wstring> GetWifiNetworks() const;
+    bool StoreWifiNetworks(std::vector<std::wstring>& networks);
+    std::vector<std::wstring> GetWifiNetworks() const;
 
-   bool StoreBluetoothDevices(std::vector<std::wstring>& networks);
-   std::vector<std::wstring> GetBluetoothDevices() const;
+    bool StoreBluetoothDevices(std::vector<std::wstring>& networks);
+    std::vector<std::wstring> GetBluetoothDevices() const;
 
-   bool StoreManagedAudioEndpoints(std::vector<std::wstring> &endpoints);
-   std::vector<std::wstring> GetManagedAudioEndpoints() const;
+    bool StoreManagedAudioEndpoints(std::vector<std::wstring>& endpoints);
+    std::vector<std::wstring> GetManagedAudioEndpoints() const;
 
-   bool StoreQuietHoursTimes(const std::vector<std::pair<DWORD, DWORD>> &times);
-   std::vector<std::pair<DWORD, DWORD>> GetQuietHoursTimes();
+    bool StoreQuietHoursTimes(
+        const std::vector<std::pair<DWORD, DWORD>>& times);
+    std::vector<std::pair<DWORD, DWORD>> GetQuietHoursTimes();
 
-   DWORD QueryValue(SettingsKey key) const;
-   bool  SetValue(SettingsKey key, DWORD value);
+    DWORD QueryValue(SettingsKey key) const;
+    bool SetValue(SettingsKey key, DWORD value);
 
-   std::optional<std::wstring> QueryStrValue(SettingsKey key) const;
-   bool SetValue(SettingsKey key, const std::wstring &value);
+    std::optional<std::wstring> QueryStrValue(SettingsKey key) const;
+    bool SetValue(SettingsKey key, const std::wstring& value);
 
-private:
-   HKEY hSettingsKey_ = nullptr;
-   HKEY hWifiKey_ = nullptr;
-   HKEY hBluetoothKey_ = nullptr;
-   HKEY hAudioEndpointsKey_ = nullptr;
-   HKEY hQuietHoursTimesKey_ = nullptr;
+   private:
+    HKEY hSettingsKey_ = nullptr;
+    HKEY hWifiKey_ = nullptr;
+    HKEY hBluetoothKey_ = nullptr;
+    HKEY hAudioEndpointsKey_ = nullptr;
+    HKEY hQuietHoursTimesKey_ = nullptr;
 
-   bool MigrateSettings();
-   HKEY OpenAutostartKey(REGSAM samDesired);
+    bool MigrateSettings();
+    HKEY OpenAutostartKey(REGSAM samDesired);
 };
index d391608126b7243a1c76075c79cbfc56a1b34cf5..8ece00a4cae1093eaebcc372aab48c91c12aabb3 100644 (file)
@@ -31,761 +31,856 @@ POSSIBILITY OF SUCH DAMAGE.
 -----------------------------------------------------------------------------
 */
 
-#include "common.h"
 #include "WinMute.h"
+
 #include "WinAudio.h"
+#include "common.h"
 
 extern HINSTANCE hglobInstance;
 extern INT_PTR CALLBACK AboutDlgProc(HWND, UINT, WPARAM, LPARAM);
 extern INT_PTR CALLBACK SettingsDlgProc(HWND, UINT, WPARAM, LPARAM);
 
-static const wchar_t *WINMUTE_CLASS_NAME = L"WinMute";
+static const wchar_t* WINMUTE_CLASS_NAME = L"WinMute";
 
-static const wchar_t *TERMINAL_SERVER_KEY
-   = L"SYSTEM\\CurrentControlSet\\Control\\Terminal Server\\";
-static const wchar_t* GLASS_SESSION_ID
-   = L"GlassSessionId";
+static const wchar_t* TERMINAL_SERVER_KEY =
+    L"SYSTEM\\CurrentControlSet\\Control\\Terminal Server\\";
+static const wchar_t* GLASS_SESSION_ID = L"GlassSessionId";
 
-static LRESULT CALLBACK WinMuteWndProc(
-   HWND hWnd,
-   UINT msg,
-   WPARAM wParam,
-   LPARAM lParam)
+static LRESULT CALLBACK WinMuteWndProc(HWND hWnd, UINT msg, WPARAM wParam,
+                                       LPARAM lParam)
 {
-   auto wm = reinterpret_cast<WinMute*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
-   switch (msg) {
-   case WM_NCCREATE: {
-      LPCREATESTRUCTW cs = reinterpret_cast<LPCREATESTRUCTW>(lParam);
-      SetWindowLongPtrW(hWnd, GWLP_USERDATA,
-         reinterpret_cast<LONG_PTR>(cs->lpCreateParams));
-      return TRUE;
-   }
-   default:
-      break;
-   }
-   return (wm)
-      ? wm->WindowProc(hWnd, msg, wParam, lParam)
-      : DefWindowProcW(hWnd, msg, wParam, lParam);
+    auto wm = reinterpret_cast<WinMute*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
+    switch (msg) {
+        case WM_NCCREATE: {
+            LPCREATESTRUCTW cs = reinterpret_cast<LPCREATESTRUCTW>(lParam);
+            SetWindowLongPtrW(hWnd, GWLP_USERDATA,
+                              reinterpret_cast<LONG_PTR>(cs->lpCreateParams));
+            return TRUE;
+        }
+        default:
+            break;
+    }
+    return (wm) ? wm->WindowProc(hWnd, msg, wParam, lParam)
+                : DefWindowProcW(hWnd, msg, wParam, lParam);
 }
 
 static bool IsCurrentSessionRemoteable() noexcept
 {
-   bool isRemoteable = false;
-
-   if (GetSystemMetrics(SM_REMOTESESSION)) {
-      isRemoteable = true;
-   } else {
-      HKEY hRegKey = nullptr;
-      LONG lResult;
-
-      lResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, TERMINAL_SERVER_KEY, 0, KEY_READ, &hRegKey);
-      if (lResult == ERROR_SUCCESS) {
-         DWORD dwGlassSessionId = 0;
-         DWORD cbGlassSessionId = sizeof(dwGlassSessionId);
-         DWORD dwType;
-
-         lResult = RegQueryValueExW(hRegKey, GLASS_SESSION_ID, nullptr, &dwType,
-            reinterpret_cast<BYTE*>(&dwGlassSessionId),
-            &cbGlassSessionId);
-
-         if (lResult == ERROR_SUCCESS
-             && dwType == REG_DWORD
-             && cbGlassSessionId == sizeof(dwGlassSessionId)) {
-            DWORD dwCurrentSessionId;
-            if (ProcessIdToSessionId(GetCurrentProcessId(), &dwCurrentSessionId)) {
-               isRemoteable = (dwCurrentSessionId != dwGlassSessionId);
+    bool isRemoteable = false;
+
+    if (GetSystemMetrics(SM_REMOTESESSION)) {
+        isRemoteable = true;
+    } else {
+        HKEY hRegKey = nullptr;
+        LONG lResult;
+
+        lResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, TERMINAL_SERVER_KEY, 0,
+                                KEY_READ, &hRegKey);
+        if (lResult == ERROR_SUCCESS) {
+            DWORD dwGlassSessionId = 0;
+            DWORD cbGlassSessionId = sizeof(dwGlassSessionId);
+            DWORD dwType;
+
+            lResult = RegQueryValueExW(
+                hRegKey, GLASS_SESSION_ID, nullptr, &dwType,
+                reinterpret_cast<BYTE*>(&dwGlassSessionId), &cbGlassSessionId);
+
+            if (lResult == ERROR_SUCCESS && dwType == REG_DWORD &&
+                cbGlassSessionId == sizeof(dwGlassSessionId))
+            {
+                DWORD dwCurrentSessionId;
+                if (ProcessIdToSessionId(GetCurrentProcessId(),
+                                         &dwCurrentSessionId))
+                {
+                    isRemoteable = (dwCurrentSessionId != dwGlassSessionId);
+                }
             }
-         }
-         RegCloseKey(hRegKey);
-      }
-   }
+            RegCloseKey(hRegKey);
+        }
+    }
 
-   return isRemoteable;
+    return isRemoteable;
 }
 
-
 WinMute::MuteConfig::MuteConfig()
-   : muteOnWlan(false), muteOnBluetooth(false), showNotifications(false)
+    : muteOnWlan(false), muteOnBluetooth(false), showNotifications(false)
 {
 }
 
-WinMute::WinMute(WMSettings& settings) :
-   hWnd_(nullptr),
-   hTrayMenu_(nullptr),
-   hAppIcon_(nullptr),
-   hTrayIcon_(nullptr),
-   hUpdateIcon_(nullptr),
-   settings_(settings),
-   i18n_(WMi18n::GetInstance())
+WinMute::WinMute(WMSettings& settings)
+    : hWnd_(nullptr),
+      hTrayMenu_(nullptr),
+      hAppIcon_(nullptr),
+      hTrayIcon_(nullptr),
+      hUpdateIcon_(nullptr),
+      settings_(settings),
+      i18n_(WMi18n::GetInstance())
 {
 }
 
 WinMute::~WinMute() noexcept
 {
-   Unload();
+    Unload();
 }
 
 bool WinMute::RegisterWindowClass()
 {
-   WNDCLASSEX wc = { 0 };
-   wc.cbSize = sizeof(wc);
-   wc.hIcon = LoadIcon(hglobInstance, MAKEINTRESOURCE(IDI_APP));
-   // System color index brush: no GDI object to leak, tracks theme changes
-   wc.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_BTNFACE + 1);
-   wc.hInstance = hglobInstance;
-   wc.lpfnWndProc = WinMuteWndProc;
-   wc.lpszClassName = WINMUTE_CLASS_NAME;
-
-   if (!RegisterClassExW(&wc)) {
-      ShowWindowsError(L"RegisterClass");
-      return false;
-   }
-   return true;
+    WNDCLASSEX wc = {0};
+    wc.cbSize = sizeof(wc);
+    wc.hIcon = LoadIcon(hglobInstance, MAKEINTRESOURCE(IDI_APP));
+    // System color index brush: no GDI object to leak, tracks theme changes
+    wc.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_BTNFACE + 1);
+    wc.hInstance = hglobInstance;
+    wc.lpfnWndProc = WinMuteWndProc;
+    wc.lpszClassName = WINMUTE_CLASS_NAME;
+
+    if (!RegisterClassExW(&wc)) {
+        ShowWindowsError(L"RegisterClass");
+        return false;
+    }
+    return true;
 }
 
 bool WinMute::InitWindow()
 {
-   hWnd_ = CreateWindowExW(WS_EX_TOOLWINDOW, WINMUTE_CLASS_NAME, PROGRAM_NAME,
-      WS_POPUP, 0, 0, 0, 0, nullptr, 0, hglobInstance, this);
-   if (hWnd_ == nullptr) {
-      ShowWindowsError(L"CreateWindowEx");
-      return false;
-   }
-   return true;
+    hWnd_ =
+        CreateWindowExW(WS_EX_TOOLWINDOW, WINMUTE_CLASS_NAME, PROGRAM_NAME,
+                        WS_POPUP, 0, 0, 0, 0, nullptr, 0, hglobInstance, this);
+    if (hWnd_ == nullptr) {
+        ShowWindowsError(L"CreateWindowEx");
+        return false;
+    }
+    return true;
 }
 
 bool WinMute::InitAudio()
 {
-   if (IsWindowsVistaOrGreater()) {
-      // Nothing to do
-   } else if (IsWindowsXPOrGreater()) {
-      TaskDialog(
-         nullptr, nullptr,
-         PROGRAM_NAME,
-         i18n_.GetTranslationW("init.error.winmute.platform-support.title").c_str(),
-         i18n_.GetTranslationW("init.error.winmute.platform-support.text").c_str(),
-         TDCBF_OK_BUTTON, TD_ERROR_ICON, nullptr);
-      return false;
-   }
-
-   if (!muteCtrl_.Init(hWnd_, &wmTray_)) {
-      return false;
-   }
-
-   return true;
+    if (IsWindowsVistaOrGreater()) {
+        // Nothing to do
+    } else if (IsWindowsXPOrGreater()) {
+        TaskDialog(
+            nullptr, nullptr, PROGRAM_NAME,
+            i18n_.GetTranslationW("init.error.winmute.platform-support.title")
+                .c_str(),
+            i18n_.GetTranslationW("init.error.winmute.platform-support.text")
+                .c_str(),
+            TDCBF_OK_BUTTON, TD_ERROR_ICON, nullptr);
+        return false;
+    }
+
+    if (!muteCtrl_.Init(hWnd_, &wmTray_)) {
+        return false;
+    }
+
+    return true;
 }
 
-#define CHECK_MENU_ITEM(id, cond) \
-   (CheckMenuItem(hTrayMenu_, ID_TRAYMENU_ ## id, \
-                  (cond) ? MF_CHECKED : MF_UNCHECKED) != -1)
+#define CHECK_MENU_ITEM(id, cond)                \
+    (CheckMenuItem(hTrayMenu_, ID_TRAYMENU_##id, \
+                   (cond) ? MF_CHECKED : MF_UNCHECKED) != -1)
 bool WinMute::InitTrayMenu()
 {
-   if (hTrayMenu_ == nullptr) {
-      hTrayMenu_ = LoadMenuW(hglobInstance, MAKEINTRESOURCE(IDR_TRAYMENU));
-      if (hTrayMenu_ == nullptr) {
-         ShowWindowsError(L"LoadMenu");
-         return false;
-      }
-   }
-
-   if (!CHECK_MENU_ITEM(MUTEONLOCK, muteCtrl_.GetMuteOnWorkstationLock()) ||
-       !CHECK_MENU_ITEM(RESTOREAUDIO, muteCtrl_.GetRestoreVolume()) ||
-       !CHECK_MENU_ITEM(MUTEONSUSPEND, muteCtrl_.GetMuteOnSuspend()) ||
-       !CHECK_MENU_ITEM(MUTEONSHUTDOWN, muteCtrl_.GetMuteOnShutdown()) ||
-       !CHECK_MENU_ITEM(MUTEONLOGOUT, muteCtrl_.GetMuteOnLogout())) {
-      return false;
-   }
-
-   LoadMainMenuText();
-   return true;
+    if (hTrayMenu_ == nullptr) {
+        hTrayMenu_ = LoadMenuW(hglobInstance, MAKEINTRESOURCE(IDR_TRAYMENU));
+        if (hTrayMenu_ == nullptr) {
+            ShowWindowsError(L"LoadMenu");
+            return false;
+        }
+    }
+
+    if (!CHECK_MENU_ITEM(MUTEONLOCK, muteCtrl_.GetMuteOnWorkstationLock()) ||
+        !CHECK_MENU_ITEM(RESTOREAUDIO, muteCtrl_.GetRestoreVolume()) ||
+        !CHECK_MENU_ITEM(MUTEONSUSPEND, muteCtrl_.GetMuteOnSuspend()) ||
+        !CHECK_MENU_ITEM(MUTEONSHUTDOWN, muteCtrl_.GetMuteOnShutdown()) ||
+        !CHECK_MENU_ITEM(MUTEONLOGOUT, muteCtrl_.GetMuteOnLogout()))
+    {
+        return false;
+    }
+
+    LoadMainMenuText();
+    return true;
 }
 #undef CHECK_MENU_ITEM
 
 bool WinMute::Init()
 {
-   WMLog& log = WMLog::GetInstance();
+    WMLog& log = WMLog::GetInstance();
 
-   hAppIcon_ = LoadIconW(hglobInstance, MAKEINTRESOURCE(IDI_APP));
+    hAppIcon_ = LoadIconW(hglobInstance, MAKEINTRESOURCE(IDI_APP));
 
 #ifdef _DEBUG
-   WMLog::GetInstance().EnableLogFile(true);
+    WMLog::GetInstance().EnableLogFile(true);
 #else
-   WMLog::GetInstance().EnableLogFile(settings_.QueryValue(SettingsKey::LOGGING_ENABLED));
+    WMLog::GetInstance().EnableLogFile(
+        settings_.QueryValue(SettingsKey::LOGGING_ENABLED));
 #endif
-   log.LogInfo(L"Starting new session...");
-
-   if (!RegisterWindowClass() || !InitWindow()) {
-      return false;
-   }
-
-   if (!InitAudio()) {
-      return false;
-   }
-
-   if (!LoadSettings()) {
-      return false;
-   }
-
-   if (!InitTrayMenu()) {
-      return false;
-   }
-
-   if (!WTSRegisterSessionNotification(hWnd_, NOTIFY_FOR_THIS_SESSION)) {
-      const DWORD lastError = GetLastError();
-      ShowWindowsError(L"WTSRegisterSessionNotification");
-      log.LogWinError(L"WTSRegisterSessionNotification", lastError);
-      return false;
-   }
-   wtsSessionNotificationRegistered_ = true;
-
-   hPowerNotify_ = RegisterPowerSettingNotification(
-      hWnd_, &GUID_CONSOLE_DISPLAY_STATE, DEVICE_NOTIFY_WINDOW_HANDLE);
-   if (hPowerNotify_ == nullptr) {
-      const DWORD lastError = GetLastError();
-      ShowWindowsError(L"RegisterPowerSettingNotification", lastError);
-      log.LogWinError(L"RegisterPowerSettingNotification", lastError);
-      return false;
-   }
-
-   hTrayIcon_ = LoadIconW(hglobInstance, MAKEINTRESOURCE(IDI_APP));
-   if (hTrayIcon_ == nullptr) {
-      ShowWindowsError(L"LoadIcon");
-      return false;
-   }
-   hUpdateIcon_ = LoadIconW(hglobInstance, MAKEINTRESOURCE(IDI_APPUPDATE));
-   if (hUpdateIcon_ == nullptr) {
-      ShowWindowsError(L"LoadIcon");
-      return false;
-   }
-   wmTray_.Init(hWnd_, 0, hTrayIcon_, L"WinMute", true);
-   updateTray_.Init(hWnd_, 1, hUpdateIcon_, L"WinMute Update", false, WM_WINMUTE_UPDATE_POPUP);
-
-   quietHours_.Init(hWnd_, settings_);
-
-   log.LogInfo(L"WinMute initialized");
-
-   if (settings_.QueryValue(SettingsKey::MUTE_ON_RDP)
-       && IsCurrentSessionRemoteable()) {
-      wmTray_.ShowPopup(
-         i18n_.GetTranslationW("popup.remote-session-detected.title"),
-         i18n_.GetTranslationW("popup.remote-session-detected.text"));
-      muteCtrl_.SetMute(true);
-   }
-
-   CheckForUpdates();
-
-   return true;
+    log.LogInfo(L"Starting new session...");
+
+    if (!RegisterWindowClass() || !InitWindow()) {
+        return false;
+    }
+
+    if (!InitAudio()) {
+        return false;
+    }
+
+    if (!LoadSettings()) {
+        return false;
+    }
+
+    if (!InitTrayMenu()) {
+        return false;
+    }
+
+    if (!WTSRegisterSessionNotification(hWnd_, NOTIFY_FOR_THIS_SESSION)) {
+        const DWORD lastError = GetLastError();
+        ShowWindowsError(L"WTSRegisterSessionNotification");
+        log.LogWinError(L"WTSRegisterSessionNotification", lastError);
+        return false;
+    }
+    wtsSessionNotificationRegistered_ = true;
+
+    hPowerNotify_ = RegisterPowerSettingNotification(
+        hWnd_, &GUID_CONSOLE_DISPLAY_STATE, DEVICE_NOTIFY_WINDOW_HANDLE);
+    if (hPowerNotify_ == nullptr) {
+        const DWORD lastError = GetLastError();
+        ShowWindowsError(L"RegisterPowerSettingNotification", lastError);
+        log.LogWinError(L"RegisterPowerSettingNotification", lastError);
+        return false;
+    }
+
+    hLidCloseNotify_ = RegisterPowerSettingNotification(
+        hWnd_, &GUID_LIDSWITCH_STATE_CHANGE, DEVICE_NOTIFY_WINDOW_HANDLE);
+    if (hLidCloseNotify_ == nullptr) {
+        const DWORD lastError = GetLastError();
+        ShowWindowsError(L"RegisterPowerSettingNotification", lastError);
+        log.LogWinError(L"RegisterPowerSettingNotification", lastError);
+        UnregisterPowerSettingNotification(hPowerNotify_);
+        return false;
+    }
+
+    hTrayIcon_ = LoadIconW(hglobInstance, MAKEINTRESOURCE(IDI_APP));
+    if (hTrayIcon_ == nullptr) {
+        ShowWindowsError(L"LoadIcon");
+        return false;
+    }
+    hUpdateIcon_ = LoadIconW(hglobInstance, MAKEINTRESOURCE(IDI_APPUPDATE));
+    if (hUpdateIcon_ == nullptr) {
+        ShowWindowsError(L"LoadIcon");
+        return false;
+    }
+    wmTray_.Init(hWnd_, 0, hTrayIcon_, L"WinMute", true);
+    updateTray_.Init(hWnd_, 1, hUpdateIcon_, L"WinMute Update", false,
+                     WM_WINMUTE_UPDATE_POPUP);
+
+    quietHours_.Init(hWnd_, settings_);
+
+    log.LogInfo(L"WinMute initialized");
+
+    if (settings_.QueryValue(SettingsKey::MUTE_ON_RDP) &&
+        IsCurrentSessionRemoteable())
+    {
+        wmTray_.ShowPopup(
+            i18n_.GetTranslationW("popup.remote-session-detected.title"),
+            i18n_.GetTranslationW("popup.remote-session-detected.text"));
+        muteCtrl_.SetMute(true);
+    }
+
+    CheckForUpdates();
+
+    return true;
 }
 
 bool WinMute::LoadSettings()
 {
-   WMLog& log = WMLog::GetInstance();
-
-   if (log.IsLogFileEnabled()) {
-      std::wstring versionNumber;
-      GetWinMuteVersion(versionNumber);
-      log.LogInfo(L"Starting WinMute {}", versionNumber);
-      log.LogInfo(L"Loading settings:");
-      log.LogInfo(L"Check for updates: {}", settings_.QueryValue(SettingsKey::CHECK_FOR_UPDATE) ? L"Yes" : L"No");
-      log.LogInfo(L"\tCheck for beta updates: {}", settings_.QueryValue(SettingsKey::CHECK_FOR_BETA_UPDATE) ? L"Yes" : L"No");
-      log.LogInfo(L"\tRestore volume: {}", settings_.QueryValue(SettingsKey::RESTORE_AUDIO) ? L"Yes" : L"No");
-      log.LogInfo(L"\tMute delay: {}", settings_.QueryValue(SettingsKey::MUTE_DELAY));
-      log.LogInfo(L"\tMute on lock: {}", settings_.QueryValue(SettingsKey::MUTE_ON_LOCK) ? L"Yes" : L"No");
-      log.LogInfo(L"\tMute on display standby: {}", settings_.QueryValue(SettingsKey::MUTE_ON_DISPLAYSTANDBY) ? L"Yes" : L"No");
-      log.LogInfo(L"\tMute on logout: {}", settings_.QueryValue(SettingsKey::MUTE_ON_LOGOUT) ? L"Yes" : L"No");
-      log.LogInfo(L"\tMute on suspend: {}", settings_.QueryValue(SettingsKey::MUTE_ON_SUSPEND) ? L"Yes" : L"No");
-      log.LogInfo(L"\tMute on shutdown: {}", settings_.QueryValue(SettingsKey::MUTE_ON_SHUTDOWN) ? L"Yes" : L"No");
-      log.LogInfo(L"\tShow notifications: {}", settings_.QueryValue(SettingsKey::NOTIFICATIONS_ENABLED) ? L"Yes" : L"No");
-      log.LogInfo(L"\tMute on bluetooth: {}", settings_.QueryValue(SettingsKey::MUTE_ON_BLUETOOTH) ? L"Yes" : L"No");
-      log.LogInfo(L"\tTry pausing media when muting: {}", settings_.QueryValue(SettingsKey::MUTE_TRY_PAUSE_MEDIA) ? L"Yes" : L"No");
-      log.LogInfo(L"\tTry resuming media when unmuting: {}", settings_.QueryValue(SettingsKey::MUTE_TRY_RESUME_MEDIA) ? L"Yes" : L"No");
-      log.LogInfo(L"\t\tUse devicelist: {}", settings_.QueryValue(SettingsKey::MUTE_ON_BLUETOOTH_DEVICELIST) ? L"Yes" : L"No");
-      log.LogInfo(L"\tMute on WLAN: {}", settings_.QueryValue(SettingsKey::MUTE_ON_WLAN) ? L"Yes" : L"No");
-      log.LogInfo(L"\t\tUse allowlist: {}", settings_.QueryValue(SettingsKey::MUTE_ON_WLAN_ALLOWLIST) ? L"Yes" : L"No");
-      log.LogInfo(L"\tMute specific endpoints only: {}", settings_.QueryValue(SettingsKey::MUTE_INDIVIDUAL_ENDPOINTS) ? L"Yes" : L"No");
-   }
-
-   if (!settings_.QueryValue(SettingsKey::MUTE_INDIVIDUAL_ENDPOINTS)) {
-      muteCtrl_.ClearManagedEndpoints();
-   } else {
-      const auto endpoints = settings_.GetManagedAudioEndpoints();
-      const bool isAllowList = settings_.QueryValue(SettingsKey::MUTE_INDIVIDUAL_ENDPOINTS_MODE) == MUTE_ENDPOINT_MODE_INDIVIDUAL_ALLOW_LIST;
-      muteCtrl_.SetManagedEndpoints(endpoints, isAllowList);
-   }
-   muteCtrl_.SetMuteDelay(settings_.QueryValue(SettingsKey::MUTE_DELAY));
-   muteCtrl_.SetRestoreVolume(settings_.QueryValue(SettingsKey::RESTORE_AUDIO));
-   muteCtrl_.SetMuteOnWorkstationLock(settings_.QueryValue(SettingsKey::MUTE_ON_LOCK));
-   muteCtrl_.SetMuteOnDisplayStandby(settings_.QueryValue(SettingsKey::MUTE_ON_DISPLAYSTANDBY));
-   muteCtrl_.SetMuteOnLogout(settings_.QueryValue(SettingsKey::MUTE_ON_LOGOUT));
-   muteCtrl_.SetMuteOnSuspend(settings_.QueryValue(SettingsKey::MUTE_ON_SUSPEND));
-   muteCtrl_.SetMuteOnShutdown(settings_.QueryValue(SettingsKey::MUTE_ON_SHUTDOWN));
-   muteCtrl_.SetMuteTryPauseMedia(settings_.QueryValue(SettingsKey::MUTE_TRY_PAUSE_MEDIA));
-   muteCtrl_.SetMuteTryResumeMedia(settings_.QueryValue(SettingsKey::MUTE_TRY_RESUME_MEDIA));
-
-   muteCtrl_.SetNotifications(settings_.QueryValue(SettingsKey::NOTIFICATIONS_ENABLED));
-
-   muteConfig_.showNotifications = settings_.QueryValue(SettingsKey::NOTIFICATIONS_ENABLED);
-
-   muteConfig_.muteOnBluetooth = settings_.QueryValue(SettingsKey::MUTE_ON_BLUETOOTH);
-   if (!muteConfig_.muteOnBluetooth) {
-      muteCtrl_.SetMuteOnBluetoothDisconnect(false);
-      btDetector_.Unload();
-   } else {
-      if (!btDetector_.Init(hWnd_)) {
-         wmTray_.ShowPopup(
-            i18n_.GetTranslationW("popup.bluetooth-muting-disabled.title"),
-            i18n_.GetTranslationW("popup.bluetooth-muting-disabled.text"));
-         settings_.SetValue(SettingsKey::MUTE_ON_BLUETOOTH, FALSE);
-      } else {
-         muteCtrl_.SetMuteOnBluetoothDisconnect(true);
-         const bool muteOnWithDeviceList = settings_.QueryValue(SettingsKey::MUTE_ON_BLUETOOTH_DEVICELIST);
-         btDetector_.SetDeviceList(settings_.GetBluetoothDevices(), muteOnWithDeviceList);
-      }
-   }
-
-   muteConfig_.muteOnWlan = settings_.QueryValue(SettingsKey::MUTE_ON_WLAN);
-   if (!muteConfig_.muteOnWlan) {
-      wifiDetector_.Unload();
-   } else {
-      if (!wifiDetector_.Init(hWnd_)) {
-         wmTray_.ShowPopup(
-            i18n_.GetTranslationW("popup.wlan-muting-disabled.title"),
-            i18n_.GetTranslationW("popup.wlan-muting-disabled.text"));
-         settings_.SetValue(SettingsKey::MUTE_ON_WLAN, FALSE);
-      } else {
-         const bool isMuteList = !settings_.QueryValue(SettingsKey::MUTE_ON_WLAN_ALLOWLIST);
-         wifiDetector_.SetNetworkList(settings_.GetWifiNetworks(), isMuteList);
-         wifiDetector_.CheckNetwork();
-      }
-   }
-
-   //GUID_MONITOR_POWER_ON
-   return true;
+    WMLog& log = WMLog::GetInstance();
+
+    if (log.IsLogFileEnabled()) {
+        std::wstring versionNumber;
+        GetWinMuteVersion(versionNumber);
+        log.LogInfo(L"Starting WinMute {}", versionNumber);
+        log.LogInfo(L"Loading settings:");
+        log.LogInfo(L"Check for updates: {}",
+                    settings_.QueryValue(SettingsKey::CHECK_FOR_UPDATE)
+                        ? L"Yes"
+                        : L"No");
+        log.LogInfo(L"\tCheck for beta updates: {}",
+                    settings_.QueryValue(SettingsKey::CHECK_FOR_BETA_UPDATE)
+                        ? L"Yes"
+                        : L"No");
+        log.LogInfo(
+            L"\tRestore volume: {}",
+            settings_.QueryValue(SettingsKey::RESTORE_AUDIO) ? L"Yes" : L"No");
+        log.LogInfo(L"\tMute delay: {}",
+                    settings_.QueryValue(SettingsKey::MUTE_DELAY));
+        log.LogInfo(
+            L"\tMute on lock: {}",
+            settings_.QueryValue(SettingsKey::MUTE_ON_LOCK) ? L"Yes" : L"No");
+        log.LogInfo(L"\tMute on display standby: {}",
+                    settings_.QueryValue(SettingsKey::MUTE_ON_DISPLAYSTANDBY)
+                        ? L"Yes"
+                        : L"No");
+        log.LogInfo(
+            L"\tMute on logout: {}",
+            settings_.QueryValue(SettingsKey::MUTE_ON_LOGOUT) ? L"Yes" : L"No");
+        log.LogInfo(L"\tMute on suspend: {}",
+                    settings_.QueryValue(SettingsKey::MUTE_ON_SUSPEND) ? L"Yes"
+                                                                       : L"No");
+        log.LogInfo(L"\tMute on shutdown: {}",
+                    settings_.QueryValue(SettingsKey::MUTE_ON_SHUTDOWN)
+                        ? L"Yes"
+                        : L"No");
+        log.LogInfo(L"\tShow notifications: {}",
+                    settings_.QueryValue(SettingsKey::NOTIFICATIONS_ENABLED)
+                        ? L"Yes"
+                        : L"No");
+        log.LogInfo(L"\tMute on bluetooth: {}",
+                    settings_.QueryValue(SettingsKey::MUTE_ON_BLUETOOTH)
+                        ? L"Yes"
+                        : L"No");
+        log.LogInfo(L"\tTry pausing media when muting: {}",
+                    settings_.QueryValue(SettingsKey::MUTE_TRY_PAUSE_MEDIA)
+                        ? L"Yes"
+                        : L"No");
+        log.LogInfo(L"\tTry resuming media when unmuting: {}",
+                    settings_.QueryValue(SettingsKey::MUTE_TRY_RESUME_MEDIA)
+                        ? L"Yes"
+                        : L"No");
+        log.LogInfo(
+            L"\t\tUse devicelist: {}",
+            settings_.QueryValue(SettingsKey::MUTE_ON_BLUETOOTH_DEVICELIST)
+                ? L"Yes"
+                : L"No");
+        log.LogInfo(
+            L"\tMute on WLAN: {}",
+            settings_.QueryValue(SettingsKey::MUTE_ON_WLAN) ? L"Yes" : L"No");
+        log.LogInfo(L"\t\tUse allowlist: {}",
+                    settings_.QueryValue(SettingsKey::MUTE_ON_WLAN_ALLOWLIST)
+                        ? L"Yes"
+                        : L"No");
+        log.LogInfo(L"\tMute specific endpoints only: {}",
+                    settings_.QueryValue(SettingsKey::MUTE_INDIVIDUAL_ENDPOINTS)
+                        ? L"Yes"
+                        : L"No");
+    }
+
+    if (!settings_.QueryValue(SettingsKey::MUTE_INDIVIDUAL_ENDPOINTS)) {
+        muteCtrl_.ClearManagedEndpoints();
+    } else {
+        const auto endpoints = settings_.GetManagedAudioEndpoints();
+        const bool isAllowList =
+            settings_.QueryValue(SettingsKey::MUTE_INDIVIDUAL_ENDPOINTS_MODE) ==
+            MUTE_ENDPOINT_MODE_INDIVIDUAL_ALLOW_LIST;
+        muteCtrl_.SetManagedEndpoints(endpoints, isAllowList);
+    }
+    muteCtrl_.SetMuteDelay(settings_.QueryValue(SettingsKey::MUTE_DELAY));
+    muteCtrl_.SetRestoreVolume(
+        settings_.QueryValue(SettingsKey::RESTORE_AUDIO));
+    muteCtrl_.SetMuteOnWorkstationLock(
+        settings_.QueryValue(SettingsKey::MUTE_ON_LOCK));
+    muteCtrl_.SetMuteOnDisplayStandby(
+        settings_.QueryValue(SettingsKey::MUTE_ON_DISPLAYSTANDBY));
+    muteCtrl_.SetMuteOnLogout(
+        settings_.QueryValue(SettingsKey::MUTE_ON_LOGOUT));
+    muteCtrl_.SetMuteOnSuspend(
+        settings_.QueryValue(SettingsKey::MUTE_ON_SUSPEND));
+    muteCtrl_.SetMuteOnShutdown(
+        settings_.QueryValue(SettingsKey::MUTE_ON_SHUTDOWN));
+    muteCtrl_.SetMuteTryPauseMedia(
+        settings_.QueryValue(SettingsKey::MUTE_TRY_PAUSE_MEDIA));
+    muteCtrl_.SetMuteTryResumeMedia(
+        settings_.QueryValue(SettingsKey::MUTE_TRY_RESUME_MEDIA));
+
+    muteCtrl_.SetNotifications(
+        settings_.QueryValue(SettingsKey::NOTIFICATIONS_ENABLED));
+
+    muteConfig_.showNotifications =
+        settings_.QueryValue(SettingsKey::NOTIFICATIONS_ENABLED);
+
+    muteConfig_.muteOnBluetooth =
+        settings_.QueryValue(SettingsKey::MUTE_ON_BLUETOOTH);
+    if (!muteConfig_.muteOnBluetooth) {
+        muteCtrl_.SetMuteOnBluetoothDisconnect(false);
+        btDetector_.Unload();
+    } else {
+        if (!btDetector_.Init(hWnd_)) {
+            wmTray_.ShowPopup(
+                i18n_.GetTranslationW("popup.bluetooth-muting-disabled.title"),
+                i18n_.GetTranslationW("popup.bluetooth-muting-disabled.text"));
+            settings_.SetValue(SettingsKey::MUTE_ON_BLUETOOTH, FALSE);
+        } else {
+            muteCtrl_.SetMuteOnBluetoothDisconnect(true);
+            const bool muteOnWithDeviceList =
+                settings_.QueryValue(SettingsKey::MUTE_ON_BLUETOOTH_DEVICELIST);
+            btDetector_.SetDeviceList(settings_.GetBluetoothDevices(),
+                                      muteOnWithDeviceList);
+        }
+    }
+
+    muteConfig_.muteOnWlan = settings_.QueryValue(SettingsKey::MUTE_ON_WLAN);
+    if (!muteConfig_.muteOnWlan) {
+        wifiDetector_.Unload();
+    } else {
+        if (!wifiDetector_.Init(hWnd_)) {
+            wmTray_.ShowPopup(
+                i18n_.GetTranslationW("popup.wlan-muting-disabled.title"),
+                i18n_.GetTranslationW("popup.wlan-muting-disabled.text"));
+            settings_.SetValue(SettingsKey::MUTE_ON_WLAN, FALSE);
+        } else {
+            const bool isMuteList =
+                !settings_.QueryValue(SettingsKey::MUTE_ON_WLAN_ALLOWLIST);
+            wifiDetector_.SetNetworkList(settings_.GetWifiNetworks(),
+                                         isMuteList);
+            wifiDetector_.CheckNetwork();
+        }
+    }
+
+    // GUID_MONITOR_POWER_ON
+    return true;
 }
 
 void WinMute::ToggleMenuCheck(UINT item, bool* setting) noexcept
 {
-   UINT state = GetMenuState(hTrayMenu_, item, MF_BYCOMMAND);
-   if (state & MF_CHECKED) {
-      *setting = false;
-      CheckMenuItem(hTrayMenu_, item, MF_UNCHECKED);
-   } else {
-      *setting = true;
-      CheckMenuItem(hTrayMenu_, item, MF_CHECKED);
-   }
+    UINT state = GetMenuState(hTrayMenu_, item, MF_BYCOMMAND);
+    if (state & MF_CHECKED) {
+        *setting = false;
+        CheckMenuItem(hTrayMenu_, item, MF_UNCHECKED);
+    } else {
+        *setting = true;
+        CheckMenuItem(hTrayMenu_, item, MF_CHECKED);
+    }
 }
 
 void WinMute::LoadMainMenuText()
 {
-   std::map<UINT, std::wstring> menuText;
-   menuText[ID_TRAYMENU_INFO] = i18n_.GetTranslationW("traymenu.info");
-   menuText[ID_TRAYMENU_LABEL_MUTEWHEN] = i18n_.GetTranslationW("traymenu.mute-when");
-   menuText[ID_TRAYMENU_MUTEONLOCK] = i18n_.GetTranslationW("traymenu.mute-on-lock");
-   menuText[ID_TRAYMENU_MUTEONSCREENSUSPEND] = i18n_.GetTranslationW("traymenu.mute-on-screen-suspend");
-   menuText[ID_TRAYMENU_RESTOREAUDIO] = i18n_.GetTranslationW("traymenu.restore-volume");
-   menuText[ID_TRAYMENU_LABEL_MUTEON_NO_RESTORE] = i18n_.GetTranslationW("traymenu.mute-no-restore");
-   menuText[ID_TRAYMENU_MUTEONSHUTDOWN] = i18n_.GetTranslationW("traymenu.mute-on-shutdown");
-   menuText[ID_TRAYMENU_MUTEONSUSPEND] = i18n_.GetTranslationW("traymenu.mute-on-sleep");
-   menuText[ID_TRAYMENU_MUTEONLOGOUT] = i18n_.GetTranslationW("traymenu.mute-on-logout");
-   menuText[ID_TRAYMENU_MUTE] = i18n_.GetTranslationW("traymenu.mute-all-devices");
-   menuText[ID_TRAYMENU_SETTINGS] = i18n_.GetTranslationW("traymenu.settings");
-   menuText[ID_TRAYMENU_EXIT] = i18n_.GetTranslationW("traymenu.exit");
-
-   for (const auto& mt : menuText) {
-      MENUITEMINFO mii{ sizeof(MENUITEMINFO) };
-      if (!GetMenuItemInfo(hTrayMenu_, mt.first, false, &mii)) {
-         continue;
-      }
-      mii.fMask = MIIM_TYPE;
-      mii.fType = MFT_STRING;
-      mii.dwTypeData = const_cast<LPWSTR>(mt.second.c_str());
-      mii.cch = static_cast<UINT>(mt.second.length());
-      if (!SetMenuItemInfo(hTrayMenu_, mt.first, false, &mii)) {
-         continue;
-      }
-   }
+    std::map<UINT, std::wstring> menuText;
+    menuText[ID_TRAYMENU_INFO] = i18n_.GetTranslationW("traymenu.info");
+    menuText[ID_TRAYMENU_LABEL_MUTEWHEN] =
+        i18n_.GetTranslationW("traymenu.mute-when");
+    menuText[ID_TRAYMENU_MUTEONLOCK] =
+        i18n_.GetTranslationW("traymenu.mute-on-lock");
+    menuText[ID_TRAYMENU_MUTEONSCREENSUSPEND] =
+        i18n_.GetTranslationW("traymenu.mute-on-screen-suspend");
+    menuText[ID_TRAYMENU_RESTOREAUDIO] =
+        i18n_.GetTranslationW("traymenu.restore-volume");
+    menuText[ID_TRAYMENU_LABEL_MUTEON_NO_RESTORE] =
+        i18n_.GetTranslationW("traymenu.mute-no-restore");
+    menuText[ID_TRAYMENU_MUTEONSHUTDOWN] =
+        i18n_.GetTranslationW("traymenu.mute-on-shutdown");
+    menuText[ID_TRAYMENU_MUTEONSUSPEND] =
+        i18n_.GetTranslationW("traymenu.mute-on-sleep");
+    menuText[ID_TRAYMENU_MUTEONLOGOUT] =
+        i18n_.GetTranslationW("traymenu.mute-on-logout");
+    menuText[ID_TRAYMENU_MUTE] =
+        i18n_.GetTranslationW("traymenu.mute-all-devices");
+    menuText[ID_TRAYMENU_SETTINGS] = i18n_.GetTranslationW("traymenu.settings");
+    menuText[ID_TRAYMENU_EXIT] = i18n_.GetTranslationW("traymenu.exit");
+
+    for (const auto& mt : menuText) {
+        MENUITEMINFO mii{sizeof(MENUITEMINFO)};
+        if (!GetMenuItemInfo(hTrayMenu_, mt.first, false, &mii)) {
+            continue;
+        }
+        mii.fMask = MIIM_TYPE;
+        mii.fType = MFT_STRING;
+        mii.dwTypeData = const_cast<LPWSTR>(mt.second.c_str());
+        mii.cch = static_cast<UINT>(mt.second.length());
+        if (!SetMenuItemInfo(hTrayMenu_, mt.first, false, &mii)) {
+            continue;
+        }
+    }
 }
 
 void WinMute::CheckForUpdates()
 {
-   const UpdateChecker updateChecker;
-   if (!updateChecker.IsUpdateCheckEnabled(settings_)) {
-      return;
-   }
-   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_);
+    const UpdateChecker updateChecker;
+    if (!updateChecker.IsUpdateCheckEnabled(settings_)) {
+        return;
+    }
+    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(HWND hWnd)
 {
-   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();
-   }
+    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 (wParam == 0 || !updateInfo) {
-      wmTray_.ShowPopup(
-         i18n_.GetTranslationW("popup.error.update-check-failed.title"),
-         i18n_.GetTranslationW("popup.error.update-check-failed.text"));
-      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"),
-         updateInfo_.beta.version);
-      const std::wstring popupText = SafeVFormat(
-         i18n_.GetTranslationW("popup.update-available-beta.text"),
-         updateInfo_.currentVersion);
-      updateTray_.Show();
-      updateTray_.ShowPopup(popupTitle, popupText);
-   } else if (updateInfo_.stable.shouldUpdate) {
-      const std::wstring popupTitle = SafeVFormat(
-         i18n_.GetTranslationW("popup.update-available.title"),
-         updateInfo_.stable.version);
-      const std::wstring popupText = SafeVFormat(
-         i18n_.GetTranslationW("popup.update-available.text"),
-         updateInfo_.currentVersion);
-      updateTray_.Show();
-      updateTray_.ShowPopup(popupTitle, popupText);
-   }
-   return 0;
+    const std::unique_ptr<UpdateInfo> updateInfo{
+        reinterpret_cast<UpdateInfo*>(lParam)};
+    if (updateThread_.joinable()) {
+        updateThread_.join();
+    }
+    if (wParam == 0 || !updateInfo) {
+        wmTray_.ShowPopup(
+            i18n_.GetTranslationW("popup.error.update-check-failed.title"),
+            i18n_.GetTranslationW("popup.error.update-check-failed.text"));
+        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"),
+            updateInfo_.beta.version);
+        const std::wstring popupText = SafeVFormat(
+            i18n_.GetTranslationW("popup.update-available-beta.text"),
+            updateInfo_.currentVersion);
+        updateTray_.Show();
+        updateTray_.ShowPopup(popupTitle, popupText);
+    } else if (updateInfo_.stable.shouldUpdate) {
+        const std::wstring popupTitle =
+            SafeVFormat(i18n_.GetTranslationW("popup.update-available.title"),
+                        updateInfo_.stable.version);
+        const std::wstring popupText =
+            SafeVFormat(i18n_.GetTranslationW("popup.update-available.text"),
+                        updateInfo_.currentVersion);
+        updateTray_.Show();
+        updateTray_.ShowPopup(popupTitle, popupText);
+    }
+    return 0;
 }
 
 LRESULT WinMute::OnCommand(HWND hWnd, WPARAM wParam, LPARAM)
 {
-   switch (LOWORD(wParam)) {
-   case ID_TRAYMENU_INFO:
-   {
-      static bool dialogOpen = false;
-      if (!dialogOpen) {
-         dialogOpen = true;
-         DialogBox(
-            hglobInstance,
-            MAKEINTRESOURCE(IDD_ABOUT),
-            hWnd_,
-            AboutDlgProc);
-         dialogOpen = false;
-      }
-      break;
-   }
-   case ID_TRAYMENU_EXIT:
-      SendMessage(hWnd, WM_CLOSE, 0, 0);
-      break;
-   case ID_TRAYMENU_SETTINGS: {
-      static bool dialogOpen = false;
-      if (!dialogOpen) {
-         dialogOpen = true;
-         if (DialogBoxParamW(
-            hglobInstance,
-            MAKEINTRESOURCE(IDD_SETTINGS),
-            hWnd_,
-            SettingsDlgProc,
-            reinterpret_cast<LPARAM>(&settings_)) == 0) {
-            LoadSettings();
-            InitTrayMenu();
-            quietHours_.Reset(settings_);
-         }
-         dialogOpen = false;
-      }
-      break;
-   }
-   case ID_TRAYMENU_MUTE: {
-      bool state = false;
-      ToggleMenuCheck(ID_TRAYMENU_MUTE, &state);
-      muteCtrl_.SetMute(state);
-      break;
-   }
-   case ID_TRAYMENU_MUTEONLOCK: {
-      bool checked = false;
-      ToggleMenuCheck(ID_TRAYMENU_MUTEONLOCK, &checked);
-      muteCtrl_.SetMuteOnWorkstationLock(checked);
-      settings_.SetValue(SettingsKey::MUTE_ON_LOCK, checked);
-      break;
-   }
-   case ID_TRAYMENU_RESTOREAUDIO: {
-      bool checked = false;
-      ToggleMenuCheck(ID_TRAYMENU_RESTOREAUDIO, &checked);
-      muteCtrl_.SetRestoreVolume(checked);
-      settings_.SetValue(SettingsKey::RESTORE_AUDIO, checked);
-      break;
-   }
-   case ID_TRAYMENU_MUTEONSCREENSUSPEND: {
-      bool checked = false;
-      ToggleMenuCheck(ID_TRAYMENU_SCREENSUSPEND, &checked);
-      muteCtrl_.SetMuteOnDisplayStandby(checked);
-      settings_.SetValue(SettingsKey::MUTE_ON_DISPLAYSTANDBY, checked);
-      break;
-   }
-   case ID_TRAYMENU_MUTEONSHUTDOWN: {
-      bool checked = false;
-      ToggleMenuCheck(ID_TRAYMENU_MUTEONSHUTDOWN, &checked);
-      muteCtrl_.SetMuteOnShutdown(checked);
-      settings_.SetValue(SettingsKey::MUTE_ON_SHUTDOWN, checked);
-      break;
-   }
-   case ID_TRAYMENU_MUTEONSUSPEND: {
-      bool checked = false;
-      ToggleMenuCheck(ID_TRAYMENU_MUTEONSUSPEND, &checked);
-      muteCtrl_.SetMuteOnSuspend(checked);
-      settings_.SetValue(SettingsKey::MUTE_ON_SUSPEND, checked);
-      break;
-   }
-   case ID_TRAYMENU_MUTEONLOGOUT: {
-      bool checked = false;
-      ToggleMenuCheck(ID_TRAYMENU_MUTEONLOGOUT, &checked);
-      muteCtrl_.SetMuteOnLogout(checked);
-      settings_.SetValue(SettingsKey::MUTE_ON_LOGOUT, checked);
-      break;
-   }
-   default:
-      break;
-   }
-   return 0;
+    switch (LOWORD(wParam)) {
+        case ID_TRAYMENU_INFO: {
+            static bool dialogOpen = false;
+            if (!dialogOpen) {
+                dialogOpen = true;
+                DialogBox(hglobInstance, MAKEINTRESOURCE(IDD_ABOUT), hWnd_,
+                          AboutDlgProc);
+                dialogOpen = false;
+            }
+            break;
+        }
+        case ID_TRAYMENU_EXIT:
+            SendMessage(hWnd, WM_CLOSE, 0, 0);
+            break;
+        case ID_TRAYMENU_SETTINGS: {
+            static bool dialogOpen = false;
+            if (!dialogOpen) {
+                dialogOpen = true;
+                if (DialogBoxParamW(hglobInstance,
+                                    MAKEINTRESOURCE(IDD_SETTINGS), hWnd_,
+                                    SettingsDlgProc,
+                                    reinterpret_cast<LPARAM>(&settings_)) == 0)
+                {
+                    LoadSettings();
+                    InitTrayMenu();
+                    quietHours_.Reset(settings_);
+                }
+                dialogOpen = false;
+            }
+            break;
+        }
+        case ID_TRAYMENU_MUTE: {
+            bool state = false;
+            ToggleMenuCheck(ID_TRAYMENU_MUTE, &state);
+            muteCtrl_.SetMute(state);
+            break;
+        }
+        case ID_TRAYMENU_MUTEONLOCK: {
+            bool checked = false;
+            ToggleMenuCheck(ID_TRAYMENU_MUTEONLOCK, &checked);
+            muteCtrl_.SetMuteOnWorkstationLock(checked);
+            settings_.SetValue(SettingsKey::MUTE_ON_LOCK, checked);
+            break;
+        }
+        case ID_TRAYMENU_RESTOREAUDIO: {
+            bool checked = false;
+            ToggleMenuCheck(ID_TRAYMENU_RESTOREAUDIO, &checked);
+            muteCtrl_.SetRestoreVolume(checked);
+            settings_.SetValue(SettingsKey::RESTORE_AUDIO, checked);
+            break;
+        }
+        case ID_TRAYMENU_MUTEONSCREENSUSPEND: {
+            bool checked = false;
+            ToggleMenuCheck(ID_TRAYMENU_SCREENSUSPEND, &checked);
+            muteCtrl_.SetMuteOnDisplayStandby(checked);
+            settings_.SetValue(SettingsKey::MUTE_ON_DISPLAYSTANDBY, checked);
+            break;
+        }
+        case ID_TRAYMENU_MUTEONSHUTDOWN: {
+            bool checked = false;
+            ToggleMenuCheck(ID_TRAYMENU_MUTEONSHUTDOWN, &checked);
+            muteCtrl_.SetMuteOnShutdown(checked);
+            settings_.SetValue(SettingsKey::MUTE_ON_SHUTDOWN, checked);
+            break;
+        }
+        case ID_TRAYMENU_MUTEONSUSPEND: {
+            bool checked = false;
+            ToggleMenuCheck(ID_TRAYMENU_MUTEONSUSPEND, &checked);
+            muteCtrl_.SetMuteOnSuspend(checked);
+            settings_.SetValue(SettingsKey::MUTE_ON_SUSPEND, checked);
+            break;
+        }
+        case ID_TRAYMENU_MUTEONLOGOUT: {
+            bool checked = false;
+            ToggleMenuCheck(ID_TRAYMENU_MUTEONLOGOUT, &checked);
+            muteCtrl_.SetMuteOnLogout(checked);
+            settings_.SetValue(SettingsKey::MUTE_ON_LOGOUT, checked);
+            break;
+        }
+        default:
+            break;
+    }
+    return 0;
 }
 
 LRESULT WinMute::OnTrayIcon(HWND hWnd, WPARAM wParam, LPARAM lParam)
 {
-   // NOTIFYICON_VERSION_4 semantics: LOWORD(lParam) carries the event,
-   // HIWORD(lParam) the icon ID and wParam the anchor coordinates.
-   const UINT event = LOWORD(lParam);
-   if (event == WM_CONTEXTMENU ||
-       event == NIN_SELECT ||
-       event == NIN_KEYSELECT) {
-      const POINT p{ GET_X_LPARAM(wParam), GET_Y_LPARAM(wParam) };
-      SetForegroundWindow(hWnd);
-      TrackPopupMenuEx(
-         GetSubMenu(hTrayMenu_, 0),
-         TPM_NONOTIFY | TPM_TOPALIGN | TPM_LEFTALIGN,
-         p.x, p.y, hWnd_, nullptr);
-   }
-   return TRUE;
+    // NOTIFYICON_VERSION_4 semantics: LOWORD(lParam) carries the event,
+    // HIWORD(lParam) the icon ID and wParam the anchor coordinates.
+    const UINT event = LOWORD(lParam);
+    if (event == WM_CONTEXTMENU || event == NIN_SELECT ||
+        event == NIN_KEYSELECT)
+    {
+        const POINT p{GET_X_LPARAM(wParam), GET_Y_LPARAM(wParam)};
+        SetForegroundWindow(hWnd);
+        TrackPopupMenuEx(GetSubMenu(hTrayMenu_, 0),
+                         TPM_NONOTIFY | TPM_TOPALIGN | TPM_LEFTALIGN, p.x, p.y,
+                         hWnd_, nullptr);
+    }
+    return TRUE;
 }
 
 LRESULT WinMute::OnUpdatePopup(HWND hWnd, WPARAM, LPARAM lParam)
 {
-   // NOTIFYICON_VERSION_4 semantics: LOWORD(lParam) carries the event.
-   const UINT event = LOWORD(lParam);
-   if (event == NIN_BALLOONUSERCLICK) {
-      const bool betaUpdates = settings_.QueryValue(SettingsKey::CHECK_FOR_BETA_UPDATE) != 0;
-      if (betaUpdates && updateInfo_.beta.shouldUpdate) {
-         LaunchBrowser(hWnd, updateInfo_.beta.downloadUrl);
-      } else if (updateInfo_.stable.shouldUpdate) {
-         LaunchBrowser(hWnd, updateInfo_.stable.downloadUrl);
-      }
-   }
-   if (event == NIN_BALLOONHIDE || event == NIN_BALLOONTIMEOUT || event == NIN_BALLOONUSERCLICK) {
-      updateTray_.Hide();
-   }
-   return 0;
+    // NOTIFYICON_VERSION_4 semantics: LOWORD(lParam) carries the event.
+    const UINT event = LOWORD(lParam);
+    if (event == NIN_BALLOONUSERCLICK) {
+        const bool betaUpdates =
+            settings_.QueryValue(SettingsKey::CHECK_FOR_BETA_UPDATE) != 0;
+        if (betaUpdates && updateInfo_.beta.shouldUpdate) {
+            LaunchBrowser(hWnd, updateInfo_.beta.downloadUrl);
+        } else if (updateInfo_.stable.shouldUpdate) {
+            LaunchBrowser(hWnd, updateInfo_.stable.downloadUrl);
+        }
+    }
+    if (event == NIN_BALLOONHIDE || event == NIN_BALLOONTIMEOUT ||
+        event == NIN_BALLOONUSERCLICK)
+    {
+        updateTray_.Hide();
+    }
+    return 0;
 }
 
-
 LRESULT WinMute::OnSettingChange(HWND, WPARAM, LPARAM)
 {
-   return 0;
+    return 0;
 }
 
 LRESULT WinMute::OnPowerBroadcast(HWND, WPARAM wParam, LPARAM lParam)
 {
-   if (wParam == PBT_APMSUSPEND) {
-      muteCtrl_.NotifySuspend(true);
-   } else if (wParam == PBT_POWERSETTINGCHANGE) {
-      const PPOWERBROADCAST_SETTING bs =
-         reinterpret_cast<PPOWERBROADCAST_SETTING>(lParam);
-      if (IsEqualGUID(bs->PowerSetting, GUID_CONSOLE_DISPLAY_STATE)) {
-         const DWORD state = bs->Data[0];
-         if (state == 0x0) { // Display standby
-            muteCtrl_.NotifyDisplayStandby(true);
-         } else if (state == 0x1) { // Display on
-            muteCtrl_.NotifyDisplayStandby(false);
-         } else if (state == 0x2) { // Display dimmed
-         }
-      }
-   }
-   return TRUE;
+    if (wParam == PBT_APMSUSPEND) {
+        muteCtrl_.NotifySuspend(true);
+    } else if (wParam == PBT_POWERSETTINGCHANGE) {
+        const PPOWERBROADCAST_SETTING bs =
+            reinterpret_cast<PPOWERBROADCAST_SETTING>(lParam);
+        if (IsEqualGUID(bs->PowerSetting, GUID_CONSOLE_DISPLAY_STATE)) {
+            const DWORD state = bs->Data[0];
+            if (state == 0x0) {  // Display standby
+                muteCtrl_.NotifyDisplayStandby(true);
+            } else if (state == 0x1) {  // Display on
+                muteCtrl_.NotifyDisplayStandby(false);
+            } else if (state == 0x2) {  // Display dimmed
+            }
+        } else if (IsEqualGUID(bs->PowerSetting, GUID_LIDSWITCH_STATE_CHANGE)) {
+            const DWORD state = bs->Data[0];
+            if (state == 0x0) {  // Lid closed
+                muteCtrl_.NotifyLidClosed(true);
+            } else if (state == 0x1) {  // Lid open
+                muteCtrl_.NotifyLidClosed(true);
+            }
+        }
+    }
+    return TRUE;
 }
 
 LRESULT WinMute::OnQuietHours(HWND, UINT msg, WPARAM, LPARAM)
 {
-   if (msg == WM_WINMUTE_QUIETHOURS_START) {
-      muteCtrl_.NotifyQuietHours(true);
-      if (settings_.QueryValue(SettingsKey::QUIETHOURS_NOTIFICATIONS)) {
-         wmTray_.ShowPopup(
-            i18n_.GetTranslationW("popup.quiet-hours-started.title"),
-            i18n_.GetTranslationW("popup.quiet-hours-started.text"));
-      }
-      quietHours_.SetEnd();
-      return 0;
-   } else if (msg == WM_WINMUTE_QUIETHOURS_END) {
-      muteCtrl_.NotifyQuietHours(false);
-      if (settings_.QueryValue(SettingsKey::QUIETHOURS_NOTIFICATIONS)) {
-         wmTray_.ShowPopup(
-            i18n_.GetTranslationW("popup.quiet-hours-ended.title"),
-            i18n_.GetTranslationW("popup.quiet-hours-ended.text"));
-      }
-      if (settings_.QueryValue(SettingsKey::QUIETHOURS_FORCEUNMUTE)) {
-         muteCtrl_.SetMute(false);
-      }
-      quietHours_.SetStart();
-   }
-   return 0;
+    if (msg == WM_WINMUTE_QUIETHOURS_START) {
+        muteCtrl_.NotifyQuietHours(true);
+        if (settings_.QueryValue(SettingsKey::QUIETHOURS_NOTIFICATIONS)) {
+            wmTray_.ShowPopup(
+                i18n_.GetTranslationW("popup.quiet-hours-started.title"),
+                i18n_.GetTranslationW("popup.quiet-hours-started.text"));
+        }
+        quietHours_.SetEnd();
+        return 0;
+    } else if (msg == WM_WINMUTE_QUIETHOURS_END) {
+        muteCtrl_.NotifyQuietHours(false);
+        if (settings_.QueryValue(SettingsKey::QUIETHOURS_NOTIFICATIONS)) {
+            wmTray_.ShowPopup(
+                i18n_.GetTranslationW("popup.quiet-hours-ended.title"),
+                i18n_.GetTranslationW("popup.quiet-hours-ended.text"));
+        }
+        if (settings_.QueryValue(SettingsKey::QUIETHOURS_FORCEUNMUTE)) {
+            muteCtrl_.SetMute(false);
+        }
+        quietHours_.SetStart();
+    }
+    return 0;
 }
 
 LRESULT WinMute::OnAudioServiceShutdown(HWND hWnd, WPARAM, LPARAM)
 {
-   TaskDialog(
-      hWnd, hglobInstance, PROGRAM_NAME,
-      i18n_.GetTranslationW("general.error.audio-service-shutdown.title").c_str(),
-      i18n_.GetTranslationW("general.error.audio-service-shutdown.text").c_str(),
-      TDCBF_OK_BUTTON, TD_WARNING_ICON, nullptr);
-   return 0;
+    TaskDialog(
+        hWnd, hglobInstance, PROGRAM_NAME,
+        i18n_.GetTranslationW("general.error.audio-service-shutdown.title")
+            .c_str(),
+        i18n_.GetTranslationW("general.error.audio-service-shutdown.text")
+            .c_str(),
+        TDCBF_OK_BUTTON, TD_WARNING_ICON, nullptr);
+    return 0;
 }
 
 LRESULT WinMute::OnDeviceChange(HWND, UINT msg, WPARAM wParam, LPARAM lParam)
 {
-   if (muteConfig_.muteOnBluetooth) {
-      const auto btStatus = btDetector_.GetBluetoothStatus(msg, wParam, lParam);
-      if (btStatus == BluetoothDetector::BluetoothStatus::Connected) {
-         muteCtrl_.NotifyBluetoothConnected(true);
-      } else if (btStatus == BluetoothDetector::BluetoothStatus::Disconnected) {
-         muteCtrl_.NotifyBluetoothConnected(false);
-      }
-   }
-   return TRUE;
+    if (muteConfig_.muteOnBluetooth) {
+        const auto btStatus =
+            btDetector_.GetBluetoothStatus(msg, wParam, lParam);
+        if (btStatus == BluetoothDetector::BluetoothStatus::Connected) {
+            muteCtrl_.NotifyBluetoothConnected(true);
+        } else if (btStatus == BluetoothDetector::BluetoothStatus::Disconnected)
+        {
+            muteCtrl_.NotifyBluetoothConnected(false);
+        }
+    }
+    return TRUE;
 }
 
 LRESULT WinMute::OnWifiStatusChange(HWND, WPARAM wParam, LPARAM lParam)
 {
-   if (!muteConfig_.muteOnWlan) {
-      return 0;
-   }
-   if (wParam != 1) { // Not Connected
-      return 0;
-   }
-
-   if (settings_.QueryValue(SettingsKey::NOTIFICATIONS_ENABLED)) {
-      std::wstring popupMsg;
-      // 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 = SafeVFormat(
-            i18n_.GetTranslationW("popup.wlan-not-on-mute-list.text"),
-            wifiName);
-      } else {
-         popupMsg = SafeVFormat(
-            i18n_.GetTranslationW("popup.wlan-is-on-mute-list.text"),
-            wifiName);
-      }
-      wmTray_.ShowPopup(
-         i18n_.GetTranslationW("popup.workstation-muted.title"),
-         popupMsg);
-   }
-   muteCtrl_.SetMute(true);
-
-   return 0;
+    if (!muteConfig_.muteOnWlan) {
+        return 0;
+    }
+    if (wParam != 1) {  // Not Connected
+        return 0;
+    }
+
+    if (settings_.QueryValue(SettingsKey::NOTIFICATIONS_ENABLED)) {
+        std::wstring popupMsg;
+        // 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 = SafeVFormat(
+                i18n_.GetTranslationW("popup.wlan-not-on-mute-list.text"),
+                wifiName);
+        } else {
+            popupMsg = SafeVFormat(
+                i18n_.GetTranslationW("popup.wlan-is-on-mute-list.text"),
+                wifiName);
+        }
+        wmTray_.ShowPopup(
+            i18n_.GetTranslationW("popup.workstation-muted.title"), popupMsg);
+    }
+    muteCtrl_.SetMute(true);
+
+    return 0;
 }
 
-LRESULT CALLBACK WinMute::WindowProc(
-   HWND hWnd,
-   UINT msg,
-   WPARAM wParam,
-   LPARAM lParam)
+LRESULT CALLBACK WinMute::WindowProc(HWND hWnd, UINT msg, WPARAM wParam,
+                                     LPARAM lParam)
 {
-   static UINT uTaskbarRestart = 0;
-   switch (msg) {
-   case WM_CREATE:
-      uTaskbarRestart = RegisterWindowMessageW(L"TaskbarCreated");
-      return TRUE;
-   case WM_COMMAND:
-      return OnCommand(hWnd, wParam, lParam);
-   case WM_WINMUTE_UPDATE_POPUP:
-      return OnUpdatePopup(hWnd, wParam, lParam);
-   case WM_TRAYICON:
-      return OnTrayIcon(hWnd, wParam, lParam);
-   case WM_CLOSE:
-      Close();
-      return 0;
-   case WM_WTSSESSION_CHANGE: {
-      if (wParam == WTS_SESSION_LOCK) {
-         muteCtrl_.NotifyWorkstationLock(true);
-      } else if (wParam == WTS_SESSION_UNLOCK) {
-         muteCtrl_.NotifyWorkstationLock(false);
-      }
-      return 0;
-   }
-   case WM_POWERBROADCAST:
-      return OnPowerBroadcast(hWnd, wParam, lParam);
-   case WM_QUERYENDSESSION:
-      return TRUE;
-   case WM_ENDSESSION:
-      if (wParam == TRUE) {
-         if (lParam == 0) { // Shutdown
-            muteCtrl_.NotifyShutdown();
-         } else if ((lParam & ENDSESSION_LOGOFF)) {
-            muteCtrl_.NotifyLogout();
-         }
-      }
-      break;
-   case WM_WINMUTE_QUIETHOURS_START: // fall through
-   case WM_WINMUTE_QUIETHOURS_END:
-      return OnQuietHours(hWnd, msg, wParam, lParam);
-   case WM_WINMUTE_AUDIO_SERVICE_SHUTDOWN:
-      return OnAudioServiceShutdown(hWnd, wParam, lParam);
-   case WM_DEVICECHANGE:
-      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:
-      if (msg == uTaskbarRestart) { // Restore trayicon if explorer.exe crashes
-         wmTray_.Hide();
-         wmTray_.Show();
-      }
-      break;
-   }
-
-   return DefWindowProc(hWnd, msg, wParam, lParam);
+    static UINT uTaskbarRestart = 0;
+    switch (msg) {
+        case WM_CREATE:
+            uTaskbarRestart = RegisterWindowMessageW(L"TaskbarCreated");
+            return TRUE;
+        case WM_COMMAND:
+            return OnCommand(hWnd, wParam, lParam);
+        case WM_WINMUTE_UPDATE_POPUP:
+            return OnUpdatePopup(hWnd, wParam, lParam);
+        case WM_TRAYICON:
+            return OnTrayIcon(hWnd, wParam, lParam);
+        case WM_CLOSE:
+            Close();
+            return 0;
+        case WM_WTSSESSION_CHANGE: {
+            if (wParam == WTS_SESSION_LOCK) {
+                muteCtrl_.NotifyWorkstationLock(true);
+            } else if (wParam == WTS_SESSION_UNLOCK) {
+                muteCtrl_.NotifyWorkstationLock(false);
+            }
+            return 0;
+        }
+        case WM_POWERBROADCAST:
+            return OnPowerBroadcast(hWnd, wParam, lParam);
+        case WM_QUERYENDSESSION:
+            return TRUE;
+        case WM_ENDSESSION:
+            if (wParam == TRUE) {
+                if (lParam == 0) {  // Shutdown
+                    muteCtrl_.NotifyShutdown();
+                } else if ((lParam & ENDSESSION_LOGOFF)) {
+                    muteCtrl_.NotifyLogout();
+                }
+            }
+            break;
+        case WM_WINMUTE_QUIETHOURS_START:  // fall through
+        case WM_WINMUTE_QUIETHOURS_END:
+            return OnQuietHours(hWnd, msg, wParam, lParam);
+        case WM_WINMUTE_AUDIO_SERVICE_SHUTDOWN:
+            return OnAudioServiceShutdown(hWnd, wParam, lParam);
+        case WM_DEVICECHANGE:
+            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:
+            if (msg ==
+                uTaskbarRestart) {  // Restore trayicon if explorer.exe crashes
+                wmTray_.Hide();
+                wmTray_.Show();
+            }
+            break;
+    }
+
+    return DefWindowProc(hWnd, msg, wParam, lParam);
 }
 
 void WinMute::Unload() noexcept
 {
-   if (hPowerNotify_ != nullptr) {
-      UnregisterPowerSettingNotification(hPowerNotify_);
-      hPowerNotify_ = nullptr;
-   }
-   if (wtsSessionNotificationRegistered_) {
-      WTSUnRegisterSessionNotification(hWnd_);
-      wtsSessionNotificationRegistered_ = false;
-   }
-   settings_.Unload();
+    if (hPowerNotify_ != nullptr) {
+        UnregisterPowerSettingNotification(hPowerNotify_);
+        hPowerNotify_ = nullptr;
+    }
+    if (hLidCloseNotify_ != nullptr) {
+        UnregisterPowerSettingNotification(hLidCloseNotify_);
+        hLidCloseNotify_ = nullptr;
+    }
+    if (wtsSessionNotificationRegistered_) {
+        WTSUnRegisterSessionNotification(hWnd_);
+        wtsSessionNotificationRegistered_ = false;
+    }
+    settings_.Unload();
 }
 
 void WinMute::Close()
 {
-   Unload();
-   PostQuitMessage(0);
+    Unload();
+    PostQuitMessage(0);
 }
index fb574b635a33bf39667c660665f3d555bcdd104c..4d78612ded29b9a3603be541bd43538d1864b61a 100644 (file)
@@ -67,6 +67,7 @@ private:
 
    bool wtsSessionNotificationRegistered_ = false;
    HPOWERNOTIFY hPowerNotify_ = nullptr;
+   HPOWERNOTIFY hLidCloseNotify_ = nullptr;
 
    TrayIcon wmTray_;
    TrayIcon updateTray_;
index ac5bd762bac5cbe59b743af0e00fe6b1180d6359..aff266277825bcddedf9270b6b1632417e5dc27c 100644 (file)
@@ -105,7 +105,7 @@ BEGIN
     LTEXT           "If force unmute is enabled, WinMute will unmute your workstation when quiet hours end and not take into account if your workstation was already muted before quiet hours started.",IDC_QUIET_HOURS_FORCE_UNMUTE_DESCRIPTION,33,140,204,37
     CONTROL         "Show quiet hours notifications",IDC_SHOWNOTIFICATIONS,
                     "Button",BS_AUTOCHECKBOX | WS_TABSTOP,23,175,180,21
-    CONTROL         "",IDC_QUIET_HOURS_TIMES,"SysListView32",LVS_REPORT | LVS_ALIGNLEFT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | WS_BORDER | WS_TABSTOP,22,47,155,72
+    CONTROL         "",IDC_QUIET_HOURS_TIMES,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,22,47,155,72
     PUSHBUTTON      "Add",IDC_QUIET_HOURS_ADD,183,46,56,16
     PUSHBUTTON      "Edit",IDC_QUIET_HOURS_EDIT,183,65,56,16
     PUSHBUTTON      "Remove",IDC_QUIET_HOURS_REMOVE,183,84,56,16
@@ -132,7 +132,7 @@ BEGIN
     EDITTEXT        IDC_ABOUTTEXT,7,14,182,144,ES_MULTILINE | ES_AUTOVSCROLL | ES_NOHIDESEL | ES_READONLY | NOT WS_BORDER
 END
 
-IDD_SETTINGS_MUTE DIALOGEX 0, 0, 253, 263
+IDD_SETTINGS_MUTE DIALOGEX 0, 0, 253, 289
 STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD
 FONT 8, "MS Shell Dlg", 400, 0, 0x1
 BEGIN
@@ -142,27 +142,29 @@ BEGIN
     CONTROL         "Manage audio endpoints individually",IDC_MANAGE_AUDIO_ENDPOINTS_INDIVIDUALLY,
                     "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,28,227,18
     PUSHBUTTON      "Manage endpoints...",IDC_MANAGE_ENDPOINTS,26,46,97,15
-    GROUPBOX        "Mute with volume restore, when...",IDC_GROUP_MUTE_WITH_RESTORE,7,71,239,71
+    GROUPBOX        "Mute with volume restore, when...",IDC_GROUP_MUTE_WITH_RESTORE,7,71,239,91
     CONTROL         "... the workstation is locked.",IDC_MUTE_WHEN_WS_LOCKED,
                     "Button",BS_AUTOCHECKBOX | WS_TABSTOP,20,83,214,10
     CONTROL         "... the screen turns off.",IDC_MUTE_WHEN_SCREEN_OFF,
                     "Button",BS_AUTOCHECKBOX | WS_TABSTOP,20,97,205,10
-    CONTROL         "Restore volume afterwards.",IDC_RESTOREVOLUME,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,112,221,10
-    EDITTEXT        IDC_MUTEDELAY,13,124,30,13,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER
-    LTEXT           "seconds delay before muting.",IDC_DELAY_MUTING_LABEL,47,127,187,8
-    GROUPBOX        "Mute without volume restore, when...",IDC_GROUP_MUTE_WITHOUT_RESTORE,7,145,239,67
+    CONTROL         "Restore volume afterwards.",IDC_RESTOREVOLUME,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,131,221,10
+    EDITTEXT        IDC_MUTEDELAY,13,143,30,13,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER
+    LTEXT           "seconds delay before muting.",IDC_DELAY_MUTING_LABEL,47,146,187,8
+    GROUPBOX        "Mute without volume restore, when...",IDC_GROUP_MUTE_WITHOUT_RESTORE,7,165,239,67
     CONTROL         "... the computer shuts down.",IDC_MUTE_WHEN_SHUTDOWN,
-                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,20,156,220,10
+                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,20,176,220,10
     CONTROL         "... the computer goes into sleep/hibernate.",IDC_MUTE_WHEN_SLEEP,
-                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,20,170,214,10
-    CONTROL         "... you log out.",IDC_MUTE_WHEN_LOGOUT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,20,184,214,10
+                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,20,190,214,10
+    CONTROL         "... you log out.",IDC_MUTE_WHEN_LOGOUT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,20,204,214,10
     CONTROL         "... when WinMute is started within a RDP session.",IDC_MUTE_WHEN_RDP_SESSION,
-                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,20,198,220,10
-    GROUPBOX        "Media",IDC_GROUP_MUTE_MEDIA_CONTROL,7,216,239,42
+                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,20,218,220,10
+    GROUPBOX        "Media",IDC_GROUP_MUTE_MEDIA_CONTROL,7,236,239,42
     CONTROL         "Try pausing currently played media when muting.",IDC_MUTE_TRY_PAUSE_MEDIA,
-                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,20,227,219,10
+                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,20,247,219,10
     CONTROL         "Try resuming media when unmuting.",IDC_MUTE_TRY_RESUME_MEDIA,
-                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,20,241,214,10
+                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,20,261,214,10
+    CONTROL         "... the laptop lid closes.",IDC_MUTE_WHEN_LID_CLOSE,
+                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,20,110,205,10
 END
 
 IDD_SETTINGS_WIFI DIALOGEX 0, 0, 242, 216
@@ -336,7 +338,7 @@ BEGIN
         LEFTMARGIN, 7
         RIGHTMARGIN, 246
         TOPMARGIN, 7
-        BOTTOMMARGIN, 254
+        BOTTOMMARGIN, 280
     END
 
     IDD_SETTINGS_WIFI, DIALOG
index 84afdd4468681511a82298dabddb1dc99b96f3ec..db1a043a58a78c4f4d7f2ec11a94e6cd3a4f8c93 100644 (file)
@@ -77,7 +77,7 @@
     <Link>
       <SubSystem>Windows</SubSystem>
       <GenerateDebugInformation>true</GenerateDebugInformation>
-      <AdditionalDependencies>mincore.lib;windowsapp.lib;Winhttp.lib;Bthprops.lib;Winmm.lib;UxTheme.lib;Wlanapi.lib;comctl32.lib;WtsApi32.lib;Version.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalDependencies>mincore.lib;windowsapp.lib;Winhttp.lib;Bthprops.lib;Winmm.lib;UxTheme.lib;Wlanapi.lib;comctl32.lib;WtsApi32.lib;Version.lib;PowrProf.lib%(AdditionalDependencies)</AdditionalDependencies>
     </Link>
     <Manifest>
       <EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
       <OptimizeReferences>true</OptimizeReferences>
       <GenerateDebugInformation>true</GenerateDebugInformation>
-      <AdditionalDependencies>mincore.lib;windowsapp.lib;Winhttp.lib;Bthprops.lib;Winmm.lib;UxTheme.lib;Wlanapi.lib;comctl32.lib;WtsApi32.lib;Version.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalDependencies>mincore.lib;windowsapp.lib;Winhttp.lib;Bthprops.lib;Winmm.lib;UxTheme.lib;Wlanapi.lib;comctl32.lib;WtsApi32.lib;Version.lib;PowrProf.lib%(AdditionalDependencies)</AdditionalDependencies>
       <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
       <TreatLinkerWarningAsErrors>true</TreatLinkerWarningAsErrors>
       <CETCompat>true</CETCompat>
@@ -319,4 +319,4 @@ copy /Y %(FullPath) $(OutputPath)lang</Command>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   </ImportGroup>
-</Project>
\ No newline at end of file
+</Project>
index 2d04518ee7c8f9006e3483a86bc78b42a5c0186f..c32271d4b944e383daaf322764d58125fd61c106 100644 (file)
@@ -34,34 +34,42 @@ POSSIBILITY OF SUCH DAMAGE.
 #pragma once
 
 #ifndef UNICODE
-#  define UNICODE
+#    define UNICODE
 #endif
 
 #ifndef _UNICODE
-#  define _UNICODE
+#    define _UNICODE
 #endif
 
 #if defined _M_IX86
-#  pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")
+#    pragma comment( \
+        linker,      \
+        "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")
 #elif defined _M_IA64
-#  pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"")
+#    pragma comment( \
+        linker,      \
+        "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"")
 #elif defined _M_X64
-#  pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"")
+#    pragma comment( \
+        linker,      \
+        "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"")
 #else
-#  pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
+#    pragma comment( \
+        linker,      \
+        "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
 #endif
 
 #define STRICT
 #define _WIN32_WINNT 0x0601
+#include <atlbase.h>
 #include <sdkddkver.h>
 
-#include <atlbase.h>
-#include <atomic>
 #include <algorithm>
 #include <array>
+#include <atomic>
 #include <cassert>
-#include <cstdarg>
 #include <chrono>
+#include <cstdarg>
 #include <filesystem>
 #include <format>
 #include <fstream>
@@ -81,48 +89,48 @@ POSSIBILITY OF SUCH DAMAGE.
 
 namespace fs = std::filesystem;
 
-#include <windows.h>
-#include <windowsx.h>
-#include <commctrl.h>
-#include <WtsApi32.h>
-#include <winhttp.h>
-#include <dbt.h>
+#include <BluetoothAPIs.h>
 #include <Bthdef.h>
 #include <Bthsdpdef.h>
-#include <BluetoothAPIs.h>
-#include <tchar.h>
+#include <Mmdeviceapi.h>
+#include <WtsApi32.h>
+#include <comdef.h>
+#include <comip.h>
+#include <commctrl.h>
+#include <dbt.h>
+#include <dwmapi.h>
+#include <initguid.h>
+#include <powrprof.h>
+#include <roapi.h>
+#include <sal.h>
 #include <strsafe.h>
+#include <tchar.h>
 #include <time.h>
 #include <uxtheme.h>
-#include <comip.h>
-#include <comdef.h>
+#include <windows.h>
+#include <windowsx.h>
+#include <winhttp.h>
 #include <wlanapi.h>
-#include <Mmdeviceapi.h>
-#include <dwmapi.h>
-#include <sal.h>
-#include <roapi.h>
 #pragma warning(disable : 4201)
-#  include <endpointvolume.h>
+#include <endpointvolume.h>
 #pragma warning(default : 4201)
 
-#include "libs/json.hpp"
-
-#include "resource.h"
-
-#include "WMi18n.h"
-#include "WMSettings.h"
-#include "WMLog.h"
-#include "UpdateChecker.h"
-#include "TrayIcon.h"
-#include "WinAudio.h"
+#include "BluetoothDetector.h"
 #include "MediaController.h"
 #include "MuteControl.h"
-#include "WiFiDetector.h"
-#include "BluetoothDetector.h"
 #include "QuietHoursTimer.h"
-#include "WinMute.h"
+#include "TrayIcon.h"
+#include "UpdateChecker.h"
 #include "Utility.h"
 #include "VersionHelper.h"
+#include "WMLog.h"
+#include "WMSettings.h"
+#include "WMi18n.h"
+#include "WiFiDetector.h"
+#include "WinAudio.h"
+#include "WinMute.h"
+#include "libs/json.hpp"
+#include "resource.h"
 
 // =============================================================================
 // Macros
@@ -132,8 +140,8 @@ namespace fs = std::filesystem;
 // =============================================================================
 // Constants
 
-static const wchar_t *PROGRAM_NAME = L"WinMute";
-static const wchar_t *LOG_FILE_NAME = L"WinMute.log";
+static const wchar_t* PROGRAM_NAME = L"WinMute";
+static const wchar_t* LOG_FILE_NAME = L"WinMute.log";
 
 constexpr int WM_SAVESETTINGS = WM_USER + 300;
 constexpr int WM_WINMUTE_UPDATE_POPUP = WM_USER + 301;
index eac69edd204eb328f03d582ba6a5cf7668cf4936..1f0fce21ab54cf4ed8a1927037dda7b3183cb69b 100644 (file)
@@ -78,6 +78,8 @@
 #define IDC_MUTE_RESUME_MEDIA           1029
 #define IDC_MUTE_TRY_RESUME_MEDIA       1029
 #define IDC_STATIC_BLUETOOTH_NOT_AVAILABLE 1030
+#define IDC_MUTE_WHEN_SCREEN_OFF2       1030
+#define IDC_MUTE_WHEN_LID_CLOSE         1030
 #define IDC_BLUETOOTH_ADD               1031
 #define IDC_BLUETOOTH_EDIT              1032
 #define IDC_BLUETOOTH_REMOVE            1033