[feat] remember remote display resolutions across connections

This commit is contained in:
dijunkun committed 2026-11-11 14:14:00 +08:00
1 parent 17b4db25fb
commit a862bf6b35
15 files changed
+414 -67

No files matched your search

@@ -253,6 +253,8 @@ int SessionDeviceManager::InitializeScreenCapturer() {
uint64_t send_errors = 0;
for (const std::string &remote_id : connected_remote_ids) {
if (owner_.managed_host_frontend_ && remote_id.rfind("lan/", 0) != 0) continue;
// Warm/shared capture may already be running for another controller.
if (!owner_.DisplayResolutionsReadyForCapture(remote_id)) continue;
if (!owner_.preview_subscriptions_.ShouldSend(remote_id, now_time,
stream_id)) continue;
if (owner_.WithController(
@@ -693,6 +695,9 @@ void SessionDeviceManager::PushAudio(const std::string& remote_id,
}
void SessionDeviceManager::UpdateInteractions() {
// Restore the previous session's modes and apply the new controller's saved
// selections before starting capture or allowing an early input return.
owner_.HandleDisplayResolutionChanges();
// Release even when pending remote-input cleanup makes this tick return early.
UpdateScreenSharingPower();
#ifdef _WIN32
@@ -720,7 +725,8 @@ void SessionDeviceManager::UpdateInteractions() {
if (owner_.start_screen_capturer_ && !owner_.screen_capturer_is_started_) {
const auto now = std::chrono::steady_clock::now();
if (now >= next_capture_start_retry_) {
if (now >= next_capture_start_retry_ &&
owner_.DisplayResolutionsReadyForCapture()) {
next_capture_start_retry_ = now + std::chrono::seconds(1);
if (StartScreenCapturer() == 0) {
owner_.screen_capturer_is_started_ = true;
@@ -799,7 +805,6 @@ void SessionDeviceManager::UpdateInteractions() {
}
owner_.keyboard_.CheckRemoteTimeouts();
owner_.HandleDisplayResolutionChanges();
}
void SessionDeviceManager::DrainCapturedKeyboardInput() {
@@ -0,0 +1,77 @@
#include "remote_resolution_store.h"
#include <fstream>
#include <display_resolution_preferences.h>
#include "common/private_file.h"
namespace crossdesk {
namespace {
constexpr std::uintmax_t kMaxStoreBytes = 8 * 1024 * 1024;
}
bool RemoteResolutionStore::Load(const std::filesystem::path &path) {
std::lock_guard lock(mutex_);
path_ = path;
devices_.clear();
try {
if (!std::filesystem::exists(path_)) return true;
if (std::filesystem::file_size(path_) > kMaxStoreBytes) return false;
std::ifstream input(path_, std::ios::binary);
const auto json = nlohmann::json::parse(input);
if (json.at("version") != 1 || !json.at("devices").is_object())
return false;
for (const auto &[device, values] : json.at("devices").items()) {
std::vector<DisplayResolutionPreference> preferences;
if (!device.empty() && ReadDisplayResolutionPreferences(values, preferences))
devices_.emplace(device, std::move(preferences));
}
return true;
} catch (const std::exception &) {
return false;
}
}
std::vector<DisplayResolutionPreference>
RemoteResolutionStore::Get(const std::string &device) const {
std::lock_guard lock(mutex_);
const auto found = devices_.find(device);
return found == devices_.end() ? std::vector<DisplayResolutionPreference>{}
: found->second;
}
bool RemoteResolutionStore::Remember(
const std::string &device, const DisplayResolutionPreference &preference) {
if (device.empty() || !ValidDisplayResolutionPreference(preference))
return false;
std::lock_guard lock(mutex_);
if (path_.empty()) return false;
auto updated = devices_;
auto &preferences = updated[device];
const auto found = std::find_if(preferences.begin(), preferences.end(),
[&](const auto &saved) { return saved.display_key == preference.display_key; });
if (found != preferences.end()) {
if (found->resolution == preference.resolution) return true;
*found = preference;
} else {
if (preferences.size() >= kMaxResolutionDisplays)
preferences.erase(preferences.begin());
preferences.push_back(preference);
}
try {
nlohmann::json json{{"version", 1}, {"devices", nlohmann::json::object()}};
for (const auto &[id, saved] : updated)
json["devices"][id] = DisplayResolutionPreferencesJson(saved);
const auto text = json.dump(2);
if (text.size() > kMaxStoreBytes) return false;
private_file::EnsureDirectory(path_.parent_path());
private_file::Write(path_, text);
devices_ = std::move(updated);
return true;
} catch (const std::exception &) {
return false;
}
}
} // namespace crossdesk
@@ -0,0 +1,33 @@
/*
* @Author: DI JUNKUN
* @Date: 2026-11-11
* Copyright (c) 2026 by DI JUNKUN, All Rights Reserved.
*/
#ifndef _REMOTE_RESOLUTION_STORE_H_
#define _REMOTE_RESOLUTION_STORE_H_
#include <filesystem>
#include <map>
#include <mutex>
#include <display_resolution.h>
namespace crossdesk {
class RemoteResolutionStore {
public:
bool Load(const std::filesystem::path &path);
std::vector<DisplayResolutionPreference> Get(const std::string &device) const;
bool Remember(const std::string &device,
const DisplayResolutionPreference &preference);
private:
mutable std::mutex mutex_;
std::filesystem::path path_;
std::map<std::string, std::vector<DisplayResolutionPreference>> devices_;
};
} // namespace crossdesk
#endif