Skip to content

Latest commit

 

History

41 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SharperDisplay

Free HiDPI scaling and per-display brightness for external monitors on macOS.
A lightweight, open-source menu bar app — no subscription, no trial.

platform arch swift license


The problem

Plug a 1440p (or 1080p) monitor into a Mac and macOS gives you exactly one sharp option: the native resolution, with everything tiny. The crisp "Retina" scaling you get on the built-in display — where the desktop renders at 2× and is downsampled — is simply not offered. And since macOS 26, the brightness keys no longer reach third-party apps at all, so they always dim the laptop screen even when you are working on the external monitor.

SharperDisplay fixes both.

Features

🖥 HiDPI on any external display Unlocks the full ladder of scaled Retina resolutions — including at your monitor's real refresh rate (75 Hz, 120 Hz, …).
⚡️ Instant switching The heavy setup happens once in the background. After that, changing resolution is a single mode switch — no black screens, no window shuffling.
☀️ Per-display brightness Hardware DDC/CI where the monitor supports it, smooth gamma dimming where it doesn't.
⌨️ Brightness keys that follow your cursor Cursor on the external monitor → the monitor dims. Cursor on the laptop → macOS handles it natively.
🪟 Native-looking HUD Drawn with the system Liquid Glass view, matched pixel-for-pixel against the macOS on-screen display.
💾 Remembers everything Settings persist per display, re-apply on reconnect, and are cleanly reverted when the app quits.

Requirements

  • macOS 26 (Tahoe) or later
  • Apple Silicon Mac
  • Accessibility permission — only needed for the brightness keys

Install

⬇️ Download SharperDisplay 1.0.0 — open the disk image and drag the app to Applications. That's it.

The build is signed with a Developer ID and notarized by Apple, so there are no security warnings and no Terminal commands to run.

To use the brightness keys, grant System Settings → Privacy & Security → Accessibility → SharperDisplay once. Everything else works without it.

Build from source

git clone https://github.com/tdsrmd/SharperDisplay.git
cd SharperDisplay
brew install xcodegen
xcodegen generate
xcodebuild build -project SharperDisplay.xcodeproj -scheme SharperDisplay -configuration Release -derivedDataPath build
cp -R build/Build/Products/Release/SharperDisplay.app /Applications/

A local build is ad-hoc signed, so macOS invalidates the Accessibility grant every time you replace the bundle — re-grant it after each rebuild.

How it works

Three macOS limitations had to be worked around. Each solution was verified against real hardware rather than assumed:

1. HiDPI modes are hidden for most external displays. SharperDisplay creates a virtual display carrying a ladder of 2× modes and attaches it to the physical display as a mirror slave — the physical display stays the master, so it keeps its position, its main-display status and your window layout. macOS then exposes the full HiDPI mode list for the physical display, and switching between them is an ordinary CGDisplaySetDisplayMode call.

2. macOS 26 swallows the brightness keys. On Tahoe the keys never reach CGEventTap — not at session level, not even at HID level. SharperDisplay remaps them at the HID layer with hidutil, catches the remapped keys, and drives brightness itself: the app's own control for external displays, DisplayServices for the built-in one. The remap is removed when the app quits and can be switched off from the panel.

3. The Tahoe on-screen display cannot be driven by third-party apps. Its fill value is ignored, so SharperDisplay draws its own HUD using NSGlassEffectView — the same Liquid Glass view the system uses — positioned and measured to match the native one.

Architecture

UI            MenuBarView · BrightnessOSDView
Controllers   HiDPIController · BrightnessController
Services      DisplayService · VirtualDisplayService · BrightnessService
              SystemBrightness · MediaKeyMonitor · KeyRemapService · OSDService
Logic         ModeSelection · BrightnessMath · CursorRouting   (pure, unit-tested)
Persistence   PreferenceStore

Controllers hold all the decisions and are tested against fake services; the services are thin wrappers over CoreGraphics, IOKit and a few private frameworks. Private API usage is confined to Support/PrivateAPIs.h and the services importing it.

xcodebuild test -project SharperDisplay.xcodeproj -scheme SharperDisplay -destination 'platform=macOS'

Troubleshooting

Brightness keys still change the laptop screen. The Accessibility grant is stale — remove SharperDisplay from the Accessibility list, add /Applications/SharperDisplay.app again, and toggle it on. The app picks it up within a few seconds.

"Mirroring failed" right after (re)launching. macOS refuses new mirror sets for up to a minute after tearing one down. The app retries in the background; the spinner next to the display name shows it is still working, and your request is applied as soon as it succeeds.

Brightness says "(Software)". Your monitor or cable path rejected DDC/CI writes, so gamma dimming is used instead. Try a different port or cable; the app upgrades itself to hardware control automatically when DDC works.

Alternatives

BetterDisplay is the far more featureful (and excellent) app in this space, with a paid Pro tier. MonitorControl is free but does not do HiDPI and cannot intercept brightness keys on macOS 26. SharperDisplay is deliberately small: HiDPI, brightness, keys — nothing else.

Contributing

Issues and pull requests are welcome. Please keep the existing structure: pure logic stays in Logic/ with unit tests, system access stays behind a service protocol, and controllers stay testable against fakes.

License

MIT — see LICENSE.

About

Free HiDPI scaling and per-display brightness for external monitors on macOS 26 — menu bar app with brightness keys that follow your cursor

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages