pragma Singleton // GNOME and GTK applications already honour these desktop sound preferences. // Panama controls the same durable keys so moving between sessions does not // create two competing notions of whether event feedback is enabled. import Quickshell import Quickshell.Io import QtQuick Singleton { id: root property bool eventSounds: true property bool inputFeedback: false property string lastError: "" readonly property bool busy: eventRead.running || inputRead.running || eventWrite.running || inputWrite.running function parsedBoolean(text: string, fallback: bool): bool { const value = text.trim(); if (value === "true") return true; if (value === "false") return false; return fallback; } function refresh(): void { if (!eventRead.running) eventRead.running = true; if (!inputRead.running) inputRead.running = true; } function setEventSounds(enabled: bool): void { root.eventSounds = enabled; root._writeEventSounds(); } function setInputFeedback(enabled: bool): void { root.inputFeedback = enabled; root._writeInputFeedback(); } // Assigning `running = true` to a Process that is already running is a // no-op, not a queue -- so a toggle that lands mid-write would otherwise // be dropped silently. eventWrite.onExited re-checks root.eventSounds // against what was actually written and calls this again if they still // disagree. function _writeEventSounds(): void { if (eventWrite.running) return; eventWrite.writtenValue = root.eventSounds; eventWrite.command = ["gsettings", "set", "org.gnome.desktop.sound", "event-sounds", String(root.eventSounds)]; eventWrite.running = true; } function _writeInputFeedback(): void { if (inputWrite.running) return; inputWrite.writtenValue = root.inputFeedback; inputWrite.command = ["gsettings", "set", "org.gnome.desktop.sound", "input-feedback-sounds", String(root.inputFeedback)]; inputWrite.running = true; } Process { id: eventRead command: ["gsettings", "get", "org.gnome.desktop.sound", "event-sounds"] stdout: StdioCollector { onStreamFinished: root.eventSounds = root.parsedBoolean(this.text, root.eventSounds) } onExited: (code, status) => { if (code !== 0) root.lastError = "Event sound preferences could not be read."; } } Process { id: inputRead command: ["gsettings", "get", "org.gnome.desktop.sound", "input-feedback-sounds"] stdout: StdioCollector { onStreamFinished: root.inputFeedback = root.parsedBoolean(this.text, root.inputFeedback) } onExited: (code, status) => { if (code !== 0) root.lastError = "Input feedback preferences could not be read."; } } Process { id: eventWrite property bool writtenValue: true onExited: (code, status) => { if (code !== 0) { root.lastError = "Event sound preferences could not be changed."; root.refresh(); } else { root.lastError = ""; } if (root.eventSounds !== eventWrite.writtenValue) root._writeEventSounds(); } } Process { id: inputWrite property bool writtenValue: false onExited: (code, status) => { if (code !== 0) { root.lastError = "Input feedback preferences could not be changed."; root.refresh(); } else { root.lastError = ""; } if (root.inputFeedback !== inputWrite.writtenValue) root._writeInputFeedback(); } } Component.onCompleted: root.refresh() }