Multiple monitor setup - bspwm + Polybar
Required packages:
- bspwm
- polybar
- xrandr
- autorandr
Detect connected displays
First of all, we want to check the discriptors of connected displays with this command:
> xrandr --listmonitors
Monitors: 2
0: +*eDP1 1920/280x1080/160+0+0 eDP1
1: +HDMI2 1680/470x1050/300+1920+0 HDMI2
Let’s remember these; I’ll describe my monitors as eDP1 (my laptop’s display) and HDMI2 (external monitor).
Startup script
Next, we’re going to create a script which detects an external monitor when connected, moves bspwm desktops to it and removes those when a monitor is disconnected.
You can store it where you like, just make sure to use the correct path to it.
#! /bin/sh
internal_monitor=eDP1
external_monitor=HDMI2
if [ external_monitor = *connected* ]; then
xrandr --output internal_monitor --primary --mode 1920x1080 --rotate normal --output external_monitor --mode 1680x1050 --rotate normal --right-of internal_monitor
fi
monitor_add() {
desktops=4 # How many desktops to move to the second monitor
for desktop in $(bspc query -D -m $internal_monitor | sed "$desktops"q)
do
bspc desktop $desktop --to-monitor $external_monitor
done
# Remove "Desktop" created by bspwm
bspc desktop Desktop --remove
}
monitor_remove() {
bspc monitor $internal_monitor -a Desktop # Temp desktop because one desktop required per monitor
# Move everything to external monitor to reorder desktops
for desktop in $(bspc query -D -m $internal_monitor)
do
bspc desktop $desktop --to-monitor $external_monitor
done
# Now move everything back to internal monitor
bspc monitor $external_monitor -a Desktop # Temp desktop
for desktop in $(bspc query -D -m $external_monitor)
do
bspc desktop $desktop --to-monitor $internal_monitor
done
bspc desktop Desktop --remove # Remove temp desktops
}
if [ $(xrandr -q | grep "$external_monitor connected") ]; then
monitor_add
else
monitor_remove
fi
Make it executable:
chmod +x $HOME/path/to/script/startup
bspwm
In bspwmrc
add the needed desktop numbers by monitor descriptors like this and add the polybar launch script if you haven’t already:
$HOME/.config/bspwm/bspwmrc
#! /bin/sh
bspc monitor eDP1 -d 1 2 3 4
bspc monitor HDMI2 -d 5 6 7 8
if [ -x $HOME/path/to/polybar/launch.sh ]; then
$HOME/path/to/polybar/launch.sh &
fi
Polybar
Let’s create a separate Polybar instance for the external monitor.
Pay attention to adding pin-workspaces = true
to both main and secondary bars.
$HOME/.config/polybar/config.ini
[bar/main]
width = 100%
height = 30
offset-y = 0
bottom = false
fixed-center = true
monitor = eDP1
pin-workspaces = true
...
[bar/external]
width = 100%
height = 30
offset-y = 0
bottom = false
fixed-center = true
monitor = HDMI2
pin-workspaces = true
...
Launch the secondary (external) Polybar instance conditionally when the external monitor is connected. My launch script looks like this:
$HOME/.config/polybar/launch.sh
#!/usr/bin/env bash
killall polybar
while pgrep -u $UID -x polybar >/dev/null; do sleep 1; done
CONFIG_DIR=$(dirname $0)/themes/$THEME/config.ini
polybar main -c $CONFIG_DIR &
# launch secondary Polybar if an external monitor is connected
if [[ $(xrandr -q | grep 'HDMI2 connected') ]]; then
polybar external -c $CONFIG_DIR &
fi
autorandr
This command will magically make your external monitor work: it sets the resolution and puts it to the right of your primary display.
xrandr --output internal_monitor --primary --mode 1920x1080 --rotate normal --output external_monitor --mode 1680x1050 --rotate normal --right-of internal_monitor
Autorandr automatically selects a display configuration based on connected devices, so you don’t need to use the previous command all the time when connecting a display. Let’s create a separate profile with an external display:
autorandr -s docked
Then, you can disconnect your external display and create a profile just for a primary display (I personally don’t use it):
xrandr --output internal_monitor --primary --mode 1920x1080 --rotate normal
autorandr -s undocked
Finally, create a file called postswitch
in the autorandr
directory. Put our newly made startup in it in order to run it every time you connect an external display:
$HOME/.config/autorandr/postswitch
#! /bin/sh
$HOME/path/to/script/startup
And make it executable:
chmod +x $HOME/.config/autorandr/postswitch
That’s it! Now, you will be able to switch between multiple separate desktops on each display. Everything should work fine after reconnecting an external display - you will still get several new desktops on it.