Review everything shipped this weekend, and fix what the reviewers caught
Claude-Session: https://claude.ai/code/session_01Ms2FbjQy31TVf3CEvQhGM8
This commit is contained in:
@@ -97,8 +97,18 @@ Singleton {
|
||||
if (root.transaction === null)
|
||||
return;
|
||||
if (exitCode !== 0) {
|
||||
root.lastError = "Hyprpaper did not apply that background.";
|
||||
root.transaction = null;
|
||||
// Coming back from a video, hyprpaper's service is being
|
||||
// started again underneath us and may not have its socket yet.
|
||||
// That is a "not ready", not a "no", so the handoff is retried
|
||||
// a few times before it counts as a failure.
|
||||
if (root.pendingStillPolicy !== null
|
||||
&& root.stillHandoffAttempts < root.stillHandoffLimit) {
|
||||
stillAfterVideo.restart();
|
||||
return;
|
||||
}
|
||||
root.lastError = "Hyprpaper did not apply that background.";
|
||||
root.abandonStillHandoff();
|
||||
root.schedulePendingHotplug();
|
||||
return;
|
||||
}
|
||||
@@ -116,6 +126,34 @@ Singleton {
|
||||
onExited: (exitCode, exitStatus) => root.finishVerification(exitCode)
|
||||
}
|
||||
|
||||
// `busy` is the gate on every apply path, on refreshActive and on the
|
||||
// slideshow timer, and a transaction is the only thing that clears it. So a
|
||||
// hyprctl that never returns does not fail a wallpaper change — it takes the
|
||||
// whole wallpaper surface out of service for the rest of the session, with
|
||||
// no error to say why. Nothing here is a ten-second operation.
|
||||
Timer {
|
||||
id: transactionWatchdog
|
||||
interval: 10000
|
||||
onTriggered: {
|
||||
if (root.transaction === null)
|
||||
return;
|
||||
root.transaction = null;
|
||||
root.abandonStillHandoff();
|
||||
// Killing the stuck child is part of the release: `busy` counts the
|
||||
// processes too, so leaving one running would keep the latch shut.
|
||||
applyProcess.running = false;
|
||||
verifyProcess.running = false;
|
||||
root.lastError = "Hyprpaper stopped responding while setting that background.";
|
||||
}
|
||||
}
|
||||
|
||||
onTransactionChanged: {
|
||||
if (root.transaction === null)
|
||||
transactionWatchdog.stop();
|
||||
else
|
||||
transactionWatchdog.restart();
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
root.rescan();
|
||||
root.refreshActive();
|
||||
@@ -253,11 +291,17 @@ Singleton {
|
||||
const normalized = root.normalizePolicy(policy);
|
||||
if (normalized === null) {
|
||||
root.lastError = "That wallpaper policy is not valid.";
|
||||
// Nothing will reach schedulePendingHotplug from here, and a flag
|
||||
// left standing turns the next unrelated apply into a surprise
|
||||
// hotplug reapply. The signature change that armed it will arm it
|
||||
// again if a display really did move.
|
||||
root.pendingHotplugReapply = false;
|
||||
return false;
|
||||
}
|
||||
const outputs = root.outputNames();
|
||||
if (outputs.length === 0) {
|
||||
root.lastError = "No display to set a wallpaper on.";
|
||||
root.pendingHotplugReapply = false;
|
||||
return false;
|
||||
}
|
||||
const expected = WallpaperPolicy.effectiveMap(
|
||||
@@ -266,6 +310,7 @@ Singleton {
|
||||
if (Object.keys(expected).length !== outputs.length
|
||||
|| Object.values(expected).some(path => path === "")) {
|
||||
root.lastError = "That wallpaper policy is not valid.";
|
||||
root.pendingHotplugReapply = false;
|
||||
return false;
|
||||
}
|
||||
root.lastError = "";
|
||||
@@ -318,6 +363,7 @@ Singleton {
|
||||
if (!matches) {
|
||||
root.lastError = "Hyprpaper did not confirm that background.";
|
||||
root.transaction = null;
|
||||
root.abandonStillHandoff();
|
||||
root.schedulePendingHotplug();
|
||||
return;
|
||||
}
|
||||
@@ -325,6 +371,7 @@ Singleton {
|
||||
const completed = root.transaction;
|
||||
root.activeByOutput = observed;
|
||||
root.transaction = null;
|
||||
root.abandonStillHandoff();
|
||||
root.lastError = "";
|
||||
if (completed.automatic) {
|
||||
root.slideshowPath = completed.policy.slideshowPath;
|
||||
@@ -413,28 +460,53 @@ Singleton {
|
||||
policy.mode = "single";
|
||||
policy.globalPath = effectivePath;
|
||||
policy.slideshowPath = effectivePath;
|
||||
// Returning from a video: stop mpvpaper first, then give hyprpaper's
|
||||
// service a beat to come back before the transaction talks to it.
|
||||
// Returning from a video: stop mpvpaper first, then offer the policy to
|
||||
// hyprpaper once its service is back, retrying while it is still coming
|
||||
// up rather than betting on one long wait (see attemptStillHandoff).
|
||||
if (VideoWallpaper.active) {
|
||||
VideoWallpaper.stop();
|
||||
root.pendingStillPolicy = policy;
|
||||
root.stillHandoffAttempts = 0;
|
||||
stillAfterVideo.restart();
|
||||
return true;
|
||||
}
|
||||
return root.applyPolicy(policy, true, false);
|
||||
}
|
||||
|
||||
// The still policy waiting for hyprpaper to come back, and how many times it
|
||||
// has been offered to it. A single blind wait used to stand in for this: it
|
||||
// was long enough to be felt on every switch and still short enough to lose
|
||||
// whenever systemd was busy, and losing meant the desktop kept the video's
|
||||
// last frame with an error in Settings and no wallpaper behind it.
|
||||
property var pendingStillPolicy: null
|
||||
property int stillHandoffAttempts: 0
|
||||
readonly property int stillHandoffLimit: 3
|
||||
|
||||
Timer {
|
||||
id: stillAfterVideo
|
||||
interval: 900
|
||||
onTriggered: {
|
||||
if (root.pendingStillPolicy) {
|
||||
root.applyPolicy(root.pendingStillPolicy, true, false);
|
||||
root.pendingStillPolicy = null;
|
||||
}
|
||||
interval: 300
|
||||
onTriggered: root.attemptStillHandoff()
|
||||
}
|
||||
|
||||
function attemptStillHandoff(): void {
|
||||
if (root.pendingStillPolicy === null)
|
||||
return;
|
||||
// The previous attempt's verification may still be winding down.
|
||||
if (root.busy) {
|
||||
stillAfterVideo.restart();
|
||||
return;
|
||||
}
|
||||
root.stillHandoffAttempts += 1;
|
||||
if (!root.applyPolicy(root.pendingStillPolicy, true, false)) {
|
||||
// Rejected before hyprpaper was ever asked — retrying an invalid
|
||||
// policy would only fail identically three more times.
|
||||
root.abandonStillHandoff();
|
||||
}
|
||||
}
|
||||
|
||||
function abandonStillHandoff(): void {
|
||||
root.pendingStillPolicy = null;
|
||||
root.stillHandoffAttempts = 0;
|
||||
}
|
||||
|
||||
function setMode(mode: string): bool {
|
||||
@@ -458,6 +530,7 @@ Singleton {
|
||||
DesktopPreferences.set("videoWallpaperPath", "");
|
||||
VideoWallpaper.stop();
|
||||
root.pendingStillPolicy = policy;
|
||||
root.stillHandoffAttempts = 0;
|
||||
stillAfterVideo.restart();
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user