diff options
Diffstat (limited to 'shared')
| -rw-r--r-- | shared/Notify.qml | 5 | ||||
| -rw-r--r-- | shared/Status.qml | 97 |
2 files changed, 3 insertions, 99 deletions
diff --git a/shared/Notify.qml b/shared/Notify.qml index a85ed6a..836dc21 100644 --- a/shared/Notify.qml +++ b/shared/Notify.qml @@ -42,9 +42,8 @@ Singleton { // Read from the status registry's own file rather than from the Status // singleton. The renderers only read DND; referencing Status here would - // instantiate it, and its onPresentationChanged writes status.dnd and - // shells out to breaktimer.sh, side effects a read-only consumer must not - // trigger. The file is the interface, so reading it directly is the same + // instantiate it, and its onPresentationChanged writes status.dnd, a side + // effect a read-only consumer must not trigger. The file is the interface, so reading it directly is the same // value with none of the write side. property bool dnd: false diff --git a/shared/Status.qml b/shared/Status.qml index 523ea7d..f32cd35 100644 --- a/shared/Status.qml +++ b/shared/Status.qml @@ -44,23 +44,6 @@ Singleton { // drawer's view of it. readonly property bool quiet: quietFile.value - // Breaktimer, read only. The daemon publishes these three files and owns - // them; the shell calls verbs and never writes them, because the daemon - // loop rewrites state and phase on every transition. - // - // A stopped daemon is read from the state file rather than probed: both - // paths that end it, stop_daemon and the cleanup trap, write "stopped" - // there. A daemon lost to SIGKILL leaves a stale "running" and the drawer - // shows a frozen countdown, which is a visible wrong answer the start - // button resolves. That is cheaper than a liveness probe per repaint. - readonly property string btState: btStateFile.value - readonly property string btPhase: btPhaseFile.value - readonly property int btRemain: btRemainFile.value - - readonly property bool btRunning: root.btState === "running" - || root.btState === "paused" - readonly property bool btPaused: root.btState === "paused" - readonly property int activeCount: (root.dnd ? 1 : 0) + (root.presentation ? 1 : 0) + (root.nolock ? 1 : 0) + (root.quiet ? 1 : 0) @@ -144,49 +127,17 @@ Singleton { root.setMode("dnd", true); root.setMode("nolock", true); root.setMode("quiet", true); - // pause/resume write the state file whether or not a daemon - // runs, so send the verb only when one exists. - if (root.btRunning) root.runBreaktimer("pause"); } else { root.setMode("dnd", root.dndBeforePresentation); root.setMode("nolock", root.nolockBeforePresentation); root.setMode("quiet", root.quietBeforePresentation); - if (root.btRunning) root.runBreaktimer("resume"); - } - } - - function runBreaktimer(verb) { - breakProc.command = ["breaktimer.sh", verb]; - breakProc.running = false; - breakProc.running = true; - } - - // Seconds as m:ss. The daemon rewrites the remaining seconds every five - // seconds, its tick, so this counts down in five second steps and does - // not interpolate: a local one second timer would be a second clock - // drifting against the first, correcting itself with a visible jump, and - // it would keep ticking while the daemon is frozen outside the work - // window or paused. - function btCountdown() { - const s = Math.max(0, root.btRemain); - return Math.floor(s / 60) + ":" + String(s % 60).padStart(2, "0"); - } - - // breaktimer owns its own state file; this only calls its verbs. Two - // writers on that file would race with its daemon loop, which rewrites it - // on every phase change. - Process { - id: breakProc - onExited: code => { - if (code !== 0) - console.warn("status: breaktimer.sh " + breakProc.command[1] + " exited " + code); } } // --- game detection --------------------------------------------------- // // A game is a fullscreen app that already holds the screen, and the idle - // lock, DND and breaktimer are all unwanted while it runs, so presentation + // lock and DND are both unwanted while it runs, so presentation // is set automatically. This machine's games come from Steam and launch // either under gamescope or directly, and the DuckStation and PCSX2 emulators // run standalone, so all four are tested and any one is enough. @@ -269,56 +220,10 @@ Singleton { onLoadFailed: mf.value = false } - // A daemon file holding a word. Same watch and same missing-file rule as - // ModeFile, without a write path: this side only reads. - component WordFile: FileView { - id: wf - - property string value: "stopped" - - function reparse() { - const t = wf.text().trim(); - if (t !== wf.value) wf.value = t; - } - - watchChanges: true - printErrors: false - onFileChanged: wf.reload() - onLoaded: wf.reparse() - // No file means no daemon, which is the stopped state, not an error. - onLoadFailed: wf.value = "stopped" - } - - // The remaining seconds. Validated as an integer rather than trusted: - // the file is written every tick and a read can catch it mid-write, and - // an empty string coerces to 0 silently while NaN would propagate into - // the countdown as "NaN:aN". - component SecondsFile: FileView { - id: sf - - property int value: 0 - - function reparse() { - const n = parseInt(sf.text().trim(), 10); - const v = (isNaN(n) || n < 0) ? 0 : n; - if (v !== sf.value) sf.value = v; - } - - watchChanges: true - printErrors: false - onFileChanged: sf.reload() - onLoaded: sf.reparse() - onLoadFailed: sf.value = 0 - } - ModeFile { id: dndFile; path: root.dir + "/status.dnd" } ModeFile { id: presFile; path: root.dir + "/status.presentation" } ModeFile { id: nolockFile; path: root.dir + "/status.nolock" } ModeFile { id: quietFile; path: root.dir + "/status.quiet" } // Written only by the game detector above, never by statusctl. ModeFile { id: gamingFile; path: root.dir + "/status.gaming" } - - WordFile { id: btStateFile; path: root.dir + "/breaktimer.state" } - WordFile { id: btPhaseFile; path: root.dir + "/breaktimer.phase" } - SecondsFile { id: btRemainFile; path: root.dir + "/breaktimer.remain" } } |
