AutoDisplay keeps your display layouts synchronised with the hardware that is
actually connected. The dispatcher inspects the active heads, selects the
matching configuration directory, runs pre/post hooks in order, and applies the
bundled xrandr script without returning until everything has completed. The
trigger is a privileged helper that reacts to udev hotplug events, locates the
active graphical session, drops to that user, and invokes the dispatcher.
- What's new
- Build & benchmark
- Installation
- Dispatcher usage
- Trigger behaviour
- Forcing and troubleshooting
- License
- Deterministic execution – pre and post hooks now run strictly in lexical order with blocking semantics so the dispatcher does not exit until every script has finished and the display change is confirmed.
- Smart signature caching – the dispatcher persists the last applied
signature and skips redundant work unless
--forceis supplied, ensuring that repeated events do not flap your monitors while still letting you reapply the current setup on demand. - Profile guided builds – the provided
Makefiledrives Clang with-march=nativeand gathers profile data viahyperfinebefore producing the optimised dispatcher and trigger. - Headless fixtures – pass
AUTODISPLAY_XRANDR_FIXTURE=/path/to/fixture.txt(used by the build system) to exercise the dispatcher without a live X server. UseAUTODISPLAY_STATE_HOMEto redirect the configuration tree to a scratch directory during tests. - Manual trigger overrides – set
AUTODISPLAY_TRIGGER_USER,AUTODISPLAY_TRIGGER_DISPLAY, andAUTODISPLAY_DISPATCHERwhen you need the trigger to target a specific user or an alternate dispatcher binary (the build harness uses this for PGO).
AutoDisplay requires clang, llvm-profdata, and hyperfine (all available on
Debian/Ubuntu). Once installed, run a plain make to perform the full PGO cycle
and leave the optimised binaries in build/bin/:
make # builds with clang, -march=native, and profile feedback
make clean # remove build artefactsDuring the profile phase the build system uses the fixture under
fixtures/xrandr-dual.txt together with a throwaway state directory to avoid
polluting your real $HOME.
Use the install target to deploy everything. The default prefix is
/usr/local, but it can be overridden in the usual way.
sudo make install # install into /usr/local
sudo make PREFIX=/opt/autodisplay installInstalled files:
$(PREFIX)/bin/autodisplay-dispatcher$(PREFIX)/bin/autodisplay-trigger$(PREFIX)/share/autodisplay/autodisplay-prepopulate.sh/etc/udev/rules.d/95-autodisplay.rules(overridable viaUDEV_RULES_DIR)
After installing, reload udev so the hotplug rule is picked up:
sudo udevadm control --reload-rules
sudo udevadm trigger --subsystem-match=drmThe optional install.sh wrapper still performs the legacy configuration
bootstrapping (creating ~/.config/autodisplay/default/ with sample hooks). It
now relies on make behind the scenes so that the binaries match the PGO build.
autodisplay-dispatcher [--apply] [--force]
autodisplay-dispatcher --save <name>
autodisplay-dispatcher --print-signature
--apply(default) inspects the active heads, chooses the configuration that matches the generated signature (ordefaultwhen none exists), runs the blocking pre hooks, appliesxrandr, and finally runs the blocking post hooks.--forcebypasses the signature cache so the same layout can be re-applied after editing scripts or when the previous run failed.--save <name>captures the current layout using the livexrandr --queryoutput (or the configured fixture) and generates hook scaffolding.--print-signatureemits the current signature without modifying anything.
The dispatcher writes to /tmp/autodisplay.log so you can trace every decision.
~/.config/autodisplay/
├── default/
│ ├── pre.d/00-sample.sh
│ ├── post.d/00-sample.sh
│ └── xrandr
├── state/last_signature
└── <signature-or-alias>/
├── pre.d/
├── post.d/
└── xrandr
Hook directories are executed lexically, synchronously, and without any
background processes. Use the state/last_signature file to inspect what was
last applied or delete it to force a full evaluation on the next run.
AUTODISPLAY_STATE_HOME– override the base path used in place of$HOME.AUTODISPLAY_XRANDR_FIXTURE– consume syntheticxrandr --queryoutput.
The trigger is intended to be executed by udev (95-autodisplay.rules). It:
- Creates
/tmp/autodisplay.lockto avoid concurrent invocations. - Searches
/procfor an Xorg/Xwayland session unlessAUTODISPLAY_TRIGGER_USERis set. - Drops privileges to that user, sets
DISPLAY/XAUTHORITY, and execs the dispatcher. - Waits for the dispatcher to exit and logs to
/tmp/autodisplay-trigger.log.
You can run it manually, for example:
sudo AUTODISPLAY_TRIGGER_USER=$USER AUTODISPLAY_TRIGGER_DISPLAY=:0 \
AUTODISPLAY_DISPATCHER=$(pwd)/build/bin/autodisplay-dispatcher \
./build/bin/autodisplay-triggerautodisplay-dispatcher --force– reapply the current signature regardless of cache state.autodisplay-dispatcher --save office– snapshot a layout and generate hooks.tail -f /tmp/autodisplay.log /tmp/autodisplay-trigger.log– inspect logs.AUTODISPLAY_XRANDR_FIXTURE=fixtures/xrandr-dual.txt \ AUTODISPLAY_STATE_HOME=$(mktemp -d) \ ./build/bin/autodisplay-dispatcher --print-signature– dry run without X.
AutoDisplay is released under the Beer-Ware License (Revision 42) with Velaar v@alamos.link as the licensor. If the software helps you, feel free to buy them a beer.