pragma Singleton // Pointer size and text scale. // // These are the two settings that must agree across three consumers that do not // share a configuration system: the compositor draws the cursor, GTK // applications read gsettings, and the shell renders its own text. Panama's // store is the source of truth, and this pushes the value out to the other two // so they cannot disagree. // // pointer size -> gsettings (GTK) + `hyprctl setcursor` (compositor) // text scale -> gsettings (GTK) // // The shell's own font size is not scaled here. Theme.qml's sizes are part of // the design rather than a user preference, and scaling them at runtime would // reflow every panel against layouts that were tuned at the design size. Text // scale therefore affects applications, which is where it matters, and the // page says so rather than implying it does more. import Quickshell import Quickshell.Io import QtQuick import qs.config Singleton { id: root property string lastError: "" readonly property bool busy: runner.running || root.pending.length > 0 readonly property string cursorTheme: DesktopPreferences.get("cursorTheme") readonly property int cursorSize: DesktopPreferences.get("cursorSize") readonly property real textScale: DesktopPreferences.get("textScale") // A short queue, because applying one setting takes several commands and // Process runs one at a time. property var pending: [] Process { id: runner onExited: (exitCode, exitStatus) => { if (exitCode !== 0) root.lastError = "That accessibility setting could not be applied."; root.drain(); } } function drain(): void { if (runner.running || root.pending.length === 0) return; const next = root.pending[0]; root.pending = root.pending.slice(1); runner.exec(next); } function enqueue(commands: var): void { root.pending = root.pending.concat(commands); root.drain(); } Component.onCompleted: { settle.restart(); } // Push the stored values outward once at startup, so a value changed in a // previous session is in effect in this one even though gsettings and the // compositor do not read Panama's store. Timer { id: settle interval: 1200 onTriggered: root.applyAll() } Connections { target: DesktopPreferences function onRevisionChanged(): void { coalesce.restart(); } } Timer { id: coalesce interval: 250 onTriggered: root.applyAll() } function applyAll(): void { root.lastError = ""; const size = String(root.cursorSize); const commands = [ ["gsettings", "set", "org.gnome.desktop.interface", "cursor-size", size], ["gsettings", "set", "org.gnome.desktop.interface", "text-scaling-factor", String(root.textScale)] ]; commands.push(["hyprctl", "setcursor", root.cursorTheme, size]); root.enqueue(commands); } }