fix(profile): button-initiated DPI/SmartShift changes update the UI and persist - #148
Merged
Merged
Conversation
mmaher88
force-pushed
the
fix-button-persists-to-profile
branch
2 times, most recently
from
July 28, 2026 06:05
6a13026 to
b6f3069
Compare
…nd persist A diverted button that cycles DPI or toggles SmartShift wrote straight to DeviceSession, bypassing the profile entirely. The UI kept showing the old value: DeviceModel's display cache is re-armed by onDisplayProfileChanged with the unchanged profile's values, clobbering the live state the relay had just exposed. The value also snapped back on the next profile apply. Persist the change into the active profile instead, so there is one source of truth. applyHardwareChange mirrors applyDisplayedChange but targets the HARDWARE profile — the button acted on the device, not on whichever profile is being viewed — and skips the hardware forward because the device is already in the new state. The UI is refreshed only when the viewed profile is the active one. The dispatcher notifies explicitly rather than having the orchestrator listen to DeviceSession's change signals; that keeps a profile *application* from echoing back and rewriting the profile it just applied. AppRootFixture seeded a default profile with SmartShift on but left the mock session's SmartShift at its zero-initialised default, so a toggle computed from the session was a no-op. Seed the session to match, as real enumeration would. Tests: 3 orchestrator (incl. writing the hardware profile while viewing another) + 2 end-to-end button-press tests. Verified on an MX Master 3S.
mmaher88
force-pushed
the
fix-button-persists-to-profile
branch
from
July 28, 2026 06:13
b6f3069 to
16cfa70
Compare
This was referenced Jul 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Symptom
Bind a button to DPI cycle or SmartShift toggle, press it: the hardware changes but the UI keeps showing the old value. This one has been chased repeatedly.
Root cause
Traced with instrumentation on real hardware:
The button wrote straight to
DeviceSession, bypassing the profile.DeviceModelhas two sources of truth — a display cache (fed by profile loads / UI edits) and the live session — and the getters short-circuit to the cache. The relay correctly cleared the cache, butonDisplayProfileChangedthen re-armed it from the unchanged profile, clobbering the live value.That's why cache-invalidation patches kept regressing: the bug is a sequencing race (clear → re-arm), so any new caller of
setDisplayValuesreintroduces it. The value also snapped back on the next profile apply.Fix
Persist button-initiated changes into the active profile, so there's one source of truth.
ProfileOrchestrator::applyHardwareChange— mirror ofapplyDisplayedChange, but targets the hardware profile (the button acted on the device, not on whichever profile you're viewing), and skips the hardware forward since the device is already in the new state. UI refreshes only when the viewed profile is the active one.dpiChangedByButton/smartShiftChangedByButton) rather than having the orchestrator listen toDeviceSession's change signals — this is what stops a profile application from echoing back and rewriting the profile it just applied.connect()calls in the .cpp" convention.Behavior change
A DPI cycled by button now survives the next profile apply instead of snapping back, and is written to the profile on disk. That is the intended semantics for this change. Saves are synchronous, matching the existing
applyDisplayedChangepath (which already saves per UI change, including slider drags).Test fixture fix
AppRootFixtureseeded a default profile with SmartShift on but left the mock session's SmartShift at its zero-initialisedfalse, so a toggle computed from the session was a silent no-op. Seeded the session to match, as real enumeration +applyProfileToHardwaredo in production.Tests
Full suite green: 736 C++. Smoke-tested on an MX Master 3S — SmartShift toggle and DPI cycle both reflect in the UI immediately.