Every day, when I come home from work, I connect my Xubuntu XPS 15 9560 laptop to my 27” secondary monitor and need to do the same ritual:
- wait for xfce4-display-settings to pop up,
- select “extend to the right” (which restricts my secondary monitor to be on the right of my laptop),
- inally select advanced and adjust the position of the secondary monitor to roughly where it needs to be: a little above the laptop’s display.
I got tired of this very quickly, but XFCE’s Display settings lacks consistency and there’s no other way but to develop a custom solution for now.
So here are the steps:
xfce4-display-settings (or just open the Whisker menu and look for “Display”), then toggle “Configure new displays when connected”. This will disable the popup every time you connect a screen, since we’ll now do it automatically.
First, we have to find the right xrandr command to automatically setup your connect, e.g
xrandr --output DP-1 --mode 2560x1440 --pos 1920x0 --output eDP-1 --pos 0x700 --scale 1x1 in my case.
ARandR is a visual interface for xrandr (the X11 “resize and rotate“ protocol), which can also save commands as shell scripts. Install it with
sudo apt-get install ARandR.
Play with the displays until it works and then select
Layout -> Save As to save the command as a
.sh file. Experiment with the values until you get a minimal, reliable and pixel-perfect command.
The following script will do the actual automatic connection. It is heavily inspired by this StackOverflow answer: I struggled for a while to understand why my command couldn’t be run automatically until that answer indicated that it needed a DISPLAY handle and XAUTHORITY.
This is my script:
A couple of notes here:
- On line 4, the status of the display is inserted in a variable which we later check to determine the state of the screen. You should change the “DP-1” to the name of your display as it appears in
- On disconnected or unknown events, I let XFCE handle the automatic resizing. Otherwise,
/usr/bin/xrandr --autoshould be used.
- The xrandr command is executed if two conditions occur: the monitor is connected following the event, and the resolution appears in
xrandr -q. This is the purpose of line 14, but you should tune it to fit the xrandr query output.
udev is a Linux device manager, which generates various events. These can be observed through
sudo udevadm monitor --environment. What interests us here is that we can make a udev rule which can trigger a xrandr script on device change events.
So make a new rule, e.g
10 is intentionally a low priority number so we make sure our script has no conflicts. The content of the rule would probably be:
ACTION=="change", SUBSYSTEM=="drm", RUN+="/bin/sh -c 'cd /home/[user]/scripts; /bin/sh layout.sh'"
RUN indicates the path of the script we made in step 3. The
SUBSYSTEM are trigger rules for udev and can be tuned if you see that the script doesn’t run. Use the
sudo udevadm monitor --environment command above, then plug your monitor and see what events play.
After inserting or editing a udev rule, run
sudo udevadm control --reload-rules or even
sudo service udev restart. Check that the rule can be parsed by running
udevadm test ..., then run
udevadm trigger to trigger all the rules so you should at least see the date in the script log.
- For more complex setups (three screens, different home/work configurations), you can use autorandr which can detect the current configuration but still needs to be triggered by udev or other methods (or even manually), e.g here.
- If you use Nvidia drivers, this won’t work. Nvidia replaces the Linux device manager. Note that having an nvidia card might still work if you use X11/Nouveau drivers. But read on for other solutions.
- The way XFCE does it (as explained here) is that it reacts to xrandr RRScreenChangeNotify event. Note that this works with Nvidia drivers. The former link gives C and Python implementations here, and they work well with the same technique presented here, although you should remember to provide a DISPLAY handle and XAUTHORITY. I suggest using C with
gcc -o screen-watcher monitor_watcher.c -lxcb -lxcb-randr, calling xrandr with a
system()call, and making it a systemd service. Another approach is randrd which works the same way.