├── .flake8 ├── .gitignore ├── Makefile ├── README.md ├── autorandr.1 ├── autorandr.py ├── contrib ├── autorandr_launcher │ ├── .gitignore │ ├── autorandr_launcher.c │ └── makefile ├── autorandr_nitrogen_wallpaper │ └── autorandr_nitrogen_wallpaper ├── bash_completion │ └── autorandr ├── etc │ └── xdg │ │ └── autostart │ │ ├── autorandr-launcher.desktop │ │ ├── autorandr-lid-listener.desktop │ │ └── autorandr.desktop ├── fish_completion │ └── autorandr.fish ├── listen_lid.sh ├── packaging │ ├── debian │ │ ├── debian │ │ │ └── control │ │ └── make_deb.sh │ └── rpm │ │ └── autorandr.spec ├── pm-utils │ └── 40autorandr ├── systemd │ ├── autorandr-lid-listener.service │ └── autorandr.service └── zsh_completion │ └── _autorandr ├── gpl-3.0.txt └── setup.py /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | ignore = E722 3 | max-line-length = 130 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .*.swp 2 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | DESTDIR=/ 2 | PREFIX=/usr/ 3 | RPM_SPEC=contrib/packaging/rpm/autorandr.spec 4 | CFLAGS?=-O2 -Wall 5 | CLEANUP_FILES= 6 | 7 | .PHONY: all install uninstall autorandr bash_completion autostart_config pmutils systemd udev 8 | 9 | all: 10 | @echo "Call \"make install\" to install this program." 11 | @echo "Call \"make uninstall\" to remove this program." 12 | @echo 13 | @echo "The following components were autodetected and will be installed:" 14 | @echo " "$(DEFAULT_TARGETS) 15 | @echo 16 | @echo "The following locations have been detected (from pkg-config):" 17 | @echo " - BASH_COMPLETIONS_DIR: $(BASH_COMPLETIONS_DIR)" 18 | @echo " - SYSTEMD_UNIT_DIR: $(SYSTEMD_UNIT_DIR)" 19 | @echo " - UDEV_RULES_DIR: $(UDEV_RULES_DIR)" 20 | @echo " - PM_SLEEPHOOKS_DIR: $(PM_SLEEPHOOKS_DIR)" 21 | @echo 22 | @echo "You can use the TARGETS variable to override this, but need to set" 23 | @echo "the SYSTEMD_UNIT_DIR, PM_SLEEPHOOKS_DIR and UDEV_RULES_DIR variables" 24 | @echo "in case they were not detected correctly." 25 | @echo 26 | @echo 'E.g. "make install TARGETS='autorandr pmutils' PM_UTILS_DIR=/etc/pm/sleep.d".' 27 | @echo 28 | @echo "An additional TARGETS variable \"launcher\" is available. This" 29 | @echo "installs a launcher called \"autorandr_launcher\". The launcher" 30 | @echo "is able to be run by the user and calls autorandr automatically" 31 | @echo "without using udev rules. The launcher is an alternative to the" 32 | @echo "udev/systemd setup that is more stable for some users." 33 | @echo 34 | @echo "The following additional targets are available:" 35 | @echo 36 | @echo " make deb creates a Debian package" 37 | @echo " make rpm creates a RPM package" 38 | 39 | # Rules for autorandr itself 40 | DEFAULT_TARGETS=autorandr 41 | 42 | install_autorandr: 43 | mkdir -p ${DESTDIR}${PREFIX}/bin 44 | install -m 755 autorandr.py ${DESTDIR}${PREFIX}/bin/autorandr 45 | 46 | uninstall_autorandr: 47 | rm -f ${DESTDIR}${PREFIX}/bin/autorandr 48 | 49 | # Rules for bash-completion 50 | BASH_COMPLETIONS_DIR:=$(shell pkg-config --variable=completionsdir bash-completion 2>/dev/null) 51 | ifneq (,$(BASH_COMPLETIONS_DIR)) 52 | DEFAULT_TARGETS+=bash_completion 53 | endif 54 | 55 | install_bash_completion: 56 | mkdir -p ${DESTDIR}/${BASH_COMPLETIONS_DIR} 57 | install -m 644 contrib/bash_completion/autorandr ${DESTDIR}/${BASH_COMPLETIONS_DIR}/autorandr 58 | 59 | uninstall_bash_completion: 60 | rm -f ${DESTDIR}/${BASH_COMPLETIONS_DIR}/autorandr 61 | 62 | # Rules for autostart config 63 | XDG_AUTOSTART_DIR=/etc/xdg/autostart 64 | DEFAULT_TARGETS+=autostart_config 65 | 66 | install_autostart_config: 67 | mkdir -p ${DESTDIR}/${XDG_AUTOSTART_DIR} 68 | install -m 644 contrib/etc/xdg/autostart/autorandr.desktop ${DESTDIR}/${XDG_AUTOSTART_DIR}/autorandr.desktop 69 | # KDE-specific autostart (workaround for https://github.com/systemd/systemd/issues/18791) 70 | install -m 644 contrib/etc/xdg/autostart/autorandr.desktop ${DESTDIR}/${XDG_AUTOSTART_DIR}/autorandr-kde.desktop 71 | desktop-file-edit --remove-key=X-GNOME-Autostart-Phase --add-only-show-in=KDE ${DESTDIR}/${XDG_AUTOSTART_DIR}/autorandr-kde.desktop 72 | 73 | ifneq ($(PREFIX),/usr/) 74 | sed -i -re 's#/usr/bin/autorandr#$(subst #,\#,${PREFIX})/bin/autorandr#g' ${DESTDIR}/${XDG_AUTOSTART_DIR}/autorandr.desktop 75 | sed -i -re 's#/usr/bin/autorandr#$(subst #,\#,${PREFIX})/bin/autorandr#g' ${DESTDIR}/${XDG_AUTOSTART_DIR}/autorandr-kde.desktop 76 | endif 77 | 78 | uninstall_autostart_config: 79 | rm -f ${DESTDIR}/${XDG_AUTOSTART_DIR}/autorandr.desktop 80 | rm -f ${DESTDIR}/${XDG_AUTOSTART_DIR}/autorandr-kde.desktop 81 | 82 | # Rules for systemd 83 | SYSTEMD_UNIT_DIR:=$(shell pkg-config --variable=systemdsystemunitdir systemd 2>/dev/null) 84 | ifneq (,$(SYSTEMD_UNIT_DIR)) 85 | DEFAULT_TARGETS+=systemd 86 | endif 87 | 88 | install_systemd: 89 | $(if $(SYSTEMD_UNIT_DIR),,$(error SYSTEMD_UNIT_DIR is not defined)) 90 | mkdir -p ${DESTDIR}/${SYSTEMD_UNIT_DIR} 91 | install -m 644 contrib/systemd/autorandr.service ${DESTDIR}/${SYSTEMD_UNIT_DIR}/autorandr.service 92 | install -m 644 contrib/systemd/autorandr-lid-listener.service ${DESTDIR}/${SYSTEMD_UNIT_DIR}/autorandr-lid-listener.service 93 | ifneq ($(PREFIX),/usr/) 94 | sed -i -re 's#/usr/bin/autorandr#$(subst #,\#,${PREFIX})/bin/autorandr#g' ${DESTDIR}/${SYSTEMD_UNIT_DIR}/autorandr.service 95 | endif 96 | @echo 97 | @echo "To activate the systemd units, run this command as root:" 98 | @echo " systemctl daemon-reload" 99 | @echo " systemctl enable autorandr.service" 100 | @echo " systemctl enable autorandr-lid-listener.service" 101 | @echo 102 | 103 | uninstall_systemd: 104 | $(if $(SYSTEMD_UNIT_DIR),,$(error SYSTEMD_UNIT_DIR is not defined)) 105 | rm -f ${DESTDIR}/${SYSTEMD_UNIT_DIR}/autorandr.service 106 | rm -f ${DESTDIR}/${SYSTEMD_UNIT_DIR}/autorandr-lid-listener.service 107 | 108 | # Rules for pmutils 109 | PM_SLEEPHOOKS_DIR:=$(shell pkg-config --variable=pm_sleephooks pm-utils 2>/dev/null) 110 | ifneq (,$(PM_SLEEPHOOKS_DIR)) 111 | ifeq (,$(SYSTEMD_UNIT_DIR)) 112 | DEFAULT_TARGETS+=pmutils 113 | endif 114 | endif 115 | 116 | install_pmutils: 117 | $(if $(PM_SLEEPHOOKS_DIR),,$(error PM_SLEEPHOOKS_DIR is not defined)) 118 | mkdir -p ${DESTDIR}/${PM_SLEEPHOOKS_DIR} 119 | install -m 755 contrib/pm-utils/40autorandr ${DESTDIR}/${PM_SLEEPHOOKS_DIR}/40autorandr 120 | ifneq ($(PREFIX),/usr/) 121 | sed -i -re 's#/usr/bin/autorandr#$(subst #,\#,${PREFIX})/bin/autorandr#g' ${DESTDIR}/${PM_SLEEPHOOKS_DIR}/40autorandr 122 | endif 123 | 124 | uninstall_pmutils: 125 | $(if $(PM_SLEEPHOOKS_DIR),,$(error PM_SLEEPHOOKS_DIR is not defined)) 126 | rm -f ${DESTDIR}/${PM_SLEEPHOOKS_DIR}/40autorandr 127 | 128 | 129 | # Rules for udev 130 | UDEV_RULES_DIR:=$(shell pkg-config --variable=udevdir udev 2>/dev/null)/rules.d 131 | ifneq (/rules.d,$(UDEV_RULES_DIR)) 132 | DEFAULT_TARGETS+=udev 133 | endif 134 | 135 | install_udev: 136 | $(if $(UDEV_RULES_DIR),,$(error UDEV_RULES_DIR is not defined)) 137 | mkdir -p ${DESTDIR}/${UDEV_RULES_DIR}/ 138 | echo 'ACTION=="change", SUBSYSTEM=="drm", RUN+="$(if $(findstring systemd, $(DEFAULT_TARGETS)),/bin/systemctl start --no-block autorandr.service,${PREFIX}/bin/autorandr --batch --change --default default)"' > ${DESTDIR}/${UDEV_RULES_DIR}/40-monitor-hotplug.rules 139 | @echo 140 | @echo "To activate the udev rules, run this command as root:" 141 | @echo " udevadm control --reload-rules" 142 | @echo 143 | 144 | uninstall_udev: 145 | $(if $(UDEV_RULES_DIR),,$(error UDEV_RULES_DIR is not defined)) 146 | rm -f ${DESTDIR}/${UDEV_RULES_DIR}/40-monitor-hotplug.rules 147 | 148 | # Rules for manpage 149 | MANDIR:=${PREFIX}/share/man/man1 150 | DEFAULT_TARGETS+=manpage 151 | 152 | install_manpage: 153 | mkdir -p ${DESTDIR}/${MANDIR} 154 | cp autorandr.1 ${DESTDIR}/${MANDIR} 155 | 156 | uninstall_manpage: 157 | rm -f ${DESTDIR}/${MANDIR}/autorandr.1 158 | 159 | # Rules for launcher 160 | LAUNCHER_LDLIBS=$(shell pkg-config --libs pkg-config xcb xcb-randr 2>/dev/null) 161 | ifneq (,$(LAUNCHER_LDLIBS)) 162 | CLEANUP_FILES+=contrib/autorandr_launcher/autorandr-launcher 163 | LAUNCHER_CFLAGS=$(shell pkg-config --cflags pkg-config xcb xcb-randr 2>/dev/null) 164 | DEF_AUTORANDR_PATH="-DAUTORANDR_PATH=\"${DESTDIR}${PREFIX}/bin/autorandr\"" 165 | contrib/autorandr_launcher/autorandr-launcher: contrib/autorandr_launcher/autorandr_launcher.c 166 | $(CC) $(CFLAGS) $(LAUNCHER_CFLAGS) $(DEF_AUTORANDR_PATH) -o $@ $+ $(LDFLAGS) $(LAUNCHER_LDLIBS) $(LDLIBS) 167 | 168 | install_launcher: contrib/autorandr_launcher/autorandr-launcher 169 | mkdir -p ${DESTDIR}${PREFIX}/bin 170 | install -m 755 contrib/autorandr_launcher/autorandr-launcher ${DESTDIR}${PREFIX}/bin/autorandr-launcher 171 | mkdir -p ${DESTDIR}/${XDG_AUTOSTART_DIR} 172 | install -m 644 contrib/etc/xdg/autostart/autorandr-launcher.desktop ${DESTDIR}/${XDG_AUTOSTART_DIR}/autorandr-launcher.desktop 173 | ifneq ($(PREFIX),/usr/) 174 | sed -i -re 's#/usr/bin/autorandr-launcher#$(subst #,\#,${PREFIX})/bin/autorandr-launcher#g' ${DESTDIR}/${XDG_AUTOSTART_DIR}/autorandr-launcher.desktop 175 | endif 176 | endif 177 | 178 | uninstall_launcher: 179 | rm -f ${DESTDIR}${PREFIX}/bin/autorandr-launcher 180 | rm -f ${DESTDIR}/${XDG_AUTOSTART_DIR}/autorandr-launcher.desktop 181 | 182 | TARGETS=$(DEFAULT_TARGETS) 183 | install: $(patsubst %,install_%,$(TARGETS)) 184 | uninstall: $(patsubst %,uninstall_%,$(TARGETS)) 185 | 186 | deb: 187 | ./contrib/packaging/debian/make_deb.sh 188 | 189 | rpm: 190 | spectool -g -R $(RPM_SPEC) 191 | rpmbuild -ba $(RPM_SPEC) 192 | 193 | clean: 194 | rm -f $(CLEANUP_FILES) 195 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # autorandr 2 | 3 | Automatically select a display configuration based on connected devices 4 | 5 | ## Branch information 6 | 7 | This is a compatible Python rewrite of 8 | [wertarbyte/autorandr](https://github.com/wertarbyte/autorandr). Contributions 9 | for bash-completion, fd.o/XDG autostart, Nitrogen, pm-utils, and systemd can be 10 | found under [contrib](contrib/). 11 | 12 | The original [wertarbyte/autorandr](https://github.com/wertarbyte/autorandr) 13 | tree is unmaintained, with lots of open pull requests and issues. I forked it 14 | and merged what I thought were the most important changes. If you are searching 15 | for that version, see the [`legacy` branch](https://github.com/phillipberndt/autorandr/tree/legacy). 16 | Note that the Python version is better suited for non-standard configurations, 17 | like if you use `--transform` or `--reflect`. If you use `auto-disper`, you 18 | have to use the bash version, as there is no disper support in the Python 19 | version (yet). Both versions use a compatible configuration file format, so 20 | you can, to some extent, switch between them. I will maintain the `legacy` 21 | branch until @wertarbyte finds the time to maintain his branch again. 22 | 23 | If you are interested in why there are two versions around, see 24 | [#7](https://github.com/phillipberndt/autorandr/issues/7), 25 | [#8](https://github.com/phillipberndt/autorandr/issues/8) and 26 | especially 27 | [#12](https://github.com/phillipberndt/autorandr/issues/12) 28 | if you are unhappy with this version and would like to contribute to the bash 29 | version. 30 | 31 | ## License information and authors 32 | 33 | autorandr is available under the terms of the GNU General Public License 34 | (version 3). 35 | 36 | Contributors to this version of autorandr are: 37 | 38 | * Adrián López 39 | * andersonjacob 40 | * Alexander Lochmann 41 | * Alexander Wirt 42 | * Brice Waegeneire 43 | * Chris Dunder 44 | * Christoph Gysin 45 | * Christophe-Marie Duquesne 46 | * Daniel Hahler 47 | * Maciej Sitarz 48 | * Mathias Svensson 49 | * Matthew R Johnson 50 | * Nazar Mokrynskyi 51 | * Phillip Berndt 52 | * Rasmus Wriedt Larsen 53 | * Sam Coulter 54 | * Simon Wydooghe 55 | * Stefan Tomanek 56 | * stormc 57 | * tachylatus 58 | * Timo Bingmann 59 | * Timo Kaufmann 60 | * Tomasz Bogdal 61 | * Victor Häggqvist 62 | * Jan-Oliver Kaiser 63 | * Alexandre Viau 64 | 65 | ## Installation/removal 66 | 67 | You can use the `autorandr.py` script as a stand-alone binary. If you'd like to 68 | install it as a system-wide application, there is a Makefile included that also 69 | places some configuration files in appropriate directories such that autorandr 70 | is invoked automatically when a monitor is connected or removed, the system 71 | wakes up from suspend, or a user logs into an X11 session. Run `make install` 72 | as root to install it. 73 | 74 | If you prefer to have a system wide install managed by your package manager, 75 | you can 76 | 77 | * Use the [official Arch package](https://archlinux.org/packages/extra/any/autorandr/). 78 | * Use the [official Debian package](https://packages.debian.org/sid/x11/autorandr) on sid 79 | * Use the [official Fedora package](https://packages.fedoraproject.org/pkgs/autorandr/autorandr/) on Fedora 39+. 80 | * Use the [FreeBSD Ports Collection](https://www.freshports.org/x11/autorandr/) on FreeBSD. 81 | * Use the [official Gentoo package](https://packages.gentoo.org/packages/x11-misc/autorandr). 82 | * Use the 83 | [nix package](https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/services/misc/autorandr.nix) 84 | on NixOS. 85 | * Use the 86 | [guix package](https://git.savannah.gnu.org/cgit/guix.git/log/gnu/packages/xdisorg.scm?qt=grep&q=autorandr) 87 | on Guix. 88 | * Use the [SlackBuild](https://slackbuilds.org/repository/14.2/desktop/autorandr/) on Slackware. 89 | * Use the automated nightlies generated by the 90 | [openSUSE build service](https://build.opensuse.org/package/show/home:phillipberndt/autorandr) 91 | for various distributions (RPM and DEB based). 92 | * Use the [X binary package system](https://wiki.voidlinux.eu/XBPS)' on Void Linux 93 | * Build a .deb-file from the source tree using `make deb`. 94 | * Build a .rpm-file from the source tree using `make rpm`. 95 | 96 | We appreciate packaging scripts for other distributions, please file a pull 97 | request if you write one. 98 | 99 | If you prefer `pip` over your package manager, you can install autorandr with: 100 | 101 | sudo pip install "git+http://github.com/phillipberndt/autorandr#egg=autorandr" 102 | 103 | or simply 104 | 105 | sudo pip install autorandr 106 | 107 | if you prefer to use a stable version. 108 | 109 | ## How to use 110 | 111 | Save your current display configuration and setup with: 112 | 113 | autorandr --save mobile 114 | 115 | Connect an additional display, configure your setup and save it: 116 | 117 | autorandr --save docked 118 | 119 | Now autorandr can detect which hardware setup is active: 120 | 121 | $ autorandr 122 | mobile 123 | docked (detected) 124 | 125 | To automatically reload your setup: 126 | 127 | $ autorandr --change 128 | 129 | To manually load a profile: 130 | 131 | $ autorandr --load 132 | 133 | or simply: 134 | 135 | $ autorandr 136 | 137 | autorandr tries to avoid reloading an identical configuration. To force the 138 | (re)configuration: 139 | 140 | $ autorandr --load --force 141 | 142 | To prevent a profile from being loaded, place a script call _block_ in its 143 | directory. The script is evaluated before the screen setup is inspected, and 144 | in case of it returning a value of 0 the profile is skipped. This can be used 145 | to query the status of a docking station you are about to leave. 146 | 147 | If no suitable profile can be identified, the current configuration is kept. 148 | To change this behaviour and switch to a fallback configuration, specify 149 | `--default `. The system-wide installation of autorandr by default 150 | calls autorandr with a parameter `--default default`. There are three special, 151 | virtual configurations called `horizontal`, `vertical` and `common`. They 152 | automatically generate a configuration that incorporates all screens 153 | connected to the computer. You can symlink `default` to one of these 154 | names in your configuration directory to have autorandr use any of them 155 | as the default configuration without you having to change the system-wide 156 | configuration. 157 | 158 | You can store default values for any option in an INI-file located at 159 | `~/.config/autorandr/settings.ini`. In a `config` section, you may place any 160 | default values in the form `option-name=option-argument`. 161 | 162 | A common and effective use of this is to specify default `skip-options`, for 163 | instance skipping the `gamma` setting if using 164 | [`redshift`](https://github.com/jonls/redshift) as a daemon. To implement 165 | the equivalent of `--skip-options gamma`, your `settings.ini` file should look 166 | like this: 167 | 168 | ``` 169 | [config] 170 | skip-options=gamma 171 | ``` 172 | 173 | ## Advanced usage 174 | 175 | ### Hook scripts 176 | 177 | Three more scripts can be placed in the configuration directory 178 | (as defined by the [XDG spec](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html), 179 | usually `~/.config/autorandr` or `~/.autorandr` if you have an old installation 180 | for user configuration and `/etc/xdg/autorandr` for system wide configuration): 181 | 182 | - `postswitch` is executed *after* a mode switch has taken place. This can be 183 | used to notify window managers or other applications about the switch. 184 | - `preswitch` is executed *before* a mode switch takes place. 185 | - `postsave` is executed after a profile was stored or altered. 186 | - `predetect` is executed before autorandr attempts to run xrandr. 187 | 188 | These scripts must be executable and can be placed directly in the configuration 189 | directory, where they will always be executed, or in the profile subdirectories, 190 | where they will only be executed on changes regarding that specific profile. 191 | 192 | Instead (or in addition) to these scripts, you can also place as many executable 193 | files as you like in subdirectories called `script_name.d` (e.g. `postswitch.d`). 194 | The order of execution of scripts in these directories is by file name, you can 195 | force a certain ordering by naming them `10-wallpaper`, `20-restart-wm`, etc. 196 | 197 | If a script with the same name occurs multiple times, user configuration 198 | takes precedence over system configuration (as specified by the 199 | [XDG spec](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html)) 200 | and profile configuration over general configuration. 201 | 202 | As a concrete example, suppose you have the files 203 | 204 | - `/etc/xdg/autorandr/postswitch` 205 | - `~/.config/autorandr/postswitch` 206 | - `~/.config/autorandr/postswitch.d/notify-herbstluftwm` 207 | - `~/.config/autorandr/docked/postswitch` 208 | 209 | and switch from `mobile` to `docked`. Then 210 | `~/.config/autorandr/docked/postswitch` is executed, since the profile specific 211 | configuration takes precedence, and 212 | `~/.config/autorandr/postswitch.d/notify-herbstluftwm` is executed, since 213 | it has a unique name. 214 | 215 | If you switch back from `docked` to `mobile`, `~/.config/autorandr/postswitch` 216 | is executed instead of the `docked` specific `postswitch`. 217 | 218 | If you experience issues with xrandr being executed too early after connecting 219 | a new monitor, then you can use a `predetect` script to delay the execution. 220 | Write e.g. `sleep 1` into that file to make autorandr wait a second before 221 | running `xrandr`. 222 | 223 | #### Variables 224 | 225 | Some of autorandr's state is exposed as environment variables 226 | prefixed with `AUTORANDR_`, such as: 227 | - `AUTORANDR_CURRENT_PROFILE` 228 | - `AUTORANDR_CURRENT_PROFILES` 229 | - `AUTORANDR_PROFILE_FOLDER` 230 | - `AUTORANDR_MONITORS` 231 | 232 | with the intention that they can be used within the hook scripts. 233 | 234 | For instance, you might display which profile has just been activated by 235 | including the following in a `postswitch` script: 236 | ```sh 237 | notify-send -i display "Display profile" "$AUTORANDR_CURRENT_PROFILE" 238 | ``` 239 | 240 | The one kink is that during `preswitch`, `AUTORANDR_CURRENT_PROFILE` is 241 | reporting the *upcoming* profile rather than the *current* one. 242 | 243 | ### Wildcard EDID matching 244 | 245 | The EDID strings in the `~/.config/autorandr/*/setup` files may contain an 246 | asterisk to enable wildcard matching: Such EDIDs are matched against connected 247 | monitors using the usual file name globbing rules. This can be used to create 248 | profiles matching multiple (or any) monitors. 249 | 250 | ### udev triggers with NVidia cards 251 | 252 | In order for `udev` to detect `drm` events from the native NVidia driver, the 253 | kernel parameter `nvidia-drm.modeset` must be set to 1. For example, add a file 254 | `/etc/modprobe.d/nvidia-drm-modeset.conf`: 255 | 256 | ``` 257 | options nvidia_drm modeset=1 258 | ``` 259 | 260 | ### Wayland 261 | 262 | Before running autorandr will check the environment for the `WAYLAND_DISPLAY` 263 | variable to check if the program is running in a Wayland session. This is to 264 | avoid issues between usage of xrandr in Wayland environments. 265 | 266 | If you need to run autorandr in a Wayland environment, one workaround is to 267 | unset the `WAYLAND_DISPLAY` variable before running the program, such as: 268 | 269 | ``` 270 | WAYLAND_DISPLAY= autorandr 271 | ``` 272 | 273 | ## Changelog 274 | 275 | **autorandr 1.15** 276 | * *2023-11-27* Several regex literal bug fixes 277 | * *2023-12-27* Fix #375: Listen to correct events in launcher 278 | * *2024-03-03* Fix #367: Skip profiles without outputs 279 | 280 | 281 | **autorandr 1.14** 282 | * *2023-06-22* Direct --match-edid renaming of output messages to stderr 283 | * *2023-06-22* Add Wayland awareness 284 | * *2023-06-22* Various minor auxiliary tooling bug fixes, see git-log 285 | 286 | **autorandr 1.13.3** 287 | * *2023-01-24* Revert udev rule to rely on "change" event (see #324) 288 | 289 | **autorandr 1.13.2** 290 | * *2023-01-23* Fix autostart in KDE (see #320) 291 | * *2023-01-23* Match add/remove rather than change in udev rule (see #321) 292 | * *2023-01-23* Fix wildcard use in EDIDs (see #322) 293 | * *2023-01-23* Do a final xrandr call to set the frame buffer size (see #319) 294 | 295 | **autorandr 1.13.1** 296 | * *2023-01-16* Fix bug with Version comparison 297 | 298 | **autorandr 1.13** 299 | * *2023-01-15* Add reversed horizontal/vertical profiles 300 | * *2023-01-15* Fix distutils deprecation warning 301 | * *2023-01-15* Print error when user script fails 302 | * *2022-12-01* Support `--skip-options set` to skip setting properties 303 | 304 | **autorandr 1.12.1** 305 | * *2021-12-22* Fix `--match-edid` (see #273) 306 | 307 | **autorandr 1.12** 308 | * *2021-12-16* Switch default interpreter to Python 3 309 | * *2021-12-16* Add `--list` to list all profiles 310 | * *2021-12-16* Add `--cycle` to cycle all detected profiles 311 | * *2021-12-16* Store display properties (see #204) 312 | 313 | **autorandr 1.11** 314 | * *2020-05-23* Handle empty sys.executable 315 | * *2020-06-08* Fix Python 2 compatibility 316 | * *2020-10-06* Set group membership of users in batch mode 317 | 318 | **autorandr 1.10.1** 319 | * *2020-05-04* Revert making the launcher the default (fixes #195) 320 | 321 | **autorandr 1.10** 322 | * *2020-04-23* Fix hook script execution order to match description from readme 323 | * *2020-04-11* Handle negative gamma values (fixes #188) 324 | * *2020-04-11* Sort approximate matches in detected profiles by quality of match 325 | * *2020-01-31* Handle non-ASCII environment variables (fixes #180) 326 | * *2019-12-31* Fix output positioning if the top-left output is not the first 327 | * *2019-12-31* Accept negative gamma values (and interpret them as 0) 328 | * *2019-12-31* Prefer the X11 launcher over systemd/udev configuration 329 | 330 | **autorandr 1.9** 331 | 332 | * *2019-11-10* Count closed lids as disconnected outputs 333 | * *2019-10-05* Do not overwrite existing configurations without `--force` 334 | * *2019-08-16* Accept modes that don't match the WWWxHHH pattern 335 | * *2019-03-22* Improve bash autocompletion 336 | * *2019-03-21* Store CRTC values in configurations 337 | * *2019-03-24* Fix handling of recently disconnected outputs (See #128 and #143) 338 | 339 | **autorandr 1.8.1** 340 | 341 | * *2019-03-18* Removed mandb call from Makefile 342 | 343 | **autorandr 1.8** 344 | 345 | * *2019-02-17* Add an X11 daemon that runs autorandr when a display connects (by @rliou92, #127) 346 | * *2019-02-17* Replace width=0 check with disconnected to detect disconnected monitors (by @joseph-jones, #139) 347 | * *2019-02-17* Fix handling of empty padding (by @jschwab, #138) 348 | * *2019-02-17* Add a man page (by @somers-all-the-time, #133) 349 | 350 | **autorandr 1.7** 351 | 352 | * *2018-09-25* Fix FB size computation with rotated screens (by @Janno, #117) 353 | 354 | **autorandr 1.6** 355 | 356 | * *2018-04-19* Bugfix: Do not load default profile unless --change is set 357 | * *2018-04-30* Added a `AUTORANDR_MONITORS` variable to hooks (by @bricewge, #106) 358 | * *2018-06-29* Fix detection of current configuration if extra monitors are active 359 | * *2018-07-11* Bugfix in the latest change: Correctly handle "off" minitors when comparing 360 | * *2018-07-19* Do not kill spawned user processes from systemd unit 361 | * *2018-07-20* Correctly handle "off" monitors when comparing -- fixup for another bug. 362 | 363 | **autorandr 1.5** 364 | 365 | * *2018-01-03* Add --version 366 | * *2018-01-04* Fixed vertical/horizontal/clone-largest virtual profiles 367 | * *2018-03-07* Output all non-error messages to stdout instead of stderr 368 | * *2018-03-25* Add --detected and --current to filter the profile list output 369 | * *2018-03-25* Allow wildcard matching in EDIDs 370 | 371 | **autorandr 1.4** 372 | 373 | * *2017-12-22* Fixed broken virtual profile support 374 | * *2017-12-14* Added support for a settings file 375 | * *2017-12-14* Added a virtual profile `off`, which disables all screens 376 | 377 | **autorandr 1.3** 378 | 379 | * *2017-11-13* Add a short form for `--load` 380 | * *2017-11-21* Fix environment stealing in `--batch` mode (See #87) 381 | 382 | **autorandr 1.2** 383 | 384 | * *2017-07-16* Skip `--panning` unless it is required (See #72) 385 | * *2017-10-13* Add `clone-largest` virtual profile 386 | 387 | **autorandr 1.1** 388 | 389 | * *2017-06-07* Call systemctl with `--no-block` from udev rule (See #61) 390 | * *2017-01-20* New script hook, `predetect` 391 | * *2017-01-18* Accept comments (lines starting with `#`) in config/setup files 392 | 393 | **autorandr 1.0** 394 | 395 | * *2016-12-07* Tag the current code as version 1.0.0; see github issue #54 396 | * *2016-10-03* Install a desktop file to `/etc/xdg/autostart` by default 397 | -------------------------------------------------------------------------------- /autorandr.1: -------------------------------------------------------------------------------- 1 | .TH AUTORANDR 1 2 | .SH NAME 3 | autorandr \- automatically select a display configuration based on connected devices 4 | .SH SYNOPSIS 5 | .B autorandr 6 | [\fIOPTION\fR] [\fIPROFILE\fR] 7 | .SH DESCRIPTION 8 | .PP 9 | This program automatically detects connected display hardware and then loads an appropriate X11 setup using xrandr. It also supports the use of display profiles for different hardware setups. 10 | .PP 11 | Autorandr also includes several virtual configurations including \fBoff\fR, \fBcommon\fR, \fBclone-largest\fR, \fBhorizontal\fR, and \fBvertical\fR. See the documentation for explanation of each. 12 | .SH OPTIONS 13 | .TP 14 | \fB\-h\fR, \fB\-\-help 15 | \fRDisplay help text and exit 16 | .TP 17 | \fB\-c\fR, \fB\-\-change 18 | \fRAutomatically load the first detected profile 19 | .TP 20 | \fB\-d\fR, \fB\-\-default \fIPROFILE 21 | \fRMake profile \fIPROFILE\fR the default profile. The default profile is used if no suitable profile can be identified. Else, the current configuration is kept. 22 | .TP 23 | \fB\-l\fR, \fB\-\-load \fIPROFILE 24 | \fRLoad profile \fIPROFILE 25 | .TP 26 | \fB\-s\fR, \fB\-\-save \fIPROFILE 27 | \fRSave the current setup to profile \fIPROFILE 28 | .TP 29 | \fB\-r\fR, \fB\-\-remove \fIPROFILE 30 | \fRRemove profile \fIPROFILE 31 | .TP 32 | .BR \-\-batch 33 | \fRRun autorandr for all users with active X11 sessions 34 | .TP 35 | .BR \-\-current 36 | List only the current (active) configuration(s) 37 | .TP 38 | .BR \-\-config 39 | Dump the variable values of your current xrandr setup 40 | .TP 41 | .BR \-\-cycle 42 | Cycle through all detected profiles 43 | .TP 44 | .BR \-\-debug 45 | Enable verbose output 46 | .TP 47 | .BR \-\-detected 48 | List only the detected (i.e. available) configuration(s) 49 | .TP 50 | .BR \-\-dry\-run 51 | Don't change anything, only print the xrandr commands 52 | .TP 53 | .BR \-\-fingerprint 54 | Fingerprint the current hardware setup 55 | .TP 56 | .BR \-\-match-edid 57 | Match displays based on edid instead of name 58 | .TP 59 | .BR \-\-ignore-lid 60 | By default, closed lids are considered as disconnected if other outputs are detected. This flag disables this behaviour. 61 | .TP 62 | .BR \-\-force 63 | Force loading or reloading of a profile 64 | .TP 65 | .BR \-\-list 66 | List all profiles 67 | .TP 68 | \fB\-\-skip\-options [\fIOPTION\fR] ... 69 | \fRSet a comma\-separated list of xrandr arguments to skip both in change detection and profile application. See \fBxrandr(1)\fR for xrandr arguments. 70 | .TP 71 | .BR \-\-version 72 | Show version information and exit 73 | .SH FILES 74 | Configuration files are searched for in the \fIautorandr 75 | \fRdirectory in the colon separated list of paths in \fI$XDG_CONFIG_DIRS 76 | \fR- or in \fI/etc/xdg 77 | \fRif that var is not set. They are then looked for in \fI~/.autorandr 78 | \fRand if that doesn't exist, in \fI$XDG_CONFIG_HOME/autorandr 79 | \fRor in \fI~/.config/autorandr\fR if that var is unset. 80 | 81 | In each of those directories it looks for directories with \fIconfig\fR and 82 | \fIsetup\fR in them. It is best to manage these files with the 83 | \fBautorandr\fR utility. 84 | 85 | .SH DEFAULT OPTIONS 86 | 87 | You can store default values for any option in an INI-file located at 88 | \fI~/.config/autorandr/settings.ini\fR. In a config section, you may 89 | place any default values in the form \fIoption-name=option-argument\fR. 90 | 91 | .SH HOOK SCRIPTS 92 | 93 | Four more scripts can be placed in the configuration directory: 94 | .TP 95 | \fIpostswitch\fR 96 | Executed after a mode switch has taken place. This can be used to notify 97 | window managers or other applications about the switch. 98 | .TP 99 | \fIpreswitch\fR 100 | Executed before a mode switch takes place. 101 | .TP 102 | \fIpostsave\fR 103 | Executed after a profile was stored or altered. 104 | .TP 105 | \fIpredetect\fR 106 | Executed before autorandr attempts to run xrandr. 107 | 108 | .PP 109 | These scripts must be executable and can be placed directly in the 110 | configuration directory, where they will always be executed, or in 111 | the profile subdirectories, where they will only be executed on changes 112 | regarding that specific profile. 113 | 114 | Instead (or in addition) to these scripts, you can also place as many 115 | executable files as you like in subdirectories called script_name.d 116 | (e.g. postswitch.d). 117 | .PP 118 | 119 | Some of autorandr's state is exposed as environment variables prefixed with 120 | \fIAUTORANDR_\fR, such as: 121 | \fIAUTORANDR_CURRENT_PROFILE\fR, 122 | \fIAUTORANDR_CURRENT_PROFILES\fR, 123 | \fIAUTORANDR_PROFILE_FOLDER\fR, 124 | and \fIAUTORANDR_MONITORS\fR 125 | with the intention that they can be used within the hook scripts. 126 | 127 | The one kink is that during \fIpreswitch\fR, \fIAUTORANDR_CURRENT_PROFILE\fR 128 | is reporting the upcoming profile rather 129 | than the current one. 130 | 131 | .SH AUTHOR 132 | \fRPhillip Berndt 133 | .br 134 | See https://github.com/phillipberndt/autorandr for a full list of contributors. 135 | .SH REPORTING BUGS 136 | \fRReport issues upstream on GitHub: https://github.com/phillipberndt/autorandr/issues 137 | .br 138 | \fRPlease attach the output of \fBxrandr --verbose\fR to your bug report if appropriate. 139 | .SH SEE ALSO 140 | \fRFor examples, advanced usage (including predefined per-profile & global hooks and wildcard EDID matching), and full documentation, see https://github.com/phillipberndt/autorandr. 141 | -------------------------------------------------------------------------------- /autorandr.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # encoding: utf-8 3 | # 4 | # autorandr.py 5 | # Copyright (c) 2015, Phillip Berndt 6 | # 7 | # Autorandr rewrite in Python 8 | # 9 | # This script aims to be fully compatible with the original autorandr. 10 | # 11 | # This program is free software: you can redistribute it and/or modify 12 | # it under the terms of the GNU General Public License as published by 13 | # the Free Software Foundation, either version 3 of the License, or 14 | # (at your option) any later version. 15 | # 16 | # This program is distributed in the hope that it will be useful, 17 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | # GNU General Public License for more details. 20 | # 21 | # You should have received a copy of the GNU General Public License 22 | # along with this program. If not, see . 23 | # 24 | 25 | from __future__ import print_function 26 | 27 | import binascii 28 | import copy 29 | import getopt 30 | import hashlib 31 | import math 32 | import os 33 | import posix 34 | import pwd 35 | import re 36 | import shlex 37 | import subprocess 38 | import sys 39 | import shutil 40 | import time 41 | import glob 42 | 43 | from collections import OrderedDict 44 | from functools import reduce 45 | from itertools import chain 46 | 47 | 48 | if sys.version_info.major == 2: 49 | import ConfigParser as configparser 50 | else: 51 | import configparser 52 | 53 | __version__ = "1.15" 54 | 55 | try: 56 | input = raw_input 57 | except NameError: 58 | pass 59 | 60 | virtual_profiles = [ 61 | # (name, description, callback) 62 | ("off", "Disable all outputs", None), 63 | ("common", "Clone all connected outputs at the largest common resolution", None), 64 | ("clone-largest", "Clone all connected outputs with the largest resolution (scaled down if necessary)", None), 65 | ("horizontal", "Stack all connected outputs horizontally at their largest resolution", None), 66 | ("vertical", "Stack all connected outputs vertically at their largest resolution", None), 67 | ("horizontal-reverse", "Stack all connected outputs horizontally at their largest resolution in reverse order", None), 68 | ("vertical-reverse", "Stack all connected outputs vertically at their largest resolution in reverse order", None), 69 | ] 70 | 71 | properties = [ 72 | "Colorspace", 73 | "max bpc", 74 | "aspect ratio", 75 | "Broadcast RGB", 76 | "audio", 77 | "non-desktop", 78 | "TearFree", 79 | "underscan vborder", 80 | "underscan hborder", 81 | "underscan", 82 | "scaling mode", 83 | ] 84 | 85 | help_text = """ 86 | Usage: autorandr [options] 87 | 88 | -h, --help get this small help 89 | -c, --change automatically load the first detected profile 90 | -d, --default make profile the default profile 91 | -l, --load load profile 92 | -s, --save save your current setup to profile 93 | -r, --remove remove profile 94 | --batch run autorandr for all users with active X11 sessions 95 | --current only list current (active) configuration(s) 96 | --config dump your current xrandr setup 97 | --cycle automatically load the next detected profile 98 | --debug enable verbose output 99 | --detected only list detected (available) configuration(s) 100 | --dry-run don't change anything, only print the xrandr commands 101 | --fingerprint fingerprint your current hardware setup 102 | --ignore-lid treat outputs as connected even if their lids are closed 103 | --match-edid match displays based on edid instead of name 104 | --force force (re)loading of a profile / overwrite exiting files 105 | --list list configurations 106 | --skip-options