Skip to content

velaar/autodisplay-c

Repository files navigation

AutoDisplay

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.

Table of contents

What's new

  • 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 --force is 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 Makefile drives Clang with -march=native and gathers profile data via hyperfine before 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. Use AUTODISPLAY_STATE_HOME to redirect the configuration tree to a scratch directory during tests.
  • Manual trigger overrides – set AUTODISPLAY_TRIGGER_USER, AUTODISPLAY_TRIGGER_DISPLAY, and AUTODISPLAY_DISPATCHER when you need the trigger to target a specific user or an alternate dispatcher binary (the build harness uses this for PGO).

Build & benchmark

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 artefacts

During 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.

Installation

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 install

Installed files:

  • $(PREFIX)/bin/autodisplay-dispatcher
  • $(PREFIX)/bin/autodisplay-trigger
  • $(PREFIX)/share/autodisplay/autodisplay-prepopulate.sh
  • /etc/udev/rules.d/95-autodisplay.rules (overridable via UDEV_RULES_DIR)

After installing, reload udev so the hotplug rule is picked up:

sudo udevadm control --reload-rules
sudo udevadm trigger --subsystem-match=drm

The 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.

Dispatcher usage

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 (or default when none exists), runs the blocking pre hooks, applies xrandr, and finally runs the blocking post hooks.
  • --force bypasses 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 live xrandr --query output (or the configured fixture) and generates hook scaffolding.
  • --print-signature emits the current signature without modifying anything.

The dispatcher writes to /tmp/autodisplay.log so you can trace every decision.

Configuration tree

~/.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.

Environment helpers

  • AUTODISPLAY_STATE_HOME – override the base path used in place of $HOME.
  • AUTODISPLAY_XRANDR_FIXTURE – consume synthetic xrandr --query output.

Trigger behaviour

The trigger is intended to be executed by udev (95-autodisplay.rules). It:

  1. Creates /tmp/autodisplay.lock to avoid concurrent invocations.
  2. Searches /proc for an Xorg/Xwayland session unless AUTODISPLAY_TRIGGER_USER is set.
  3. Drops privileges to that user, sets DISPLAY/XAUTHORITY, and execs the dispatcher.
  4. 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-trigger

Forcing and troubleshooting

  • autodisplay-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.

License

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.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published