feat(display): Configure display device based on user config (#3441)

This commit is contained in:
Lukas Senionis 2025-01-08 03:40:48 +02:00 committed by GitHub
commit 76bea8acb9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 1690 additions and 95 deletions

View file

@ -170,6 +170,14 @@
"install_steam_audio_drivers": "enabled",
"adapter_name": "",
"output_name": "",
"dd_configuration_option": "verify_only",
"dd_resolution_option": "auto",
"dd_manual_resolution": "",
"dd_refresh_rate_option": "auto",
"dd_manual_refresh_rate": "",
"dd_hdr_option": "auto",
"dd_config_revert_delay": 3000,
"dd_wa_hdr_toggle": "disabled",
"min_fps_factor": 1,
},
},

View file

@ -74,6 +74,11 @@ const config = ref(props.config)
:config="config"
/>
<DisplayDeviceOptions
:platform="platform"
:config="config"
/>
<!-- Display Modes -->
<DisplayModesSettings
:platform="platform"

View file

@ -1,45 +1,127 @@
<script setup>
import { ref } from 'vue'
import { $tp } from '../../../platform-i18n'
import PlatformLayout from '../../../PlatformLayout.vue'
import Checkbox from "../../../Checkbox.vue";
const props = defineProps({
platform: String,
config: Object,
display_mode_remapping: Array
config: Object
})
const config = ref(props.config)
const display_mode_remapping = ref(props.display_mode_remapping)
// TODO: Sample for use in PR #2032
function getRemappingType()
{
// Assuming here that at least one setting is set to "automatic"
if (config.value.resolution_change !== 'automatic') {
return "refresh_rate_only";
}
if (config.value.refresh_rate_change !== 'automatic') {
return "resolution_only";
}
return "";
}
function addRemapping(type) {
let template = {
type: type,
received_resolution: "",
received_fps: "",
final_resolution: "",
final_refresh_rate: "",
};
display_mode_remapping.value.push(template);
}
</script>
<template>
<div class="mb-3">
<!-- TODO: Implement on PR #2032 -->
</div>
<PlatformLayout :platform="platform">
<template #windows>
<div class="mb-3 accordion">
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button" type="button" data-bs-toggle="collapse"
data-bs-target="#panelsStayOpen-collapseOne">
{{ $t('config.dd_options_header') }}
</button>
</h2>
<div id="panelsStayOpen-collapseOne" class="accordion-collapse collapse show"
aria-labelledby="panelsStayOpen-headingOne">
<div class="accordion-body">
<!-- Configuration option -->
<div class="mb-3">
<label for="dd_configuration_option" class="form-label">
{{ $t('config.dd_config_label') }}
</label>
<select id="dd_configuration_option" class="form-select" v-model="config.dd_configuration_option">
<option value="disabled">{{ $t('_common.disabled') }}</option>
<option value="verify_only">{{ $t('config.dd_config_verify_only') }}</option>
<option value="ensure_active">{{ $t('config.dd_config_ensure_active') }}</option>
<option value="ensure_primary">{{ $t('config.dd_config_ensure_primary') }}</option>
<option value="ensure_only_display">{{ $t('config.dd_config_ensure_only_display') }}</option>
</select>
</div>
<!-- Resolution option -->
<div class="mb-3" v-if="config.dd_configuration_option !== 'disabled'">
<label for="dd_resolution_option" class="form-label">
{{ $t('config.dd_resolution_option') }}
</label>
<select id="dd_resolution_option" class="form-select" v-model="config.dd_resolution_option">
<option value="disabled">{{ $t('config.dd_resolution_option_disabled') }}</option>
<option value="auto">{{ $t('config.dd_resolution_option_auto') }}</option>
<option value="manual">{{ $t('config.dd_resolution_option_manual') }}</option>
</select>
<div class="form-text"
v-if="config.dd_resolution_option === 'auto' || config.dd_resolution_option === 'manual'">
{{ $t('config.dd_resolution_option_ogs_desc') }}
</div>
<!-- Manual resolution -->
<div class="mt-2 ps-4" v-if="config.dd_resolution_option === 'manual'">
<div class="form-text">
{{ $t('config.dd_resolution_option_manual_desc') }}
</div>
<input type="text" class="form-control" id="dd_manual_resolution" placeholder="2560x1440"
v-model="config.dd_manual_resolution" />
</div>
</div>
<!-- Refresh rate option -->
<div class="mb-3" v-if="config.dd_configuration_option !== 'disabled'">
<label for="dd_refresh_rate_option" class="form-label">
{{ $t('config.dd_refresh_rate_option') }}
</label>
<select id="dd_refresh_rate_option" class="form-select" v-model="config.dd_refresh_rate_option">
<option value="disabled">{{ $t('config.dd_refresh_rate_option_disabled') }}</option>
<option value="auto">{{ $t('config.dd_refresh_rate_option_auto') }}</option>
<option value="manual">{{ $t('config.dd_refresh_rate_option_manual') }}</option>
</select>
<!-- Manual refresh rate -->
<div class="mt-2 ps-4" v-if="config.dd_refresh_rate_option === 'manual'">
<div class="form-text">
{{ $t('config.dd_refresh_rate_option_manual_desc') }}
</div>
<input type="text" class="form-control" id="dd_manual_refresh_rate" placeholder="59.9558"
v-model="config.dd_manual_refresh_rate" />
</div>
</div>
<!-- HDR option -->
<div class="mb-3" v-if="config.dd_configuration_option !== 'disabled'">
<label for="dd_hdr_option" class="form-label">
{{ $t('config.dd_hdr_option') }}
</label>
<select id="dd_hdr_option" class="mb-3 form-select" v-model="config.dd_hdr_option">
<option value="disabled">{{ $t('config.dd_hdr_option_disabled') }}</option>
<option value="auto">{{ $t('config.dd_hdr_option_auto') }}</option>
</select>
<!-- HDR toggle -->
<Checkbox id="dd_wa_hdr_toggle"
locale-prefix="config"
v-model="config.dd_wa_hdr_toggle"
default="false"
></Checkbox>
</div>
<!-- Config revert delay -->
<div class="mb-3" v-if="config.dd_configuration_option !== 'disabled'">
<label for="dd_config_revert_delay" class="form-label">
{{ $t('config.dd_config_revert_delay') }}
</label>
<input type="text" class="form-control" id="dd_config_revert_delay" placeholder="3000"
v-model="config.dd_config_revert_delay" />
<div class="form-text">
{{ $t('config.dd_config_revert_delay_desc') }}
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<template #linux>
</template>
<template #macos>
</template>
</PlatformLayout>
</template>

