Skip to content

Repository files navigation

DisplayDefaults

Extends the desktop when a monitor Windows has never seen before shows up, instead of duplicating it, and optionally puts it above / below / left / right of the primary.

Runs from the tray. No admin rights, nothing machine-wide.

Why

Windows already remembers per-monitor layout — arrange your screens once and reconnecting restores it. What it does not have is a default for a display it has never seen. That first connection duplicates, and you fix it by hand every time you meet a new monitor.

Because the monitor identity Windows uses carries the EDID model and the adapter output but no serial number, identical setups collide by design: arrange one desk in an open space and every identical desk is already arranged.

Install

Run DisplayDefaults-x.y.z-setup.exe from the Releases page. A monitor icon appears in the notification area.

There is no UAC prompt. The installer is per-user: it puts the exe in %LOCALAPPDATA%\Programs\DisplayDefaults, not Program Files, and registers nothing machine-wide.

The download is unsigned, so SmartScreen will show "Windows protected your PC". More info → Run anyway if you trust it, or build it yourself from source (below).

Right-click the tray icon to:

Extend new displays turn the whole thing on or off
Place new display above / below / left / right of the primary, or let Windows decide
Forget known displays treat every monitor as new again
Start with Windows writes an HKCU\...\Run value

Uninstalling

Uninstall from Add/Remove Programs. Besides its own folder, the app writes an autostart value under HKCU\...\Run and its settings in %LOCALAPPDATA%\DisplayDefaults; the uninstaller removes both.

If you built from source and are running the exe directly, nothing knows about those two things, so clean them up yourself before deleting it:

DisplayDefaults.exe --uninstall

Safe to run twice, and it prints what it removed. This is why the release is an installer rather than a bare exe: a loose exe has no uninstall hook, so winget uninstall would delete it and leave the autostart value pointing at a file that is no longer there.

Your display arrangement is deliberately not reverted. That lives in Windows' own configuration store, and it is the arrangement you chose.

Build

Needs the .NET 9 SDK. No other dependencies.

dotnet run -- --selftest    # checks the logic, then prints the monitors it can see
dotnet run                  # tray icon

--selftest exits non-zero on failure, which is what gates the release in CI.

To reproduce a release build, publish the exe and then wrap it — the installer expects publish\DisplayDefaults.exe to exist already:

dotnet publish -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:Version=1.2.3 -o publish
iscc /DAppVersion=1.2.3 installer.iss

The exe is ~48 MB, almost entirely the .NET desktop runtime bundled so users need nothing installed; the installer compresses it to ~43 MB. EnableCompressionInSingleFile in the csproj already halves the exe from 107 MB, and trimming would go further but WinForms rejects it (NETSDK1175), so that is the floor while the tray is WinForms.

Layout

File
DisplayTopology.cs CCD interop: monitor identity, extend, placement
NewDisplayWatcher.cs the feature — Start/Stop, seen-set, event wiring
TrayApp.cs tray UI
Program.cs host, selftest, --uninstall
installer.iss per-user installer; [UninstallRun] is why it exists
.github/workflows/release.yml tag → selftest → publish → installer → release
winget/ manifests submitted to winget-pkgs

After a release, point wingetcreate at the new asset to refresh winget/ and open the update PR. The workflow prints the SHA256 in its job summary.

wingetcreate update pawneeranger.DisplayDefaults --version 1.2.3 --urls <installer-url>

NewDisplayWatcher is deliberately UI-free and has Start/Stop so it can drop into a PowerToys module's enable/disable unchanged. Everything else is replaceable.

License

MIT. Same as PowerToys, so NewDisplayWatcher can be lifted into a module there without a relicensing conversation.

Known limits

  • Placement is skipped when two monitors arrive at once; they would stack on the primary.
  • Positions are physical pixels, so a mixed-DPI pair may get nudged by Windows afterwards.
  • A monitor already connected and duplicated when the app starts is recorded as known, so it is never extended. Starting up should not yank your topology.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages