Close display verification races
This commit is contained in:
@@ -38,6 +38,9 @@ Singleton {
|
||||
property bool revertQueued: false
|
||||
property var revertExpected: null
|
||||
property string revertReason: ""
|
||||
property bool revertVerificationActive: false
|
||||
property int operationGeneration: 0
|
||||
property int revertGeneration: -1
|
||||
property int secondsLeft: 0
|
||||
|
||||
readonly property bool awaitingConfirmation: root.pendingOutput !== ""
|
||||
@@ -63,13 +66,16 @@ Singleton {
|
||||
|
||||
Process {
|
||||
id: query
|
||||
property int generation: 0
|
||||
command: ["hyprctl", "-j", "monitors"]
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: root.parse(this.text)
|
||||
onStreamFinished: root.parse(this.text, query.generation)
|
||||
}
|
||||
onExited: (exitCode, exitStatus) => {
|
||||
if (exitCode !== 0)
|
||||
root.lastError = "Could not read the connected displays.";
|
||||
if (root.revertQueued && !applyRun.running && root.awaitingConfirmation)
|
||||
root.performRevert();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,6 +102,7 @@ Singleton {
|
||||
onExited: (exitCode, exitStatus) => {
|
||||
// Exit status is advisory only. Hyprland's Lua bridge can report
|
||||
// success without applying a value, so exact readback decides.
|
||||
root.revertVerificationActive = true;
|
||||
revertVerifyTimer.attempts = 0;
|
||||
revertVerifyTimer.restart();
|
||||
}
|
||||
@@ -104,11 +111,13 @@ Singleton {
|
||||
Component.onCompleted: root.refresh()
|
||||
|
||||
function refresh(): void {
|
||||
if (!query.running)
|
||||
if (!query.running) {
|
||||
query.generation = root.operationGeneration;
|
||||
query.running = true;
|
||||
}
|
||||
}
|
||||
|
||||
function parse(text: string): void {
|
||||
function parse(text: string, generation: int): void {
|
||||
try {
|
||||
const raw = JSON.parse(text);
|
||||
root.monitors = raw.map(monitor => {
|
||||
@@ -129,6 +138,9 @@ Singleton {
|
||||
mode: current?.mode ?? `${width}x${height}@${refreshRate}`,
|
||||
scale: monitor.scale ?? 1,
|
||||
transform: monitor.transform ?? 0,
|
||||
currentFormat: monitor.currentFormat ?? "",
|
||||
colorPreset: monitor.colorManagementPreset ?? "",
|
||||
vrr: monitor.vrr === true,
|
||||
modes: modes
|
||||
};
|
||||
});
|
||||
@@ -137,9 +149,13 @@ Singleton {
|
||||
root.pendingVerified = true;
|
||||
verifyTimer.stop();
|
||||
root.lastError = "";
|
||||
} else if (root.revertExpected
|
||||
} else if (root.revertVerificationActive
|
||||
&& generation === root.revertGeneration
|
||||
&& root.revertExpected
|
||||
&& root.matchesRequest(root.monitorNamed(root.revertExpected.output), root.revertExpected)) {
|
||||
revertVerifyTimer.stop();
|
||||
root.revertVerificationActive = false;
|
||||
root.revertGeneration = -1;
|
||||
root.revertExpected = null;
|
||||
if (root.revertReason === "")
|
||||
root.lastError = "";
|
||||
@@ -240,6 +256,13 @@ Singleton {
|
||||
&& monitor.transform === requested.transform;
|
||||
}
|
||||
|
||||
function modeIsCurrent(monitor: var, candidate: var): bool {
|
||||
return !!monitor && !!candidate
|
||||
&& monitor.width === candidate.width
|
||||
&& monitor.height === candidate.height
|
||||
&& Math.abs(monitor.refreshRate - candidate.refresh) < 0.01;
|
||||
}
|
||||
|
||||
// Applies immediately and starts the countdown. Nothing is stored yet: the
|
||||
// settings file is only written by confirm().
|
||||
function apply(output: string, mode: string, scale: real, transform: int): bool {
|
||||
@@ -275,6 +298,7 @@ Singleton {
|
||||
scale: monitor.scale,
|
||||
transform: monitor.transform
|
||||
};
|
||||
root.operationGeneration++;
|
||||
root.pendingRequested = {
|
||||
output: output,
|
||||
mode: mode,
|
||||
@@ -348,7 +372,7 @@ Singleton {
|
||||
root.revertReason = message;
|
||||
if (message !== "")
|
||||
root.lastError = message;
|
||||
if (applyRun.running) {
|
||||
if (applyRun.running || query.running) {
|
||||
root.revertQueued = true;
|
||||
return;
|
||||
}
|
||||
@@ -357,7 +381,10 @@ Singleton {
|
||||
|
||||
function performRevert(): void {
|
||||
const previous = root.pendingPrevious;
|
||||
root.operationGeneration++;
|
||||
root.revertGeneration = root.operationGeneration;
|
||||
root.revertExpected = previous;
|
||||
root.revertVerificationActive = false;
|
||||
root.clearPending();
|
||||
if (previous) {
|
||||
revertRun.exec(["hyprctl", "eval",
|
||||
@@ -405,6 +432,8 @@ Singleton {
|
||||
attempts++;
|
||||
if (attempts > 25) {
|
||||
stop();
|
||||
root.revertVerificationActive = false;
|
||||
root.revertGeneration = -1;
|
||||
root.revertExpected = null;
|
||||
root.revertReason = "";
|
||||
root.lastError = "The previous display setting could not be verified. Open Displays and restore it manually.";
|
||||
|
||||
Reference in New Issue
Block a user