178 lines
6.9 KiB
QML
178 lines
6.9 KiB
QML
import Quickshell
|
|
import Quickshell.Io
|
|
import QtQuick
|
|
|
|
import qs.config
|
|
import qs.services
|
|
|
|
ShellRoot {
|
|
id: root
|
|
|
|
property var resetCalls: []
|
|
property var appliedBatches: []
|
|
property bool displayBlocked: false
|
|
|
|
// The held-open safety snapshot: `pendingSnapshotDone` is the completion
|
|
// callback restoreDefaults handed over, waiting for the contract to answer.
|
|
property var pendingSnapshotDone: null
|
|
property bool snapshotRefusesToStart: false
|
|
|
|
function recordReset(name: string): void {
|
|
const next = root.resetCalls.slice();
|
|
next.push(name);
|
|
root.resetCalls = next;
|
|
}
|
|
|
|
Component.onCompleted: {
|
|
// Keep compositor verification entirely inside the isolated harness.
|
|
// Production applyOptions is covered separately by the Hyprland write
|
|
// contract; this seam proves commit/reset routing without changing the
|
|
// desktop that is running the test.
|
|
if (Quickshell.env("PANAMA_SETTINGS_TEST_ISOLATE_COMPOSITOR") === "1") {
|
|
SystemSettings.compositorApplyOverride = function(requested) {
|
|
const batches = root.appliedBatches.slice();
|
|
batches.push(requested);
|
|
root.appliedBatches = batches;
|
|
for (const key in requested)
|
|
DesktopPreferences.set(key, requested[key]);
|
|
return true;
|
|
};
|
|
}
|
|
SystemSettings.displayBusy = function() { return false; };
|
|
SystemSettings.readDisplays = function() { return DesktopPreferences.get("displays"); };
|
|
SystemSettings.protectDisplays = function(value) {
|
|
root.recordReset("display.protect");
|
|
return DesktopPreferences.set("displays", value);
|
|
};
|
|
SystemSettings.setDisplayBlocked = function(blocked) {
|
|
root.recordReset("display.block:" + blocked);
|
|
root.displayBlocked = blocked;
|
|
};
|
|
// The real snapshot is another process reading settings.json, so the
|
|
// stub is held open rather than answering inline: the contract drives
|
|
// its completion by hand and can therefore prove that nothing is wiped
|
|
// in the window between "snapshot started" and "snapshot finished",
|
|
// and that a failed snapshot leaves the stores alone.
|
|
SystemSettings.takeSafetySnapshot = function(done) {
|
|
root.recordReset("snapshot.start");
|
|
if (root.snapshotRefusesToStart)
|
|
return false;
|
|
root.pendingSnapshotDone = done;
|
|
return true;
|
|
};
|
|
SystemSettings.reloadKeybinds = function() { root.recordReset("keybinds.reload"); };
|
|
SystemSettings.keybindsReloading = function() { return false; };
|
|
SystemSettings.applyWallpaper = function(path) { root.recordReset("wallpaper.set:" + path); };
|
|
SystemSettings.regenerateLock = function() { root.recordReset("lock.regenerate"); };
|
|
SystemSettings.lockBusy = function() { return false; };
|
|
}
|
|
|
|
IpcHandler {
|
|
target: "settings-system-test"
|
|
|
|
function refresh(): void { SystemSettings.refresh(); }
|
|
|
|
// One batch, matching how the shell applies persisted policy. Three
|
|
// separate setters would be refused as overlapping writes, since each
|
|
// one is only complete after its value has been read back.
|
|
function apply(autoHdr: bool, vrr: int, directScanout: int): void {
|
|
SystemSettings.applyOptions({
|
|
autoHdr: autoHdr,
|
|
vrrPolicy: vrr,
|
|
directScanoutPolicy: directScanout
|
|
});
|
|
}
|
|
|
|
// Applies an arbitrary batch of schema keys, so the contract can cover
|
|
// every getoption answer shape -- int, bool, float, str, and the css
|
|
// box that gaps read back as -- not just the display policies.
|
|
function applyJson(payload: string): bool {
|
|
return SystemSettings.applyOptions(JSON.parse(payload));
|
|
}
|
|
|
|
// The routing entry point the settings rows use: a compositor-backed
|
|
// key must be applied and verified before it is stored, a local one is
|
|
// written directly. The contract checks both halves.
|
|
function commit(key: string, payload: string): bool {
|
|
return SystemSettings.commitPreference(key, JSON.parse(payload));
|
|
}
|
|
|
|
function stored(key: string): string {
|
|
return JSON.stringify(DesktopPreferences.get(key));
|
|
}
|
|
|
|
function seedHome(): void {
|
|
HomePreferences.favorites = [{ id: "light.contract_probe", alias: "Probe" }];
|
|
HomePreferences.initialized = true;
|
|
}
|
|
|
|
function homeState(): string {
|
|
return JSON.stringify({
|
|
count: HomePreferences.favorites.length,
|
|
initialized: HomePreferences.initialized
|
|
});
|
|
}
|
|
|
|
function restoreDefaults(): bool {
|
|
root.resetCalls = [];
|
|
return SystemSettings.restoreDefaults();
|
|
}
|
|
|
|
// Whether the next safety snapshot is allowed to start at all -- the
|
|
// "a backup is already running" case, which must refuse the reset
|
|
// outright rather than proceed without one.
|
|
function snapshotCanStart(allowed: bool): void {
|
|
root.snapshotRefusesToStart = !allowed;
|
|
}
|
|
|
|
// Answer the snapshot that restoreDefaults is waiting on. Everything
|
|
// the reset does must happen after this and not before.
|
|
function finishSnapshot(success: bool): bool {
|
|
const done = root.pendingSnapshotDone;
|
|
if (!done)
|
|
return false;
|
|
root.pendingSnapshotDone = null;
|
|
root.recordReset("snapshot.finish:" + success);
|
|
done(success);
|
|
return true;
|
|
}
|
|
|
|
function resetPending(): bool {
|
|
return SystemSettings.resetPending;
|
|
}
|
|
|
|
function clearError(): void {
|
|
SystemSettings.lastError = "";
|
|
}
|
|
|
|
function resetState(): string {
|
|
return JSON.stringify({
|
|
calls: root.resetCalls,
|
|
displayBlocked: root.displayBlocked,
|
|
appliedBatches: root.appliedBatches
|
|
});
|
|
}
|
|
|
|
function applyState(): string {
|
|
return JSON.stringify(root.appliedBatches);
|
|
}
|
|
|
|
function panelAllowed(panel: string): bool {
|
|
return SystemSettings.isGnomePanelAllowed(panel);
|
|
}
|
|
|
|
function status(): string {
|
|
return JSON.stringify({
|
|
monitorName: SystemSettings.monitorName,
|
|
monitorDescription: SystemSettings.monitorDescription,
|
|
width: SystemSettings.monitorWidth,
|
|
height: SystemSettings.monitorHeight,
|
|
scale: SystemSettings.monitorScale,
|
|
format: SystemSettings.monitorFormat,
|
|
busy: SystemSettings.busy,
|
|
lastError: SystemSettings.lastError
|
|
});
|
|
}
|
|
}
|
|
}
|