crispctl: add external HDR controls - #116
Conversation
|
Ran this on top of main against three displays here, and it holds up: every refusal path lands where it should, on and off work by id and by uuid with the headroom going 1.0 to 11.56 and back, and the boost collapse through hdr off matches your LG run (brightness 120 at max 200, then off, 100, max 100, backend back to DDC in 1.3 s). The model change is right, and the read-back loop with its final read is the shape I'd have written. I pushed one commit onto your branch rather than ask for another round, since it's all deletion. Three things in it, the first two measured: The connection epoch is gone. It's a global counter, so any add, remove or move of any display refused a switch in flight. With Extra Brightness on, an hdr off while another display was switched off was refused with epoch 2 != 0, and the callback carried a movedFlag for the HDR display itself, so any arrangement change that moved the display refused its own pending switch. setHDRPreference is the panel's path too. The uuid check you added already covers the case the epoch was for, per display, so that stays. stableDisplayUUID was DisplayInfo.displayUUID line for line, so the list and the read use displayUUID again. The README is down to one short paragraph for hdr; the reference lives in crispctl help. One more thing the run turned up, and it was mine, not yours: an off 0.3 s after an on was refused 4 times in 16 with "not accepted", and the probe lines said it was the request token. The panel's HDR toggle resyncs from the live state after every screen change and re-sent the value it had just read, replacing your token while the CLI's off sat in its settle. Fixed in #124; it's older than your PR, and the CLI was the first thing that could collide with it. With both in, 0 refused in 16, and a hot-plug during an off goes through. Merging once CI is green. |
HDRToggleView resyncs its switch from the live state on every screen-parameters notification, and every HDR flip fires one. The programmatic-change guard around that write does not hold, because SwiftUI runs onChange after the view update, by which time the flag is already reset, so each resync re-sent the value it had just read as a fresh setHDRPreference. Harmless while the toggle was the only writer, since the echo carries the same value, but each echo replaces the request token, and a request from anywhere else that is waiting out its settle at that moment is refused. Measured with crispctl's hdr set from #116: an off 0.3 s after an on was refused 4 times in 16, and 0 in 16 with this guard, which sends a request only when the switch differs from the live state.
|
Thanks for the thorough testing and for pushing the cleanup commit directly! You're completely right on the epoch and UUID duplication — I was pairing with GPT-5.6 sol on this, and it definitely loves to overthink edge cases and over-engineer race protections. Your multi-display test caught that global counter trap nicely. The trimmed README reads much cleaner as well. Glad the core flow and read-back logic held up, and thanks for tracking down that fast toggle race in #124 too! |
Summary
Adds a strictly focused external-HDR slice to
crispctl:BrightnessBoostServiceeligibility, live-state, write, boost-collapse, and request-arbitration paths as Crisp's existing GUI HDR toggle.hdrresponse object withdisplayIDandenabled.Help and documentation
crispctl helptable introduced by Give crispctl a conventional help screen and uuid selectors #107.Verification
DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer make checkCrispControlModelTests: 23 passed, 0 failed, 0 skippedcrispctlbuild with warnings as errors: passedx86_64 arm64crispctl help: verified to contain the two HDR commands in the concise command tablegit diff --check: cleanHardware validation
Validated on 2026-09-06 against the exact PR head
eba2ced8a733ec8e601fb5901835c091aac54d80, using an isolated Release build without installing or replacing/Applications/Crisp.app. Before every command sequence, the running app andcrispctl.sockowner were verified to be that build.CBD3871A-5CC4-42B6-9C2A-AC2D67FEDFC9, runtime ID 3.hdr getreported the authoritative off state. A singlehdr set ... onreturnedenabled: true; independent immediate and delayed reads remained true. AppKit EDR values changed frompotential=1/current=1to approximatelypotential=7.75/current=1.2, independently confirming the WindowServer HDR/EDR transition.hdr set ... offreturnedenabled: false, and an independent read remained false. One intervening manual HDR-off action by the tester was explicitly excluded from the CLI-off evidence.maxBrightnessbecame 200, and logical brightness was set to 120. A singlehdr set ... offreturned HDR false and safely collapsed Extra Brightness to off, brightness to 100, andmaxBrightnessto 100; immediate and one-second settled reads agreed.Out of scope
No batch operations, connect/disconnect, protocol versioning, packaging/release, Homebrew, presets, skill files, website changes, localization changes, or unrelated refactor.