install it as a system-wide application, there is a Makefile included that also
places some configuration files in appropriate directories such that autorandr
is invoked automatically when a monitor is connected or removed, the system
-wakes up from suspend, or a user logs into an X11 session.
-
-For Debian-based distributions (including Ubuntu) it is recommended to call
-`make deb` to obtain a package that can be installed and removed with `dpkg`.
-
-On Arch Linux, there is [an aur package
-available](https://aur.archlinux.org/packages/autorandr-git/).
-
-autorandr is also packaged in the [nix package manager](https://nixos.org/nix/)
-repositories.
-
-On other distributions you can install autorandr by calling `make install` and
-remove it by calling `make uninstall`. Run `make` without arguments to obtain a
-list of what exactly will be installed.
+wakes up from suspend, or a user logs into an X11 session. Run `make install`
+as root to install it.
+
+If you prefer to have a system wide install managed by your package manager,
+you can
+
+* Use the [aur package](https://aur.archlinux.org/packages/autorandr-git/) on Arch
+* Use the [official Debian package](https://packages.debian.org/sid/x11/autorandr) on sid
+* Use the [ebuild from zugaina](https://gpo.zugaina.org/x11-misc/autorandr) on Gentoo.
+* Use the
+ [nix package](https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/services/misc/autorandr.nix)
+ on NixOS.
+* Use the automated nightlies generated by the
+ [openSUSE build service](https://build.opensuse.org/package/show/home:phillipberndt/autorandr)
+ for various distributions (RPM and DEB based).
+* Build a .deb-file from the source tree using `make deb`.
We appreciate packaging scripts for other distributions, please file a pull
request if you write one.
if you prefer to use a stable version.
-Automatically generated packages versions are available from the
-[openSUSE build service](https://build.opensuse.org/package/show/home:phillipberndt/autorandr).
-
## How to use
Save your current display configuration and setup with:
`~/.config/autorandr/settings.ini` in a section `config`. The most useful
candidate for doing that is `skip-options`, if you need it.
-## Hook scripts
+## Advanced usage
+
+### Hook scripts
Three more scripts can be placed in the configuration directory (as
(as defined by the [XDG spec](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html),
Write e.g. `sleep 1` into that file to make autorandr wait a second before
running `xrandr`.
+### Wildcard EDID matching
+
+The EDID strings in the `~/.config/autorandr/*/setup` files may contain an
+asterisk to enable wildcard matching: Such EDIDs are matched against connected
+monitors using the usual file name globbing rules. This can be used to create
+profiles matching multiple (or any) monitors.
+
## Changelog
+**autorandr 1.5**
+
+* *2018-01-03* Add --version
+* *2018-01-04* Fixed vertical/horizontal/clone-largest virtual profiles
+* *2018-03-07* Output all non-error messages to stdout instead of stderr
+* *2018-03-25* Add --detected and --current to filter the profile list output
+* *2018-03-25* Allow wildcard matching in EDIDs
+
**autorandr 1.4**
* *2017-12-22* Fixed broken virtual profile support
import binascii
import copy
+import fnmatch
import getopt
import hashlib
import os
else:
import configparser
+__version__ = "1.5"
+
try:
input = raw_input
except NameError:
-s, --save <profile> save your current setup to profile <profile>
-r, --remove <profile> remove profile <profile>
--batch run autorandr for all users with active X11 sessions
+--current only list current (active) configuration(s)
--config dump your current xrandr setup
--debug enable verbose output
+--detected only list detected (available) configuration(s)
--dry-run don't change anything, only print the xrandr commands
--fingerprint fingerprint your current hardware setup
--force force (re)loading of a profile
--skip-options <option> comma separated list of xrandr arguments (e.g. "gamma")
to skip both in detecting changes and applying a profile
+--version show version information and exit
If no suitable profile can be identified, the current configuration is kept.
To change this behaviour and switch to a fallback configuration, specify
return hashlib.md5(binascii.unhexlify(other.edid)).hexdigest() == self.edid
if len(self.edid) != 32 and len(other.edid) == 32 and not self.edid.startswith(XrandrOutput.EDID_UNAVAILABLE):
return hashlib.md5(binascii.unhexlify(self.edid)).hexdigest() == other.edid
+ if "*" in self.edid:
+ return fnmatch.fnmatch(other.edid, self.edid)
+ elif "*" in other.edid:
+ return fnmatch.fnmatch(self.edid, other.edid)
return self.edid == other.edid
def __ne__(self, other):
if a["preferred"]:
score += 10**6
return score
- modes = sorted(modes[output], key=key)
- mode = modes[-1]
+ output_modes = sorted(modes[output], key=key)
+ mode = output_modes[-1]
configuration[output].options["mode"] = mode["name"]
configuration[output].options["rate"] = mode["rate"]
configuration[output].options["pos"] = pos_specifier % shift
if a["preferred"]:
score += 10**6
return score
- modes = sorted(modes[output], key=key)
- mode = modes[-1]
+ output_modes = sorted(modes[output], key=key)
+ mode = output_modes[-1]
configuration[output].options["mode"] = mode["name"]
configuration[output].options["rate"] = mode["rate"]
configuration[output].options["pos"] = "0x0"
"Print the differences between two profiles for debugging"
if one == another:
return
- print("| Differences between the two profiles:", file=sys.stderr)
+ print("| Differences between the two profiles:")
for output in set(chain.from_iterable((one.keys(), another.keys()))):
if output not in one:
if "off" not in another[output].options:
- print("| Output `%s' is missing from the active configuration" % output, file=sys.stderr)
+ print("| Output `%s' is missing from the active configuration" % output)
elif output not in another:
if "off" not in one[output].options:
- print("| Output `%s' is missing from the new configuration" % output, file=sys.stderr)
+ print("| Output `%s' is missing from the new configuration" % output)
else:
for line in one[output].verbose_diff(another[output]):
- print("| [Output %s] %s" % (output, line), file=sys.stderr)
- print("\\-", file=sys.stderr)
+ print("| [Output %s] %s" % (output, line))
+ print("\\-")
def exit_help():
try:
opts, args = getopt.getopt(argv[1:], "s:r:l:d:cfh",
["batch", "dry-run", "change", "default=", "save=", "remove=", "load=",
- "force", "fingerprint", "config", "debug", "skip-options=", "help"])
+ "force", "fingerprint", "config", "debug", "skip-options=", "help",
+ "current", "detected", "version"])
except getopt.GetoptError as e:
print("Failed to parse options: {0}.\n"
"Use --help to get usage information.".format(str(e)),
if "-h" in options or "--help" in options:
exit_help()
+ if "--version" in options:
+ print("autorandr " + __version__)
+ sys.exit(0)
+
+ if "--current" in options and "--detected" in options:
+ print("--current and --detected are mutually exclusive.", file=sys.stderr)
+ sys.exit(posix.EX_USAGE)
+
# Batch mode
if "--batch" in options:
if ("DISPLAY" not in os.environ or not os.environ["DISPLAY"]) and os.getuid() == 0:
for profile_name in profiles.keys():
if profile_blocked(os.path.join(profile_path, profile_name), block_script_metadata):
- print("%s (blocked)" % profile_name, file=sys.stderr)
+ if "--current" not in options and "--detected" not in options:
+ print("%s (blocked)" % profile_name)
continue
props = []
if profile_name in detected_profiles:
props.append("(detected)")
if ("-c" in options or "--change" in options) and not load_profile:
load_profile = profile_name
+ elif "--detected" in options:
+ continue
if profile_name in current_profiles:
props.append("(current)")
- print("%s%s%s" % (profile_name, " " if props else "", " ".join(props)), file=sys.stderr)
+ elif "--current" in options:
+ continue
+ if "--current" in options or "--detected" in options:
+ print("%s" % (profile_name, ))
+ else:
+ print("%s%s%s" % (profile_name, " " if props else "", " ".join(props)))
if not configs_are_equal and "--debug" in options and profile_name in detected_profiles:
print_profile_differences(config, profiles[profile_name]["config"])