Posted on September 28, 2016
Automatically switch Xfce panel layout when plugging in a monitor
Xfce has great multi-monitor support. Different panels on each monitor, it all works great. I’ve used it with multiple monitors on my desktop for 5+ years. Love it.
But you run into some annoyances with laptops. Half the time I’m using my laptop on its own, and half the time I’m using it with an external monitor. You plug the monitor in for the first time, then you create a new panel for it and drag it over. But then when you unplug the monitor, that second panel doesn’t go away. Instead, it moves over to the main laptop screen and the only way to hide it is to delete it. Then when you plug the external monitor in again, you need to recreate it, readd all the items and so on.
Well, the Xubuntu team has made a tool called Xfce Panel Switch (Arch package: xfpanel-switch).
I’ll quickly walk though how to setup automatic switching.
Step One – Panel Configs
First, setup your panel structure the way you like it when you’re using just your laptop screen. Open Xfce Panel Switch, select Current Configuration, click Export, and save it as laptop.tar.bz2. Then plug your monitor in, setup your panels the way you like, select Current Configuration again, and export as externalmon.tar.bz2.
If you want to test out the panel switching, use the commands:
python3 /usr/share/xfpanel-switch/xfpanel-switch/panelconfig.py load /home/colin/laptop.tar.bz2 python3 /usr/share/xfpanel-switch/xfpanel-switch/panelconfig.py load /home/colin/externalmon.tar.bz2
Step Two – Udev and systemd
We could stop here and create a desktop shortcut we click each time, but where’s the fun is that?
Create a new udev rule to trigger our systemd service: /etc/udev/rules.d/95-monitor-hotplug.rules
ACTION=="change", KERNEL=="card0", SUBSYSTEM=="drm", RUN+="/usr/bin/systemctl start hot_plug.service"
Create our hot_plug service: /etc/systemd/system/hot_plug.service
[Unit] Description=Monitor hotplug [Service] Type=simple RemainAfterExit=no User=colin ExecStart=/usr/bin/bash /usr/local/bin/hotplug_monitor.sh [Install] WantedBy=multi-user.target
Replace colin with your own username
Create the script that our service executes: nano /usr/local/bin/hotplug_monitor.sh
#!/bin/bash # Replace colin with your username X_USER=colin export DISPLAY=:0 export XAUTHORITY=/home/$X_USER/.Xauthority export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus function connect() { # Remember to change the path to wherever you are storing your configs python3 /usr/share/xfpanel-switch/xfpanel-switch/panelconfig.py load /home/colin/externalmon.tar.bz2 } function disconnect() { # Remember to change the path to wherever you are storing your configs python3 /usr/share/xfpanel-switch/xfpanel-switch/panelconfig.py load /home/colin/laptop.tar.bz2 } # Replace card0-DP-1 with the card and port you are using if [ $(cat /sys/class/drm/card0-DP-1/status) == "connected" ] ; then connect elif [ $(cat /sys/class/drm/card0-DP-1/status) == "disconnected" ] ; then disconnect else exit fi
Remember to make it executable chmod +x /usr/local/bin/hotplug_monitor.sh
Important: you may need to replace card0-DP-1 in the above script with the card and port that you are using. I’m using VGA, for HDMI you probably need to check card0-HDMI-A-1 instead.
Also remember to change the paths to the location where you a storing your panel configs. I personally store them at /home/colin/.config/xfce4-panel-switcher/
(Optional) Step Three – Set monitor layout
Now that we have a script which will execute anything we like whenever we plug or unplug our monitor, lets also use it to have xrandr setup our monitor layout.
In the connect function, I have:
xrandr --output eDP1 --left-of DP1 --preferred --output eDP1 --primary
and in the disconnect function:
xrandr --output DP1 --off
This sets up my laptop monitor (eDP1) as my primary, and my VGA monitor (DP1) as a secondary monitor which is positioned to the right of it. You’ll have to change eDP1 and DP1 to reflect what your devices are. Look at the xrandr article on the Arch Wiki for more information.
Final thoughts
This saves me at least a couple minutes every time I plug my laptop in. Most of the time I didn’t even bother setting up panels on the secondary monitor because having to redo every time was getting old.
The obvious downside here is that every time you make any changes to your panel, you need to open the Xfce Panel Switcher app and export the new config to wherever it is you’re keeping them. But how often do you really need to change your panel layout? My desktop one hasn’t changed in years.
I also want to give thanks and credit to Iah on the Arch forums for posting how to detect the udev event for a monitor being plugged in.
Hope this helps!
This really helped me, thank you. Here’s some fixes to the instructions that I had to do to get it to work on my system:
1. Make sure to set hot_plug.service executable, can be done with:
sudo chmod +x /etc/systemd/system/hot_plug.service
2. The file hotplug_monitor.sh needs some modifications:
Line function connect() needs to be rewritten to:
function connect {
Make sure ‘ {‘ is directly after connect. Also remove ‘()’
The same applies for disconnect
The python3 commands looks in the wrong directory for the laptop.tar.bz2, the same applies for the externalmon.tar.bz2 file. Set these to the correct path.
3. xrandr is really useful, for HDMI it’s HDMI1 instead of DP1
4. Make sure the script is executable, sudo chmod +x /usr/local/bin/hotplug_monitor.sh
Glad I could help!
Some quick notes:
1. You shouldn’t need to set the hot_plug.service as executable. If you look in /etc/systemd/system/ none of the other services are set as executable (by default)
2. Bash functions work just fine with parentheses (see here – http://tldp.org/LDP/abs/html/functions.html)
I used /tmp/ as an example directory, because I didn’t want to make assumptions about where people want to store their configs. But I added a comment to alert people to that. Personally, I created a new directory at ~/.config/xfce4-panel-switcher/ and I store them there. And you are right that the bash script needs to be executable, I added a comment for that too.
Hey, you were right about not making the service executable. As for the parentheses you seem to be right, but I remember running into an error when simply calling it with bash the_script. I looked up on writing Bash functions here – http://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO-8.html
Then again I also ran into the issue that one of my systems doesn’t detect a change at all when I disconnect the monitor, which must be a driver issue. Forcing a xrandr –query seemed to detect that I had disconnected my monitor. That in turn required me to turn this whole process in more of polling situation for that machine…
For me, python script fails with the following lines:
Traceback (most recent call last):
File “/usr/share/xfpanel-switch/xfpanel-switch/panelconfig.py”, line 155, in
connection = Gio.bus_get_sync(session_bus, cancellable)
GLib.Error: g-io-error-quark: Could not connect: No such file or directory (1)
I can’t seem to find much on it. https://en.wikipedia.org/wiki/GIO_(software)
So I did a google search on the error and this popped up: https://bugzilla.redhat.com/show_bug.cgi?id=1213778
I’m not sure if that’s what you’re experiencing.
I’ve also looked at the documentation for the call Gio.bus_get_sync: https://people.gnome.org/~gcampagna/docs/Gio-2.0/Gio.bus_get_sync.html
The only reason I see that failing if if there’s something quite wrong with your system. In that case the thing that comes to my mind is wrong user. Like running it as root?
But if I run python line manually from terminal – it is executed without problem…
Thank you so much for this. Using your advice, I was able to get my dream setup with manjaro xfce + i3 as a window manager, and get the panels and workspaces displaying on the correct monitors. The only modification I had to make was to use xfce4-panel-profiles instead of xfpanel-switch (the name got updated). But I’m sure you already knew that!
If anyone is reading this and uses the new xfce4-panel-profiles program, all you need to do is, instead of executing the panelconfig.py script with python3, you’ll need to call the binary directly like ‘xfce4-panel-profiles load /path/to/exported_layout.tar.bz2’
Hey, thanks for your article. That was really helpful and I learned a bit about udev and systemd!
However, I also had a little trouble: The udev rule wouldn’t work. Trying to debug with “udevadm test” I got an error like ‘invalid key SUBSYSTEM’. So I removed the ‘SUBSYSTEM==”drm”‘ part, and now it work.