aboutsummaryrefslogtreecommitdiffstats
path: root/desktop/Prefs.qml
blob: fa0dde9738dceb3a99fe9c5098767e68f37cde0e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
// Copyright (C) 2026 Danilo M. <danix@danix.xyz>
//
// 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

// 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"

    // The public IP the user pinned from the performance panel; "" for none.
    property string pinnedIp: ""

    // The whole parsed object, so a write keeps keys this version does not
    // know about.
    property var doc: ({})

    function setPinnedIp(ip) {
        if (ip === root.pinnedIp) return;
        root.pinnedIp = ip;
        const perf = Object.assign({}, root.doc.perf, { pinnedIp: ip });
        root.write(Object.assign({}, root.doc, { perf: perf }));
    }

    function write(out) {
        root.doc = 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.doc = parsed;
        const pin = parsed.perf && typeof parsed.perf.pinnedIp === "string" ? parsed.perf.pinnedIp : "";
        if (pin !== root.pinnedIp) root.pinnedIp = pin;
    }

    FileView {
        id: file
        path: root.path
        atomicWrites: true
        watchChanges: true
        printErrors: false
        // printErrors is off for the missing-file read; a failed write still
        // has to be heard, or the pin silently vanishes at restart.
        onSaveFailed: error => console.warn("Prefs: writing", root.path, "failed:", error)
        onFileChanged: reload()
        onLoaded: root.reparse()
        // Missing file: the defaults, and nothing written.
        onLoadFailed: { root.doc = {}; root.pinnedIp = ""; }
    }
}