Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
302 changes: 271 additions & 31 deletions client_generic/Client/ScreensaverInstallerWin32.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
#include <windows.h>
#include <shlwapi.h>

#include <cstdlib>
#include <string>
#include <vector>

#include "Log.h"
#include "Settings.h"
Expand All @@ -14,69 +16,312 @@

namespace
{
constexpr const char* kDesktopKey = "Control Panel\\Desktop";
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)
{
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<LPBYTE>(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<const BYTE*>(value.c_str()),
static_cast<DWORD>(value.size() + 1));
const LSTATUS rc =
RegSetValueExA(hKey, valueName, 0, REG_SZ,
reinterpret_cast<const BYTE*>(value.c_str()),
static_cast<DWORD>(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;
}

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);
}

std::vector<std::string> SplitLines(const std::string& value)
{
std::vector<std::string> lines;
std::string current;

for (char c : value)
{
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<std::string> 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<long>(desktopRc));
return;
}

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(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");
return;
}

SaveBackupToSettings(backup);

if (g_Log)
g_Log->Info("SaveOriginalScreensaverSettingsOnce: saved backup "
"exe='%s', active='%s', timeout='%s'",
backup.exe.c_str(), backup.active.c_str(),
backup.timeout.c_str());
}

bool ScreensaverInstallerWin32::RestoreOriginalScreensaverSettings()
{
const ScreensaverBackup backup = ReadBackupFromSettings();

if (!backup.valid)
{
if (g_Log)
g_Log->Warning("RestoreOriginalScreensaverSettings: no valid "
"screensaver backup in settings");
return false;
}

if (g_Log)
g_Log->Info("RestoreOriginalScreensaverSettings: restoring exe='%s', "
"active='%s', timeout='%s'",
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)
g_Log->Warning("RestoreOriginalScreensaverSettings: cannot open "
"Desktop key (%ld)",
static_cast<long>(desktopRc));
return false;
}

const bool originalWasNone = backup.exe.empty();

WriteRegString(hDesktop, "SCRNSAVE.EXE", originalWasNone ? "" : backup.exe);
WriteRegString(hDesktop, "ScreenSaveActive",
originalWasNone ? "0" : backup.active);

if (!backup.timeout.empty())
WriteRegString(hDesktop, "ScreenSaveTimeOut", backup.timeout);

RegCloseKey(hDesktop);

RefreshScreensaverSettings(!originalWasNone && backup.active == "1");

if (g_Log)
g_Log->Info("RestoreOriginalScreensaverSettings: restored original "
"screensaver settings");

return true;
}

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());
if (g_Log)
g_Log->Warning("EnsureScreensaverActive: %s missing, skipping",
scrPath.c_str());
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 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<long>(rc));
if (g_Log)
g_Log->Warning(
"EnsureScreensaverActive: cannot open Desktop key (%ld)",
static_cast<long>(desktopRc));
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 (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 (g_Log)
g_Log->Info(
"EnsureScreensaverActive: SCRNSAVE.EXE '%s' -> '%s'",
currentScr.c_str(), scrPath.c_str());
}
}

Expand All @@ -85,22 +330,17 @@ void ScreensaverInstallerWin32::EnsureScreensaverActive(const std::string& worki
if (WriteRegString(hKey, "ScreenSaveActive", "1"))
{
changed = true;
if (g_Log) g_Log->Info("EnsureScreensaverActive: ScreenSaveActive '%s' -> '1'",
currentActive.c_str());
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<LPARAM>("Windows"),
SMTO_ABORTIFHUNG, 1000, nullptr);
}
RefreshScreensaverSettings(true);
}

#endif // WIN32
#endif
5 changes: 4 additions & 1 deletion client_generic/Client/ScreensaverInstallerWin32.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -18,4 +21,4 @@ namespace ScreensaverInstallerWin32
void EnsureScreensaverActive(const std::string& workingDir);
} // namespace ScreensaverInstallerWin32

#endif // WIN32
#endif // WIN32
1 change: 1 addition & 0 deletions client_generic/Client/SettingsDialogWin32.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
Loading