From d5bc60e33e7756ec96e5228968e370199c6d44d8 Mon Sep 17 00:00:00 2001 From: Sanai McCormick Date: Fri, 1 May 2026 23:23:40 +0100 Subject: [PATCH 1/3] Fix Windows screensaver restore behavior --- .../Client/ScreensaverInstallerWin32.cpp | 179 ++++++++++++++---- .../Client/ScreensaverInstallerWin32.h | 5 +- client_generic/Client/SettingsDialogWin32.cpp | 1 + .../SettingsDialogWin32.TabAdvanced.inl | 18 ++ 4 files changed, 165 insertions(+), 38 deletions(-) diff --git a/client_generic/Client/ScreensaverInstallerWin32.cpp b/client_generic/Client/ScreensaverInstallerWin32.cpp index faca1654..5fac69d4 100644 --- a/client_generic/Client/ScreensaverInstallerWin32.cpp +++ b/client_generic/Client/ScreensaverInstallerWin32.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include "Log.h" @@ -14,93 +15,197 @@ namespace { +constexpr const char* kDesktopKey = "Control Panel\\Desktop"; +constexpr const char* kBackupKey = "Software\\Infinidream\\Screensaver"; + std::string ReadRegString(HKEY hKey, const char* valueName) { char buf[MAX_PATH] = {}; DWORD type = 0; - DWORD size = sizeof(buf) - 1; + DWORD size = sizeof(buf); + const LSTATUS rc = RegQueryValueExA(hKey, valueName, nullptr, &type, reinterpret_cast(buf), &size); - if (rc != ERROR_SUCCESS || type != REG_SZ) + + if (rc != ERROR_SUCCESS) return {}; + + if (type != REG_SZ && type != REG_EXPAND_SZ) + return {}; + return std::string(buf); } bool WriteRegString(HKEY hKey, const char* valueName, const std::string& value) { - const LSTATUS rc = RegSetValueExA( - hKey, valueName, 0, REG_SZ, - reinterpret_cast(value.c_str()), - static_cast(value.size() + 1)); + const LSTATUS rc = + RegSetValueExA(hKey, valueName, 0, REG_SZ, + reinterpret_cast(value.c_str()), + static_cast(value.size() + 1)); return rc == ERROR_SUCCESS; } -} // namespace -void ScreensaverInstallerWin32::EnsureScreensaverActive(const std::string& workingDir) +bool IsPositiveIntegerString(const std::string& value) { - if (!g_Settings()->Get("settings.app.keep_screensaver_enabled", true)) + if (value.empty()) + return false; + + for (char c : value) { - if (g_Log) g_Log->Info("EnsureScreensaverActive: opt-out, skipping"); - return; + if (c < '0' || c > '9') + return false; } + return std::atoi(value.c_str()) > 0; +} + +std::string BuildScrPath(const std::string& workingDir) +{ std::string scrPath = workingDir; if (!scrPath.empty() && scrPath.back() != '\\' && scrPath.back() != '/') scrPath += '\\'; scrPath += "infinidream.scr"; + return scrPath; +} - if (!PathFileExistsA(scrPath.c_str())) +void RefreshScreensaverSettings(bool active) +{ + SystemParametersInfoA(SPI_SETSCREENSAVEACTIVE, active ? TRUE : FALSE, + nullptr, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE); +} +} // namespace + +void ScreensaverInstallerWin32::SaveOriginalScreensaverSettingsOnce( + const std::string& workingDir) +{ + HKEY hBackup = nullptr; + DWORD disposition = 0; + + if (RegCreateKeyExA(HKEY_CURRENT_USER, kBackupKey, 0, nullptr, 0, + KEY_READ | KEY_WRITE, nullptr, &hBackup, + &disposition) != ERROR_SUCCESS) + return; + + HKEY hDesktop = nullptr; + if (RegOpenKeyExA(HKEY_CURRENT_USER, kDesktopKey, 0, KEY_READ, &hDesktop) != + ERROR_SUCCESS) { - if (g_Log) g_Log->Warning("EnsureScreensaverActive: %s missing, skipping", - scrPath.c_str()); + RegCloseKey(hBackup); return; } - HKEY hKey = nullptr; - const LSTATUS rc = RegOpenKeyExA(HKEY_CURRENT_USER, "Control Panel\\Desktop", 0, - KEY_READ | KEY_WRITE, &hKey); - if (rc != ERROR_SUCCESS) + const std::string originalExe = ReadRegString(hDesktop, "SCRNSAVE.EXE"); + const std::string originalActive = + ReadRegString(hDesktop, "ScreenSaveActive"); + const std::string originalTimeout = + ReadRegString(hDesktop, "ScreenSaveTimeOut"); + + const std::string infinidreamScr = BuildScrPath(workingDir); + + if (_stricmp(originalExe.c_str(), infinidreamScr.c_str()) == 0) { - if (g_Log) g_Log->Warning("EnsureScreensaverActive: cannot open Desktop key (%ld)", - static_cast(rc)); + RegCloseKey(hDesktop); + RegCloseKey(hBackup); return; } + WriteRegString(hBackup, "OriginalExe", originalExe); + WriteRegString(hBackup, "OriginalActive", originalActive); + WriteRegString(hBackup, "OriginalTimeout", originalTimeout); + WriteRegString(hBackup, "OriginalSaved", "1"); + + RegCloseKey(hDesktop); + RegCloseKey(hBackup); +} + +bool ScreensaverInstallerWin32::RestoreOriginalScreensaverSettings() +{ + HKEY hBackup = nullptr; + if (RegOpenKeyExA(HKEY_CURRENT_USER, kBackupKey, 0, KEY_READ, &hBackup) != + ERROR_SUCCESS) + return false; + + if (ReadRegString(hBackup, "OriginalSaved") != "1") + { + RegCloseKey(hBackup); + return false; + } + + const std::string originalExe = ReadRegString(hBackup, "OriginalExe"); + const std::string originalActive = ReadRegString(hBackup, "OriginalActive"); + const std::string originalTimeout = + ReadRegString(hBackup, "OriginalTimeout"); + + RegCloseKey(hBackup); + + HKEY hDesktop = nullptr; + if (RegOpenKeyExA(HKEY_CURRENT_USER, kDesktopKey, 0, KEY_READ | KEY_WRITE, + &hDesktop) != ERROR_SUCCESS) + return false; + + const bool originalWasNone = originalExe.empty(); + + WriteRegString(hDesktop, "SCRNSAVE.EXE", + originalWasNone ? "" : originalExe); + WriteRegString(hDesktop, "ScreenSaveActive", + originalWasNone ? "0" : originalActive); + + if (!originalTimeout.empty()) + WriteRegString(hDesktop, "ScreenSaveTimeOut", originalTimeout); + + RegCloseKey(hDesktop); + + RefreshScreensaverSettings(!originalWasNone && originalActive == "1"); + + return true; +} + +void ScreensaverInstallerWin32::EnsureScreensaverActive( + const std::string& workingDir) +{ + if (!g_Settings()->Get("settings.app.keep_screensaver_enabled", true)) + return; + + SaveOriginalScreensaverSettingsOnce(workingDir); + + const std::string scrPath = BuildScrPath(workingDir); + + if (!PathFileExistsA(scrPath.c_str())) + return; + + HKEY hKey = nullptr; + if (RegOpenKeyExA(HKEY_CURRENT_USER, kDesktopKey, 0, KEY_READ | KEY_WRITE, + &hKey) != ERROR_SUCCESS) + return; + const std::string currentScr = ReadRegString(hKey, "SCRNSAVE.EXE"); const std::string currentActive = ReadRegString(hKey, "ScreenSaveActive"); + const std::string currentTimeout = ReadRegString(hKey, "ScreenSaveTimeOut"); bool changed = false; + + if (!IsPositiveIntegerString(currentTimeout)) + { + if (WriteRegString(hKey, "ScreenSaveTimeOut", "60")) + changed = true; + } + if (_stricmp(currentScr.c_str(), scrPath.c_str()) != 0) { if (WriteRegString(hKey, "SCRNSAVE.EXE", scrPath)) - { changed = true; - if (g_Log) g_Log->Info("EnsureScreensaverActive: SCRNSAVE.EXE '%s' -> '%s'", - currentScr.c_str(), scrPath.c_str()); - } } if (currentActive != "1") { if (WriteRegString(hKey, "ScreenSaveActive", "1")) - { changed = true; - if (g_Log) g_Log->Info("EnsureScreensaverActive: ScreenSaveActive '%s' -> '1'", - currentActive.c_str()); - } } RegCloseKey(hKey); if (changed) - { - // Nudge Explorer / the screen-saver subsystem to re-read the registry - // without waiting for a logon. SMTO_ABORTIFHUNG keeps us from blocking - // on a stuck top-level window. - SendMessageTimeoutA(HWND_BROADCAST, WM_SETTINGCHANGE, 0, - reinterpret_cast("Windows"), - SMTO_ABORTIFHUNG, 1000, nullptr); - } + RefreshScreensaverSettings(true); } -#endif // WIN32 +#endif \ No newline at end of file diff --git a/client_generic/Client/ScreensaverInstallerWin32.h b/client_generic/Client/ScreensaverInstallerWin32.h index 95f09bab..0a7f04e3 100644 --- a/client_generic/Client/ScreensaverInstallerWin32.h +++ b/client_generic/Client/ScreensaverInstallerWin32.h @@ -6,6 +6,9 @@ namespace ScreensaverInstallerWin32 { +void SaveOriginalScreensaverSettingsOnce(const std::string& workingDir); +bool RestoreOriginalScreensaverSettings(); + // Make sure infinidream is the active Windows screensaver, when the user has opted // in via settings.app.keep_screensaver_enabled. Idempotent — re-reads the registry // and only writes when values differ. Safe to call on every app launch. @@ -18,4 +21,4 @@ namespace ScreensaverInstallerWin32 void EnsureScreensaverActive(const std::string& workingDir); } // namespace ScreensaverInstallerWin32 -#endif // WIN32 +#endif // WIN32 \ No newline at end of file diff --git a/client_generic/Client/SettingsDialogWin32.cpp b/client_generic/Client/SettingsDialogWin32.cpp index 4b7475dd..98a8ac06 100644 --- a/client_generic/Client/SettingsDialogWin32.cpp +++ b/client_generic/Client/SettingsDialogWin32.cpp @@ -34,6 +34,7 @@ extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg #include "storage.h" #include "CacheManager.h" #include "client.h" +#include "ScreensaverInstallerWin32.h" #pragma comment(lib, "ole32.lib") #pragma comment(lib, "windowscodecs.lib") diff --git a/client_generic/Client/SettingsDialogWin32/SettingsDialogWin32.TabAdvanced.inl b/client_generic/Client/SettingsDialogWin32/SettingsDialogWin32.TabAdvanced.inl index 7a390120..ea0ee4f4 100644 --- a/client_generic/Client/SettingsDialogWin32/SettingsDialogWin32.TabAdvanced.inl +++ b/client_generic/Client/SettingsDialogWin32/SettingsDialogWin32.TabAdvanced.inl @@ -18,7 +18,25 @@ const float fieldRowGap = S(2.f); ImGui::SetWindowFontScale(topCheckboxFontScale); ImGui::SetCursorPosY(ImGui::GetCursorPosY() + firstCheckboxDownOffset); ImGui::SetCursorPosX(leftInset); +const bool wasKeepScreensaverEnabled = g_keepScreensaverEnabled; StyledCheckbox("Keep screensaver enabled", &g_keepScreensaverEnabled); + +if (wasKeepScreensaverEnabled != g_keepScreensaverEnabled) +{ + g_Settings()->Set("settings.app.keep_screensaver_enabled", + g_keepScreensaverEnabled); + g_Settings()->Storage()->Commit(); + + if (g_keepScreensaverEnabled) + { + ScreensaverInstallerWin32::EnsureScreensaverActive( + PlatformUtils::GetWorkingDir()); + } + else + { + ScreensaverInstallerWin32::RestoreOriginalScreensaverSettings(); + } +} ImGui::SetWindowFontScale(advancedFontScale); #ifdef DEBUG From d968b94fae6506f78cac19bf9616dededb03454d Mon Sep 17 00:00:00 2001 From: Sanai McCormick Date: Mon, 4 May 2026 22:37:45 +0100 Subject: [PATCH 2/3] Add logging for screensaver backup/restore and registry operations --- .../Client/ScreensaverInstallerWin32.cpp | 105 ++++++++++++++++-- 1 file changed, 94 insertions(+), 11 deletions(-) diff --git a/client_generic/Client/ScreensaverInstallerWin32.cpp b/client_generic/Client/ScreensaverInstallerWin32.cpp index 5fac69d4..9be9c28a 100644 --- a/client_generic/Client/ScreensaverInstallerWin32.cpp +++ b/client_generic/Client/ScreensaverInstallerWin32.cpp @@ -81,15 +81,27 @@ void ScreensaverInstallerWin32::SaveOriginalScreensaverSettingsOnce( HKEY hBackup = nullptr; DWORD disposition = 0; - if (RegCreateKeyExA(HKEY_CURRENT_USER, kBackupKey, 0, nullptr, 0, - KEY_READ | KEY_WRITE, nullptr, &hBackup, - &disposition) != ERROR_SUCCESS) + const LSTATUS backupRc = + RegCreateKeyExA(HKEY_CURRENT_USER, kBackupKey, 0, nullptr, 0, + KEY_READ | KEY_WRITE, nullptr, &hBackup, &disposition); + if (backupRc != ERROR_SUCCESS) + { + if (g_Log) + g_Log->Warning("SaveOriginalScreensaverSettingsOnce: cannot open " + "backup key (%ld)", + static_cast(backupRc)); return; + } HKEY hDesktop = nullptr; - if (RegOpenKeyExA(HKEY_CURRENT_USER, kDesktopKey, 0, KEY_READ, &hDesktop) != - ERROR_SUCCESS) + const LSTATUS desktopRc = + RegOpenKeyExA(HKEY_CURRENT_USER, kDesktopKey, 0, KEY_READ, &hDesktop); + if (desktopRc != ERROR_SUCCESS) { + if (g_Log) + g_Log->Warning("SaveOriginalScreensaverSettingsOnce: cannot open " + "Desktop key (%ld)", + static_cast(desktopRc)); RegCloseKey(hBackup); return; } @@ -104,6 +116,10 @@ void ScreensaverInstallerWin32::SaveOriginalScreensaverSettingsOnce( if (_stricmp(originalExe.c_str(), infinidreamScr.c_str()) == 0) { + if (g_Log) + g_Log->Info( + "SaveOriginalScreensaverSettingsOnce: current screensaver is " + "already Infinidream, not overwriting backup"); RegCloseKey(hDesktop); RegCloseKey(hBackup); return; @@ -114,6 +130,12 @@ void ScreensaverInstallerWin32::SaveOriginalScreensaverSettingsOnce( WriteRegString(hBackup, "OriginalTimeout", originalTimeout); WriteRegString(hBackup, "OriginalSaved", "1"); + if (g_Log) + g_Log->Info("SaveOriginalScreensaverSettingsOnce: saved backup " + "exe='%s', active='%s', timeout='%s'", + originalExe.c_str(), originalActive.c_str(), + originalTimeout.c_str()); + RegCloseKey(hDesktop); RegCloseKey(hBackup); } @@ -121,12 +143,22 @@ void ScreensaverInstallerWin32::SaveOriginalScreensaverSettingsOnce( bool ScreensaverInstallerWin32::RestoreOriginalScreensaverSettings() { HKEY hBackup = nullptr; - if (RegOpenKeyExA(HKEY_CURRENT_USER, kBackupKey, 0, KEY_READ, &hBackup) != - ERROR_SUCCESS) + const LSTATUS backupRc = + RegOpenKeyExA(HKEY_CURRENT_USER, kBackupKey, 0, KEY_READ, &hBackup); + if (backupRc != ERROR_SUCCESS) + { + if (g_Log) + g_Log->Warning("RestoreOriginalScreensaverSettings: cannot open " + "backup key (%ld)", + static_cast(backupRc)); return false; + } if (ReadRegString(hBackup, "OriginalSaved") != "1") { + if (g_Log) + g_Log->Warning("RestoreOriginalScreensaverSettings: backup is not " + "marked saved"); RegCloseKey(hBackup); return false; } @@ -136,12 +168,25 @@ bool ScreensaverInstallerWin32::RestoreOriginalScreensaverSettings() const std::string originalTimeout = ReadRegString(hBackup, "OriginalTimeout"); + if (g_Log) + g_Log->Info("RestoreOriginalScreensaverSettings: restoring exe='%s', " + "active='%s', timeout='%s'", + originalExe.c_str(), originalActive.c_str(), + originalTimeout.c_str()); + RegCloseKey(hBackup); HKEY hDesktop = nullptr; - if (RegOpenKeyExA(HKEY_CURRENT_USER, kDesktopKey, 0, KEY_READ | KEY_WRITE, - &hDesktop) != ERROR_SUCCESS) + const LSTATUS desktopRc = RegOpenKeyExA(HKEY_CURRENT_USER, kDesktopKey, 0, + KEY_READ | KEY_WRITE, &hDesktop); + if (desktopRc != ERROR_SUCCESS) + { + if (g_Log) + g_Log->Warning("RestoreOriginalScreensaverSettings: cannot open " + "Desktop key (%ld)", + static_cast(desktopRc)); return false; + } const bool originalWasNone = originalExe.empty(); @@ -157,6 +202,10 @@ bool ScreensaverInstallerWin32::RestoreOriginalScreensaverSettings() RefreshScreensaverSettings(!originalWasNone && originalActive == "1"); + if (g_Log) + g_Log->Info("RestoreOriginalScreensaverSettings: restored original " + "screensaver settings"); + return true; } @@ -164,19 +213,35 @@ void ScreensaverInstallerWin32::EnsureScreensaverActive( const std::string& workingDir) { if (!g_Settings()->Get("settings.app.keep_screensaver_enabled", true)) + { + if (g_Log) + g_Log->Info("EnsureScreensaverActive: opt-out, skipping"); return; + } SaveOriginalScreensaverSettingsOnce(workingDir); const std::string scrPath = BuildScrPath(workingDir); if (!PathFileExistsA(scrPath.c_str())) + { + if (g_Log) + g_Log->Warning("EnsureScreensaverActive: %s missing, skipping", + scrPath.c_str()); return; + } HKEY hKey = nullptr; - if (RegOpenKeyExA(HKEY_CURRENT_USER, kDesktopKey, 0, KEY_READ | KEY_WRITE, - &hKey) != ERROR_SUCCESS) + const LSTATUS desktopRc = RegOpenKeyExA(HKEY_CURRENT_USER, kDesktopKey, 0, + KEY_READ | KEY_WRITE, &hKey); + if (desktopRc != ERROR_SUCCESS) + { + if (g_Log) + g_Log->Warning( + "EnsureScreensaverActive: cannot open Desktop key (%ld)", + static_cast(desktopRc)); return; + } const std::string currentScr = ReadRegString(hKey, "SCRNSAVE.EXE"); const std::string currentActive = ReadRegString(hKey, "ScreenSaveActive"); @@ -187,19 +252,37 @@ void ScreensaverInstallerWin32::EnsureScreensaverActive( if (!IsPositiveIntegerString(currentTimeout)) { if (WriteRegString(hKey, "ScreenSaveTimeOut", "60")) + { changed = true; + if (g_Log) + g_Log->Info( + "EnsureScreensaverActive: ScreenSaveTimeOut '%s' -> '60'", + currentTimeout.c_str()); + } } if (_stricmp(currentScr.c_str(), scrPath.c_str()) != 0) { if (WriteRegString(hKey, "SCRNSAVE.EXE", scrPath)) + { changed = true; + if (g_Log) + g_Log->Info( + "EnsureScreensaverActive: SCRNSAVE.EXE '%s' -> '%s'", + currentScr.c_str(), scrPath.c_str()); + } } if (currentActive != "1") { if (WriteRegString(hKey, "ScreenSaveActive", "1")) + { changed = true; + if (g_Log) + g_Log->Info( + "EnsureScreensaverActive: ScreenSaveActive '%s' -> '1'", + currentActive.c_str()); + } } RegCloseKey(hKey); From 4b452705e42cfeff637aadeb65b2603113c681d2 Mon Sep 17 00:00:00 2001 From: Sanai McCormick Date: Tue, 5 May 2026 23:34:06 +0100 Subject: [PATCH 3/3] Fix screensaver backup/restore: save before read-only InitStorage --- .../Client/ScreensaverInstallerWin32.cpp | 180 +++++++++++------- client_generic/Client/client_win32.h | 34 ++-- 2 files changed, 139 insertions(+), 75 deletions(-) diff --git a/client_generic/Client/ScreensaverInstallerWin32.cpp b/client_generic/Client/ScreensaverInstallerWin32.cpp index 9be9c28a..405f4bb3 100644 --- a/client_generic/Client/ScreensaverInstallerWin32.cpp +++ b/client_generic/Client/ScreensaverInstallerWin32.cpp @@ -7,6 +7,7 @@ #include #include +#include #include "Log.h" #include "Settings.h" @@ -16,7 +17,15 @@ namespace { constexpr const char* kDesktopKey = "Control Panel\\Desktop"; -constexpr const char* kBackupKey = "Software\\Infinidream\\Screensaver"; +constexpr const char* kBackupSettingKey = "settings.app.screensaver_backup"; + +struct ScreensaverBackup +{ + bool valid = false; + std::string exe; + std::string active; + std::string timeout; +}; std::string ReadRegString(HKEY hKey, const char* valueName) { @@ -68,117 +77,160 @@ std::string BuildScrPath(const std::string& workingDir) return scrPath; } +std::string NormalizePathForCompare(std::string path) +{ + for (char& c : path) + { + if (c == '/') + c = '\\'; + } + + return path; +} + void RefreshScreensaverSettings(bool active) { SystemParametersInfoA(SPI_SETSCREENSAVEACTIVE, active ? TRUE : FALSE, nullptr, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE); } -} // namespace -void ScreensaverInstallerWin32::SaveOriginalScreensaverSettingsOnce( - const std::string& workingDir) +std::vector SplitLines(const std::string& value) { - HKEY hBackup = nullptr; - DWORD disposition = 0; + std::vector lines; + std::string current; - const LSTATUS backupRc = - RegCreateKeyExA(HKEY_CURRENT_USER, kBackupKey, 0, nullptr, 0, - KEY_READ | KEY_WRITE, nullptr, &hBackup, &disposition); - if (backupRc != ERROR_SUCCESS) + for (char c : value) { - if (g_Log) - g_Log->Warning("SaveOriginalScreensaverSettingsOnce: cannot open " - "backup key (%ld)", - static_cast(backupRc)); - return; + if (c == '\n') + { + lines.push_back(current); + current.clear(); + } + else if (c != '\r') + { + current.push_back(c); + } } + lines.push_back(current); + return lines; +} + +std::string SerializeBackup(const ScreensaverBackup& backup) +{ + return std::string(backup.valid ? "1" : "0") + "\n" + backup.exe + "\n" + + backup.active + "\n" + backup.timeout; +} + +ScreensaverBackup ReadBackupFromSettings() +{ + ScreensaverBackup backup; + + if (!g_Settings()) + return backup; + + const std::string raw = g_Settings()->Get(kBackupSettingKey, std::string()); + + const std::vector lines = SplitLines(raw); + if (lines.size() < 4 || lines[0] != "1") + return backup; + + backup.valid = true; + backup.exe = lines[1]; + backup.active = lines[2]; + backup.timeout = lines[3]; + + return backup; +} + +void SaveBackupToSettings(const ScreensaverBackup& backup) +{ + if (!g_Settings()) + return; + const std::string serialized = SerializeBackup(backup); + + if (g_Log) + g_Log->Info("SaveBackupToSettings: writing '%s'", serialized.c_str()); + + g_Settings()->Set(kBackupSettingKey, serialized); + g_Settings()->Storage()->Commit(); + + // Verify it survived the commit + const std::string verify = + g_Settings()->Get(kBackupSettingKey, std::string("MISSING")); + if (g_Log) + g_Log->Info("SaveBackupToSettings: verify read-back '%s'", + verify.c_str()); +} +} // namespace + +void ScreensaverInstallerWin32::SaveOriginalScreensaverSettingsOnce( + const std::string& workingDir) +{ HKEY hDesktop = nullptr; const LSTATUS desktopRc = RegOpenKeyExA(HKEY_CURRENT_USER, kDesktopKey, 0, KEY_READ, &hDesktop); + if (desktopRc != ERROR_SUCCESS) { if (g_Log) g_Log->Warning("SaveOriginalScreensaverSettingsOnce: cannot open " "Desktop key (%ld)", static_cast(desktopRc)); - RegCloseKey(hBackup); return; } - const std::string originalExe = ReadRegString(hDesktop, "SCRNSAVE.EXE"); - const std::string originalActive = - ReadRegString(hDesktop, "ScreenSaveActive"); - const std::string originalTimeout = - ReadRegString(hDesktop, "ScreenSaveTimeOut"); + ScreensaverBackup backup; + backup.valid = true; + backup.exe = ReadRegString(hDesktop, "SCRNSAVE.EXE"); + backup.active = ReadRegString(hDesktop, "ScreenSaveActive"); + backup.timeout = ReadRegString(hDesktop, "ScreenSaveTimeOut"); + + RegCloseKey(hDesktop); const std::string infinidreamScr = BuildScrPath(workingDir); - if (_stricmp(originalExe.c_str(), infinidreamScr.c_str()) == 0) + if (_stricmp(NormalizePathForCompare(backup.exe).c_str(), + NormalizePathForCompare(infinidreamScr).c_str()) == 0) { if (g_Log) g_Log->Info( "SaveOriginalScreensaverSettingsOnce: current screensaver is " "already Infinidream, not overwriting backup"); - RegCloseKey(hDesktop); - RegCloseKey(hBackup); return; } - WriteRegString(hBackup, "OriginalExe", originalExe); - WriteRegString(hBackup, "OriginalActive", originalActive); - WriteRegString(hBackup, "OriginalTimeout", originalTimeout); - WriteRegString(hBackup, "OriginalSaved", "1"); + SaveBackupToSettings(backup); if (g_Log) g_Log->Info("SaveOriginalScreensaverSettingsOnce: saved backup " "exe='%s', active='%s', timeout='%s'", - originalExe.c_str(), originalActive.c_str(), - originalTimeout.c_str()); - - RegCloseKey(hDesktop); - RegCloseKey(hBackup); + backup.exe.c_str(), backup.active.c_str(), + backup.timeout.c_str()); } bool ScreensaverInstallerWin32::RestoreOriginalScreensaverSettings() { - HKEY hBackup = nullptr; - const LSTATUS backupRc = - RegOpenKeyExA(HKEY_CURRENT_USER, kBackupKey, 0, KEY_READ, &hBackup); - if (backupRc != ERROR_SUCCESS) - { - if (g_Log) - g_Log->Warning("RestoreOriginalScreensaverSettings: cannot open " - "backup key (%ld)", - static_cast(backupRc)); - return false; - } + const ScreensaverBackup backup = ReadBackupFromSettings(); - if (ReadRegString(hBackup, "OriginalSaved") != "1") + if (!backup.valid) { if (g_Log) - g_Log->Warning("RestoreOriginalScreensaverSettings: backup is not " - "marked saved"); - RegCloseKey(hBackup); + g_Log->Warning("RestoreOriginalScreensaverSettings: no valid " + "screensaver backup in settings"); return false; } - const std::string originalExe = ReadRegString(hBackup, "OriginalExe"); - const std::string originalActive = ReadRegString(hBackup, "OriginalActive"); - const std::string originalTimeout = - ReadRegString(hBackup, "OriginalTimeout"); - if (g_Log) g_Log->Info("RestoreOriginalScreensaverSettings: restoring exe='%s', " "active='%s', timeout='%s'", - originalExe.c_str(), originalActive.c_str(), - originalTimeout.c_str()); - - RegCloseKey(hBackup); + backup.exe.c_str(), backup.active.c_str(), + backup.timeout.c_str()); HKEY hDesktop = nullptr; const LSTATUS desktopRc = RegOpenKeyExA(HKEY_CURRENT_USER, kDesktopKey, 0, KEY_READ | KEY_WRITE, &hDesktop); + if (desktopRc != ERROR_SUCCESS) { if (g_Log) @@ -188,19 +240,18 @@ bool ScreensaverInstallerWin32::RestoreOriginalScreensaverSettings() return false; } - const bool originalWasNone = originalExe.empty(); + const bool originalWasNone = backup.exe.empty(); - WriteRegString(hDesktop, "SCRNSAVE.EXE", - originalWasNone ? "" : originalExe); + WriteRegString(hDesktop, "SCRNSAVE.EXE", originalWasNone ? "" : backup.exe); WriteRegString(hDesktop, "ScreenSaveActive", - originalWasNone ? "0" : originalActive); + originalWasNone ? "0" : backup.active); - if (!originalTimeout.empty()) - WriteRegString(hDesktop, "ScreenSaveTimeOut", originalTimeout); + if (!backup.timeout.empty()) + WriteRegString(hDesktop, "ScreenSaveTimeOut", backup.timeout); RegCloseKey(hDesktop); - RefreshScreensaverSettings(!originalWasNone && originalActive == "1"); + RefreshScreensaverSettings(!originalWasNone && backup.active == "1"); if (g_Log) g_Log->Info("RestoreOriginalScreensaverSettings: restored original " @@ -234,6 +285,7 @@ void ScreensaverInstallerWin32::EnsureScreensaverActive( HKEY hKey = nullptr; const LSTATUS desktopRc = RegOpenKeyExA(HKEY_CURRENT_USER, kDesktopKey, 0, KEY_READ | KEY_WRITE, &hKey); + if (desktopRc != ERROR_SUCCESS) { if (g_Log) diff --git a/client_generic/Client/client_win32.h b/client_generic/Client/client_win32.h index ada619e5..e7fee97c 100644 --- a/client_generic/Client/client_win32.h +++ b/client_generic/Client/client_win32.h @@ -383,17 +383,7 @@ class CElectricSheep_Win32 : public CElectricSheep _chdir(m_WorkingDir.c_str()); - // Mirror the Mac behavior: when the user-facing app launches, reassert - // ourselves as the active screensaver if the preference is on. Done - // here (not in the installer) so HKCU resolves to the actual user, not - // the elevated installer's admin token. Skipped for screensaver/preview - // modes — only the desktop app should be writing this preference. - if (m_ScrMode == eWindowed || - m_ScrMode == eWindowed_AllowMultipleInstances || - m_ScrMode == eFullScreenStandalone) - { - ScreensaverInstallerWin32::EnsureScreensaverActive(m_WorkingDir); - } + if (m_ScrMode == eConfig) { @@ -572,9 +562,31 @@ class CElectricSheep_Win32 : public CElectricSheep g_Log->Error("AddDisplay failed for screen %d", dw); }*/ // + + // Save the backup BEFORE CElectricSheep::Startup() reopens settings in + // read-only mode. EnsureScreensaverActive is split into two parts: + // the backup save happens here while settings is still writable, + // and the registry write happens after Startup(). + if (m_ScrMode == eWindowed || + m_ScrMode == eWindowed_AllowMultipleInstances || + m_ScrMode == eFullScreenStandalone) + { + if (g_Settings()->Get("settings.app.keep_screensaver_enabled", + true)) + ScreensaverInstallerWin32::SaveOriginalScreensaverSettingsOnce( + m_WorkingDir); + } + if (CElectricSheep::Startup() == false) return false; + if (m_ScrMode == eWindowed || + m_ScrMode == eWindowed_AllowMultipleInstances || + m_ScrMode == eFullScreenStandalone) + { + ScreensaverInstallerWin32::EnsureScreensaverActive(m_WorkingDir); + } + // Keep the dream rendering while a menu bar popup is open. // Windows enters a modal menu-tracking loop on the main thread when the // user clicks a menu, which blocks our Run() loop entirely. We install