[feat] remember remote display resolutions across connections

This commit is contained in:
dijunkun
2026-11-11 14:14:00 +08:00
parent 17b4db25fb
commit a862bf6b35
15 changed files with 414 additions and 67 deletions
+15 -1
View File
@@ -52,6 +52,20 @@ struct DisplayResolutionChange {
bool accepted = false;
};
// Persist the native identity, never the display's position in a session.
struct DisplayResolutionPreference {
std::string display_key;
DisplayResolution resolution;
};
inline bool ValidDisplayResolutionPreference(
const DisplayResolutionPreference &preference) {
return !preference.display_key.empty() &&
preference.display_key.size() <= 1024 &&
preference.display_key.find('\0') == std::string::npos &&
ValidDisplayResolution(preference.resolution);
}
inline bool SupportsDisplayResolution(const DisplayResolutionInfo &display,
const DisplayResolutionChange &change) {
return display.display_id == change.display_id &&
@@ -62,4 +76,4 @@ inline bool SupportsDisplayResolution(const DisplayResolutionInfo &display,
} // namespace crossdesk
#endif
#endif
@@ -0,0 +1,58 @@
/*
* @Author: DI JUNKUN
* @Date: 2026-11-11
* Copyright (c) 2026 by DI JUNKUN, All Rights Reserved.
*/
#ifndef _DISPLAY_RESOLUTION_PREFERENCES_H_
#define _DISPLAY_RESOLUTION_PREFERENCES_H_
#include <nlohmann/json.hpp>
#include "display_resolution.h"
namespace crossdesk {
inline nlohmann::json DisplayResolutionPreferencesJson(
const std::vector<DisplayResolutionPreference> &preferences) {
auto result = nlohmann::json::array();
for (const auto &preference : preferences)
result.push_back({{"display_key", preference.display_key},
{"width", preference.resolution.width},
{"height", preference.resolution.height}});
return result;
}
inline bool ReadDisplayResolutionPreferences(
const nlohmann::json &values,
std::vector<DisplayResolutionPreference> &result) {
std::vector<DisplayResolutionPreference> parsed;
if (!values.is_array() || values.size() > kMaxResolutionDisplays)
return false;
try {
for (const auto &value : values) {
const auto &width = value.at("width");
const auto &height = value.at("height");
if (!width.is_number_integer() || !height.is_number_integer() ||
width < 1 || width > 32768 || height < 1 || height > 32768)
return false;
DisplayResolutionPreference preference{
value.at("display_key").get<std::string>(),
{width.get<int>(), height.get<int>()}};
if (!ValidDisplayResolutionPreference(preference) ||
std::any_of(parsed.begin(), parsed.end(), [&](const auto &existing) {
return existing.display_key == preference.display_key;
}))
return false;
parsed.push_back(std::move(preference));
}
} catch (const nlohmann::json::exception &) {
return false;
}
result = std::move(parsed);
return true;
}
} // namespace crossdesk
#endif
+2
View File
@@ -223,6 +223,8 @@ struct RemoteAction {
// Optional host information extension, also returned with resolution status.
std::vector<DisplayResolutionInfo> display_resolutions;
DisplayResolutionChange resolution_change;
// Controller preferences sent with its initial host information.
std::vector<DisplayResolutionPreference> preferred_display_resolutions;
std::string to_json() const;
bool from_json(const std::string& json_string);
+10
View File
@@ -1,4 +1,5 @@
#include <remote_action.h>
#include <display_resolution_preferences.h>
#include <algorithm>
#include <cstdio>
@@ -339,6 +340,9 @@ std::string RemoteAction::ToJson(const RemoteAction& action) {
if (!action.display_resolutions.empty())
object["host_info"]["display_resolutions"] =
DisplayResolutionsJson(action.display_resolutions);
if (!action.preferred_display_resolutions.empty())
object["host_info"]["preferred_display_resolutions"] =
DisplayResolutionPreferencesJson(action.preferred_display_resolutions);
break;
}
case ControlType::invalid:
@@ -354,6 +358,7 @@ bool RemoteAction::FromJson(const std::string& json_string,
try {
const json object = json::parse(json_string);
output.display_resolutions.clear();
output.preferred_display_resolutions.clear();
output.type = static_cast<ControlType>(object.at("type").get<int>());
switch (output.type) {
case ControlType::display_resolution:
@@ -549,6 +554,11 @@ bool RemoteAction::FromJson(const std::string& json_string,
ResetHostInfo(output.i);
owns_host_info = true;
const auto& host_info_object = object.at("host_info");
// A corrupt optional preference must not prevent a connection.
if (const auto preferences = host_info_object.find("preferred_display_resolutions");
preferences != host_info_object.end())
ReadDisplayResolutionPreferences(*preferences,
output.preferred_display_resolutions);
if (const auto modes = host_info_object.find("display_resolutions");
modes != host_info_object.end() &&
!ReadDisplayResolutions(*modes, output.display_resolutions)) return false;