diff options
| l--------- | desktop/Status.qml | 1 | ||||
| -rw-r--r-- | shared/Status.qml | 80 |
2 files changed, 81 insertions, 0 deletions
diff --git a/desktop/Status.qml b/desktop/Status.qml new file mode 120000 index 0000000..e7188a3 --- /dev/null +++ b/desktop/Status.qml @@ -0,0 +1 @@ +../shared/Status.qml
\ No newline at end of file diff --git a/shared/Status.qml b/shared/Status.qml new file mode 100644 index 0000000..03194e7 --- /dev/null +++ b/shared/Status.qml @@ -0,0 +1,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" } +} |
