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
76
77
78
79
80
|
// 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
// Desktop modes as state. One file per mode under $XDG_RUNTIME_DIR, holding
// "0" or "1"; a missing file means off. The runtime directory is tmpfs, so a
// reboot resets every mode with no cleanup code here.
//
// The files are the interface, not this singleton: statusctl reads and writes
// them directly so it works while the shell is down, and the FileView watch
// means an external write repaints the drawer with no polling.
Singleton {
id: root
readonly property string dir: Quickshell.env("XDG_RUNTIME_DIR") || "/tmp"
readonly property bool dnd: dndFile.value
// Number of modes currently on. The tile shows this.
readonly property int activeCount: (root.dnd ? 1 : 0)
function setMode(name, on) {
if (name === "dnd") dndFile.write(on);
}
function toggleMode(name) {
if (name === "dnd") dndFile.write(!root.dnd);
}
// One mode file. Reads "1" as true and anything else, including a missing
// file, as false.
component ModeFile: FileView {
id: mf
property bool value: false
// FileView is documented to fire fileChanged on its own setText, so a
// write would re-enter this handler. Comparing before assigning makes
// that harmless: the reparse yields the value just written and the
// binding does not change.
function reparse() {
const t = mf.text().trim();
const v = (t === "1");
if (v !== mf.value) mf.value = v;
}
function write(on) {
const s = on ? "1\n" : "0\n";
mf.value = on;
mf.setText(s);
}
// Both are the documented defaults in 0.3.1, set explicitly because
// the CLI depends on them: statusctl watches close_write,moved_to
// precisely because an atomic write lands as a rename, so a future
// release flipping this default would break the watcher silently.
atomicWrites: true
watchChanges: true
printErrors: false
onFileChanged: mf.reload()
onLoaded: mf.reparse()
// A missing file is the off state, not an error worth logging.
onLoadFailed: mf.value = false
}
ModeFile { id: dndFile; path: root.dir + "/status.dnd" }
}
|