pragma Singleton // Snapshots of the settings store. // // The whole desktop configuration is one JSON file, so a backup is a copy and a // restore is an overwrite. Worth exposing now that the settings app changes // real things -- compositor geometry, idle timeouts, the dock -- because being // able to return to a known-good state is what makes experimenting feel safe. // // Restoring rewrites the file underneath the running shell, so the store is // told to re-read afterwards rather than waiting for the next change. import Quickshell import Quickshell.Io import QtQuick import qs.config Singleton { id: root readonly property string helperPath: Quickshell.shellDir + "/scripts/panama-settings-backup" property var snapshots: [] property string lastError: "" property string lastAction: "" readonly property bool busy: listQuery.running || actionRun.running Process { id: listQuery command: [root.helperPath, "list"] stdout: StdioCollector { onStreamFinished: { try { const parsed = JSON.parse(this.text); root.snapshots = Array.isArray(parsed) ? parsed : []; root.lastError = ""; } catch (error) { root.lastError = "Could not read the list of snapshots."; } } } } Process { id: actionRun property bool restoring: false onExited: (exitCode, exitStatus) => { if (exitCode !== 0) { root.lastError = actionRun.restoring ? "That snapshot could not be restored." : "The settings could not be backed up."; return; } root.lastError = ""; root.lastAction = actionRun.restoring ? "restored" : "saved"; if (actionRun.restoring) DesktopPreferences.reload(); root.refresh(); } } Component.onCompleted: root.refresh() function refresh(): void { if (!listQuery.running) listQuery.running = true; } function save(): void { if (actionRun.running) return; actionRun.restoring = false; actionRun.exec([root.helperPath, "save"]); } // The name is matched against the snapshot list rather than trusted, so no // caller-supplied path reaches the helper even though it validates as well. function restore(name: string): bool { if (actionRun.running) return false; if (!root.snapshots.some(snapshot => snapshot.name === name)) { root.lastError = "That snapshot is not in the list."; return false; } actionRun.restoring = true; actionRun.exec([root.helperPath, "restore", name]); return true; } }