View file

@ -152,6 +152,30 @@
"controller_desc": "Allows guests to control the host system with a gamepad / controller",
"credentials_file": "Credentials File",
"credentials_file_desc": "Store Username/Password separately from Sunshine's state file.",
"dd_config_ensure_active": "Activate the display automatically",
"dd_config_ensure_only_display": "Deactivate other displays and activate only the specified display",
"dd_config_ensure_primary": "Activate the display automatically and make it a primary display",
"dd_config_label": "Device configuration",
"dd_config_revert_delay": "Config revert delay",
"dd_config_revert_delay_desc": "Additional delay in milliseconds to wait before reverting configuration when the app has been closed or the last session terminated. Main purpose is to provide a smoother transition when quickly switching between apps.",
"dd_config_verify_only": "Verify that the display is enabled (default)",
"dd_hdr_option": "HDR",
"dd_hdr_option_auto": "Switch on/off the HDR mode as requested by the client (default)",
"dd_hdr_option_disabled": "Do not change HDR settings",
"dd_options_header": "Advanced display device options",
"dd_refresh_rate_option": "Refresh rate",
"dd_refresh_rate_option_auto": "Use FPS value provided by the client (default)",
"dd_refresh_rate_option_disabled": "Do not change refresh rate",
"dd_refresh_rate_option_manual": "Use manually entered refresh rate",
"dd_refresh_rate_option_manual_desc": "Enter the refresh rate to be used",
"dd_resolution_option": "Resolution",
"dd_resolution_option_auto": "Use resolution provided by the client (default)",
"dd_resolution_option_disabled": "Do not change resolution",
"dd_resolution_option_manual": "Use manually entered resolution",
"dd_resolution_option_manual_desc": "Enter the resolution to be used",
"dd_resolution_option_ogs_desc": "\"Optimize game settings\" option must be enabled on the Moonlight client for this to work.",
"dd_wa_hdr_toggle_desc": "When using virtual display device as for streaming, it might display incorrect HDR color. With this option enabled, Sunshine will try to mitigate this issue.",
"dd_wa_hdr_toggle": "Enable high-contrast workaround for HDR",
"ds4_back_as_touchpad_click": "Map Back/Select to Touchpad Click",
"ds4_back_as_touchpad_click_desc": "When forcing DS4 emulation, map Back/Select to Touchpad Click",
"encoder": "Force a Specific Encoder",
@ -379,6 +403,10 @@
"third_party_notice": "Third Party Notice"
},
"troubleshooting": {
"dd_reset": "Reset Persistent Display Device Settings",
"dd_reset_desc": "If Sunshine is stuck trying to restore the changed display device settings, you can reset the settings and proceed to restore the display state manually.",
"dd_reset_error": "Error while resetting persistence!",
"dd_reset_success": "Success resetting persistence!",
"force_close": "Force Close",
"force_close_desc": "If Moonlight complains about an app currently running, force closing the app should fix the issue.",
"force_close_error": "Error while closing Application",

View file

@ -75,6 +75,25 @@
</div>
</div>
</div>
<!-- Reset persistent display device settings -->
<div class="card p-2 my-4" v-if="platform === 'windows'">
<div class="card-body">
<h2 id="dd_reset">{{ $t('troubleshooting.dd_reset') }}</h2>
<br>
<p style="white-space: pre-line">{{ $t('troubleshooting.dd_reset_desc') }}</p>
<div class="alert alert-success" v-if="ddResetStatus === true">
{{ $t('troubleshooting.dd_reset_success') }}
</div>
<div class="alert alert-danger" v-if="ddResetStatus === false">
{{ $t('troubleshooting.dd_reset_error') }}
</div>
<div>
<button class="btn btn-warning" :disabled="ddResetPressed" @click="ddResetPersistence">
{{ $t('troubleshooting.dd_reset') }}
</button>
</div>
</div>
</div>
<!-- Unpair Clients -->
<div class="card my-4">
<div class="card-body">
@ -141,11 +160,14 @@
clients: [],
closeAppPressed: false,
closeAppStatus: null,
ddResetPressed: false,
ddResetStatus: null,
logs: 'Loading...',
logFilter: null,
logInterval: null,
restartPressed: false,
showApplyMessage: false,
platform: "",
unpairAllPressed: false,
unpairAllStatus: null,
};
@ -159,6 +181,12 @@
}
},
created() {
fetch("/api/config")
.then((r) => r.json())
.then((r) => {
this.platform = r.platform;
});
this.logInterval = setInterval(() => {
this.refreshLogs();
}, 5000);
@ -236,6 +264,18 @@
method: "POST",
});
},
ddResetPersistence() {
this.ddResetPressed = true;
fetch("/api/reset-display-device-persistence", { method: "POST" })
.then((r) => r.json())
.then((r) => {
this.ddResetPressed = false;
this.ddResetStatus = r.status.toString() === "true";
setTimeout(() => {
this.ddResetStatus = null;
}, 5000);
});
},
},
});