Skip to content

feat: display module — brightness and power control over DDC/CI - #18

Merged
harryisfish merged 1 commit into
mainfrom
feat/display-module
Jul 3, 2026
Merged

feat: display module — brightness and power control over DDC/CI#18
harryisfish merged 1 commit into
mainfrom
feat/display-module

Conversation

@harryisfish

Copy link
Copy Markdown
Contributor

Summary

  • New smctl display command group for external displays on Apple Silicon: list [--json], brightness [0-100] [--display <index|uuid>] [--json], power on|off [--display …]
  • New DisplayDDC C target: DDC/CI over the private IOAVService I2C interface, vendored from m1ddc (MIT) and converted from Objective-C to plain C/CoreFoundation
  • power off = VCP 0xD6 soft-off: panel drops signal but stays in the macOS layout (no window rearrangement) and wakes back over DDC
  • main.swiftSMCtl.swift rename (Swift forbids @main alongside a main.swift in a multi-file target)

Why not a true layout disconnect

CGSConfigureDisplayEnabled (displayplacer route) was tested on this machine and is a one-way door: the disabled display disappears from every layer (CG, IOKit, BetterDisplay), survives replug and full sleep, and only comes back after deleting the WindowServer display plists and rebooting. Documented in project memory; deliberately not shipped.

Test plan

  • 112 unit tests pass (2 new: DDC packet checksums, no hardware needed)
  • Hardware-verified on M4 mini with Redmi 27 NU + AOC 27G2G4 (both 4K): list/JSON, brightness get/set/restore + write-verify, power off→on cycle, multi-display selector errors

adds `smctl display list | brightness | power` for external displays on
Apple Silicon, via the private IOAVService I2C interface. The DDC layer
is vendored from m1ddc (MIT, waydabber) and converted from Objective-C
to plain C/CoreFoundation so SwiftPM builds it without ARC bridging.

`power off` uses VCP 0xD6 (soft off): the panel powers down and drops
signal, but stays in the macOS layout, so windows are not rearranged
and it can be woken back over DDC. A true layout disconnect
(CGSConfigureDisplayEnabled) was tested and rejected: it is a one-way
door that survives replug and sleep, recoverable only by resetting the
WindowServer display plists and rebooting.

main.swift is renamed to SMCtl.swift because @main cannot coexist with
a file named main.swift once the target has more than one source file.
@leaperone-bot

leaperone-bot commented Jul 3, 2026

Copy link
Copy Markdown

🤖 Leo

Code Review

⏳ 等待审查...

最后更新: 2026-07-03 18:17

@harryisfish
harryisfish merged commit 333c76c into main Jul 3, 2026
1 check passed
@leaperone-bot
leaperone-bot deleted the feat/display-module branch July 3, 2026 18:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants