Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

display-toggle

Fully disables the MacBook built-in display while keeping the lid open — not a backlight dim, but a real disconnect from WindowServer compositing. The GPU stops rendering to it entirely.

Uses private SkyLight.framework APIs resolved at runtime via dlsym. No SIP disable required.

Requirements

  • macOS 13 (Ventura) or later — Apple Silicon or Intel
  • At least one external display connected (safety guard)
  • Xcode Command Line Tools: xcode-select --install

Build & Install

make build           # compile release binary → .build/release/display-toggle
sudo make install    # copy to /usr/local/bin/display-toggle
make uninstall       # remove from /usr/local/bin/

To build a universal (arm64 + x86_64) binary:

swift build -c release --arch arm64 --arch x86_64
# binary: .build/apple/Products/Release/display-toggle
sudo cp .build/apple/Products/Release/display-toggle /usr/local/bin/

Usage

SUBCOMMANDS:
  list      List all connected displays with IDs, resolutions, and status
  status    Show whether the built-in display is currently enabled or disabled
  on        Enable the built-in display
  off       Disable the built-in display (frees GPU from rendering it)
  toggle    Toggle: disable if enabled, enable if disabled
# See all displays
display-toggle list
#   Display 1: Built-in Retina  2560x1600   ID: 69732928   [ENABLED]
#   Display 2: External         2560x1440   ID: 724042646  [ENABLED]

# Current state
display-toggle status

# Disable (5-second countdown → Ctrl+C to cancel)
display-toggle off

# Disable immediately, auto-revert in 15 s unless you press Enter
display-toggle off --timeout 15

# Disable immediately, no countdown, no revert
display-toggle off --force

# Re-enable
display-toggle on

# Toggle (bind this to a hotkey)
display-toggle toggle

# Toggle with auto-revert safety net
display-toggle toggle --timeout 10

# Verbose: prints display IDs, symbol resolution, connection ID
display-toggle list --verbose

Safety

  • External display required: off / toggle-off refuse to run if no external display is active (exit code 2). Override with --force.
  • 5-second countdown: gives you time to Ctrl+C before the display goes dark. Skip with --force.
  • SIGINT / SIGTERM handlers: if you Ctrl+C during the --timeout countdown, the display re-enables before exit.
  • SIGKILL: cannot be caught. If the process is force-killed mid-operation the display stays off. Run display-toggle on from another terminal, or restart WindowServer (sudo killall -KILL WindowServer).

Exit codes

Code Meaning
0 Success
1 Error (symbol not found, API failure, no built-in display, …)
2 No external display found

Keyboard shortcut

Bind to a hotkey via Shortcuts.app:

  1. Open Shortcuts → New Shortcut
  2. Add action Run Shell Script: /usr/local/bin/display-toggle toggle --force
  3. Settings → Keyboard Shortcut → assign e.g. ⌃⌥⌘B

Or via Automator (Service → Run Shell Script), then bind in System Settings → Keyboard → Shortcuts → Services.

How it works

macOS WindowServer (via the private CGS / SkyLight layer) tracks which displays are enabled for compositing. The public CoreGraphics API lets you enumerate and query displays but not disable them. The private CGSConfigureDisplayEnabled(connectionID, displayID, false) function removes the display from the compositor entirely — windows that were on it migrate to the primary display.

The symbol is resolved at runtime from SkyLight.framework using dlsym, falling through these candidates in order:

  1. CGSConfigureDisplayEnabled — macOS 13–15 (primary)
  2. CGSSetDisplayEnabled — earlier macOS fallback
  3. SLSConfigureDisplayEnabled — SkyLight-prefixed variant

If none resolves, the tool prints the nm command to inspect your system's available symbols.

Troubleshooting

"Private API symbol not found"

Run the suggested nm command to see what's available on your macOS version:

nm /System/Library/PrivateFrameworks/SkyLight.framework/SkyLight \
  | grep -iE "display|enabled"

If you find a different symbol name, add it to the candidates array in main.swift.

Display stays off after crash / SIGKILL

display-toggle on
# or, if the binary is inaccessible:
sudo killall -KILL WindowServer   # restarts the entire display session — all apps relaunch

GPU usage didn't drop

Verify the display is actually disabled:

display-toggle status
# Built-in display (ID: 69732928): DISABLED

If still ENABLED, the private API call succeeded with code 0 but WindowServer ignored it — this can happen on newer macOS versions that changed the internal semantics. Check --verbose output and open an issue with your macOS version.

Compatibility notes

macOS Status
15 Sequoia Expected to work (CGSConfigureDisplayEnabled present)
14 Sonoma Expected to work
13 Ventura Primary target, tested path
12 Monterey May work; minimum deployment target is 13

This utility uses private APIs. Apple may rename or remove them at any time.

About

Fully disable the MacBook built-in display with the lid open—a real GPU-level disconnect from WindowServer, not just a backlight dim

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages