diff options
| author | Danilo M. <danix@danix.xyz> | 2026-10-21 10:23:05 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-10-21 10:23:05 +0200 |
| commit | 77952289f8176703eef7134262c6fd6d0d835dd6 (patch) | |
| tree | 730b1d128b77b43be4ac4127740baee2d4c4b87b | |
| parent | 93f129ad1a2b59db8533cb7c86cee3c10417ba4f (diff) | |
| download | quickshell-77952289f8176703eef7134262c6fd6d0d835dd6.tar.gz quickshell-77952289f8176703eef7134262c6fd6d0d835dd6.zip | |
Switch: never set checked itself, report the new state instead
The shared Switch flipped its own checked on click, which replaced the
caller's binding with a constant. Every use binds checked, so after a
click the switch stopped following its source: Discard on a settings
draft reverted the value and left the switch showing the click. Four
status rows and the headphones panel each carried a resync workaround
for it.
toggled now carries the new state and the switch moves only when the
caller's binding does. Handlers that read checked as the new value take
the argument instead; the workarounds are gone.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| -rw-r--r-- | desktop/Switch.qml | 7 | ||||
| -rw-r--r-- | desktop/island/HeadphonesPanel.qml | 7 | ||||
| -rw-r--r-- | desktop/modules/assistant/AssistantPage.qml | 2 | ||||
| -rw-r--r-- | desktop/modules/autostart/AutostartPage.qml | 2 | ||||
| -rw-r--r-- | desktop/modules/bluetooth/BluetoothPage.qml | 4 | ||||
| -rw-r--r-- | desktop/modules/network/NetworkPage.qml | 2 | ||||
| -rw-r--r-- | desktop/modules/notes/NotesPage.qml | 2 | ||||
| -rw-r--r-- | desktop/modules/qtmaildir/BoolSetting.qml | 2 | ||||
| -rw-r--r-- | desktop/modules/sbbuilder/SbbDesktopModule.qml | 10 | ||||
| -rw-r--r-- | desktop/modules/status/BreakRow.qml | 10 | ||||
| -rw-r--r-- | desktop/modules/status/LockRow.qml | 5 | ||||
| -rw-r--r-- | desktop/modules/status/SnoozeRow.qml | 2 | ||||
| -rw-r--r-- | desktop/modules/status/StatusRow.qml | 5 |
13 files changed, 18 insertions, 42 deletions
diff --git a/desktop/Switch.qml b/desktop/Switch.qml index f14c986..63de4ba 100644 --- a/desktop/Switch.qml +++ b/desktop/Switch.qml @@ -21,7 +21,10 @@ Rectangle { property bool checked: false property bool enabled: true - signal toggled + // The new state. The switch never sets checked itself: that would break + // the caller's binding, so a draft discarded or a state that failed to + // change left the switch showing the click. The caller's binding moves it. + signal toggled(bool on) implicitWidth: 42 implicitHeight: 24 @@ -42,6 +45,6 @@ Rectangle { MouseArea { anchors.fill: parent cursorShape: sw.enabled ? Qt.PointingHandCursor : Qt.ArrowCursor - onClicked: if (sw.enabled) { sw.checked = !sw.checked; sw.toggled(); } + onClicked: if (sw.enabled) sw.toggled(!sw.checked) } } diff --git a/desktop/island/HeadphonesPanel.qml b/desktop/island/HeadphonesPanel.qml index 86e3ae4..315bc6b 100644 --- a/desktop/island/HeadphonesPanel.qml +++ b/desktop/island/HeadphonesPanel.qml @@ -306,12 +306,7 @@ Column { anchors { right: parent.right; verticalCenter: parent.verticalCenter } enabled: !panel.busy checked: panel.voice - // The click flips checked itself, which breaks the binding; - // restore it so the switch follows what the headphones report. - onToggled: { - panel.run(["voice", checked ? "on" : "off"]); - checked = Qt.binding(() => panel.voice); - } + onToggled: on => panel.run(["voice", on ? "on" : "off"]) } } diff --git a/desktop/modules/assistant/AssistantPage.qml b/desktop/modules/assistant/AssistantPage.qml index 2970784..e088241 100644 --- a/desktop/modules/assistant/AssistantPage.qml +++ b/desktop/modules/assistant/AssistantPage.qml @@ -305,7 +305,7 @@ Column { id: think anchors.verticalCenter: parent.verticalCenter checked: page.shown("thinking") !== "false" - onToggled: page.asst.setKey("thinking", checked ? "true" : "false") + onToggled: on => page.asst.setKey("thinking", on ? "true" : "false") } Small { anchors { left: think.right; leftMargin: 10; verticalCenter: parent.verticalCenter } diff --git a/desktop/modules/autostart/AutostartPage.qml b/desktop/modules/autostart/AutostartPage.qml index 2e6df9c..0e23327 100644 --- a/desktop/modules/autostart/AutostartPage.qml +++ b/desktop/modules/autostart/AutostartPage.qml @@ -413,7 +413,7 @@ Column { anchors { left: parent.left; verticalCenter: parent.verticalCenter } enabled: page.newWs !== "" checked: page.newSilent - onToggled: page.newSilent = checked + onToggled: on => page.newSilent = on } Small { anchors { left: silent.right; leftMargin: 10; verticalCenter: parent.verticalCenter } diff --git a/desktop/modules/bluetooth/BluetoothPage.qml b/desktop/modules/bluetooth/BluetoothPage.qml index a4ba232..8ab67f0 100644 --- a/desktop/modules/bluetooth/BluetoothPage.qml +++ b/desktop/modules/bluetooth/BluetoothPage.qml @@ -39,7 +39,7 @@ Column { anchors { right: parent.right; verticalCenter: parent.verticalCenter } enabled: page.bt.adapter !== null checked: page.bt.adapter ? page.bt.adapter.enabled : false - onToggled: if (page.bt.adapter) page.bt.adapter.enabled = checked + onToggled: on => { if (page.bt.adapter) page.bt.adapter.enabled = on; } } } @@ -69,7 +69,7 @@ Column { anchors { right: parent.right; verticalCenter: parent.verticalCenter } enabled: page.bt.adapter !== null checked: page.bt.adapter ? page.bt.adapter.discoverable : false - onToggled: if (page.bt.adapter) page.bt.adapter.discoverable = checked + onToggled: on => { if (page.bt.adapter) page.bt.adapter.discoverable = on; } } } diff --git a/desktop/modules/network/NetworkPage.qml b/desktop/modules/network/NetworkPage.qml index 3749688..b789d17 100644 --- a/desktop/modules/network/NetworkPage.qml +++ b/desktop/modules/network/NetworkPage.qml @@ -106,7 +106,7 @@ Column { anchors { right: parent.right; verticalCenter: parent.verticalCenter } enabled: Networking.wifiHardwareEnabled checked: page.net.wifiOn - onToggled: Networking.wifiEnabled = checked + onToggled: on => Networking.wifiEnabled = on } } diff --git a/desktop/modules/notes/NotesPage.qml b/desktop/modules/notes/NotesPage.qml index 1a82254..c4563e0 100644 --- a/desktop/modules/notes/NotesPage.qml +++ b/desktop/modules/notes/NotesPage.qml @@ -334,7 +334,7 @@ Item { id: prevSwitch anchors { right: parent.right; verticalCenter: parent.verticalCenter } checked: page.preview - onToggled: page.preview = checked + onToggled: on => page.preview = on } } diff --git a/desktop/modules/qtmaildir/BoolSetting.qml b/desktop/modules/qtmaildir/BoolSetting.qml index a6a7030..4f41944 100644 --- a/desktop/modules/qtmaildir/BoolSetting.qml +++ b/desktop/modules/qtmaildir/BoolSetting.qml @@ -42,7 +42,7 @@ Item { id: sw anchors { left: lbl.right; leftMargin: 8; verticalCenter: parent.verticalCenter } checked: s.on - onToggled: s.store.set(s.section, s.key, checked ? "true" : "false") + onToggled: on => s.store.set(s.section, s.key, on ? "true" : "false") } Text { anchors { left: sw.right; leftMargin: 10; right: parent.right; verticalCenter: parent.verticalCenter } diff --git a/desktop/modules/sbbuilder/SbbDesktopModule.qml b/desktop/modules/sbbuilder/SbbDesktopModule.qml index fc93573..74e95d5 100644 --- a/desktop/modules/sbbuilder/SbbDesktopModule.qml +++ b/desktop/modules/sbbuilder/SbbDesktopModule.qml @@ -93,11 +93,11 @@ Module { Switch { anchors { left: evLabel.right; leftMargin: 8; verticalCenter: parent.verticalCenter } checked: col.st.value("notify", "events").includes(ev.modelData) - onToggled: { + onToggled: on => { const all = col.st.fallback("notify", "events"); - const on = col.st.value("notify", "events").filter(e => e !== ev.modelData); - if (checked) on.push(ev.modelData); - col.st.put("notify", "events", all.filter(e => on.includes(e))); + const kept = col.st.value("notify", "events").filter(e => e !== ev.modelData); + if (on) kept.push(ev.modelData); + col.st.put("notify", "events", all.filter(e => kept.includes(e))); } } } @@ -123,7 +123,7 @@ Module { // "" is how sb-builder spells no VM control; an // emptied field means the default instead. checked: col.st.value("vm", "domain") !== "" - onToggled: col.st.put("vm", "domain", checked ? null : "") + onToggled: on => col.st.put("vm", "domain", on ? null : "") } } Setting { store: col.st; section: "vm"; key: "domain"; label: "Domain" diff --git a/desktop/modules/status/BreakRow.qml b/desktop/modules/status/BreakRow.qml index 70ad3ea..8b732b1 100644 --- a/desktop/modules/status/BreakRow.qml +++ b/desktop/modules/status/BreakRow.qml @@ -81,14 +81,4 @@ Item { onToggled: Status.runBreaktimer(Status.btPaused ? "resume" : "pause") } } - - // The shared Switch writes `checked` on click and so drops the binding - // above. Resync on any state change, which also covers a change made from - // the waybar module's own bindings or from a terminal. - Connections { - target: Status - function onBtStateChanged() { - sw.checked = Status.btRunning && !Status.btPaused; - } - } } diff --git a/desktop/modules/status/LockRow.qml b/desktop/modules/status/LockRow.qml index c59c2f1..0e711d8 100644 --- a/desktop/modules/status/LockRow.qml +++ b/desktop/modules/status/LockRow.qml @@ -105,9 +105,4 @@ Item { onToggled: row.apply(!row.lockOn) } } - - // The shared Switch's click handler writes `checked` directly, which drops - // the declarative binding above. Resync on any state change so the timer, - // statusctl or presentation mode moves the switch back into agreement. - onLockOnChanged: sw.checked = row.lockOn } diff --git a/desktop/modules/status/SnoozeRow.qml b/desktop/modules/status/SnoozeRow.qml index 046d7cb..efb1844 100644 --- a/desktop/modules/status/SnoozeRow.qml +++ b/desktop/modules/status/SnoozeRow.qml @@ -109,6 +109,4 @@ Item { onToggled: row.apply(!row.active) } } - - onNowChanged: sw.checked = row.active } diff --git a/desktop/modules/status/StatusRow.qml b/desktop/modules/status/StatusRow.qml index c9e78c0..c342e2b 100644 --- a/desktop/modules/status/StatusRow.qml +++ b/desktop/modules/status/StatusRow.qml @@ -53,9 +53,4 @@ Item { checked: row.value onToggled: Status.toggleMode(row.mode) } - - // The shared Switch's click handler writes `checked` directly, which drops - // the declarative binding above. Resync on any value change so an external - // write (statusctl, waybar) moves the switch back into agreement. - onValueChanged: sw.checked = row.value } |
