// Copyright (C) 2026 Danilo M. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License version 2 as // published by the Free Software Foundation. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. pragma Singleton import Quickshell import Quickshell.Io import QtQuick import "island/Controls.js" as Controls // Preferences that must survive a reboot, in one JSON file under the state // home. Only the shell writes it, which is why it is not in ~/.config. // // Nothing is written until the user changes something. A file that fails to // parse reads as the defaults and stays on disk as it is, so a hand edit // with a typo is not replaced by a panel that was merely opened. Singleton { id: root readonly property string path: (Quickshell.env("XDG_STATE_HOME") || Quickshell.env("HOME") + "/.local/state") + "/quickshell/desktop.json" // Visible control tiles, in display order. property var controls: Controls.defaults() // The whole parsed object, so a write keeps keys this version does not // know about. property var data: ({}) function setControls(list) { root.controls = Controls.normalize(list); const out = Object.assign({}, root.data, { controls: root.controls }); root.data = out; file.setText(JSON.stringify(out, null, 2) + "\n"); } function reparse() { let parsed = {}; try { const v = JSON.parse(file.text()); if (v && typeof v === "object" && !Array.isArray(v)) parsed = v; } catch (e) {} root.data = parsed; const next = "controls" in parsed ? Controls.normalize(parsed.controls) : Controls.defaults(); // The watch also fires on our own write; compare so it is a no-op. if (JSON.stringify(next) !== JSON.stringify(root.controls)) root.controls = next; } FileView { id: file path: root.path atomicWrites: true watchChanges: true printErrors: false onFileChanged: reload() onLoaded: root.reparse() // Missing file: the defaults, and nothing written. onLoadFailed: { root.data = {}; root.controls = Controls.defaults(); } } }