Multimonitor en BSPWM
=====================
15 de Septiembre, 2020

Cada tanto veo en r/bspwm[1] gente preguntando como puede hacer
para tener soporte para varios monitores usando bspwm, o quejándose
de que se les genero un workspace extraño cuando enchufaron o
desenchufaron un monitor.

Estos eran problemas que yo también tuve en algún momento, pero
hace un tiempo encontré una solución que funciona, y con
requerimientos mínimos.

El problema parece ser una suma de cosas, a saber: gente que no
entiende como funciona bspwm, gente que quiere que funcione IGUAL
que i3, gente que no busca posts parecidos en el subreddit, y un
par mas seguro también.

La solución es primero entender como funciona la creación de
workspaces (esta en la documentación), y entender que hay que
asignarlos a un monitor sí o sí. No hay manera, hasta donde se, de
crearlos on demand pero estoy seguro que se podría crear un script
para tal fin.

La otra parte de la solución es repartir dichos workspaces en los
distintos monitores (físicos, ya que bspwm también hace uso de la
palabra monitor) que tengamos enchufados.

He creado un script, basados en otros scripts que ya existían y
encontré por ahí. Lo detallo a continuación.

```
#!/bin/sh

M=$(bspc query -M --names)
NUM=$(echo "$M" | awk 'END{print NR}')

ettin() {
   sec=$(echo "$M" | awk NR==2)
   xrandr --output LVDS1 --primary --auto --scale 1.0x1.0 --output "$sec" --right-of LVDS1 --auto --scale 1.0x1.0
   bspc monitor LVDS1 -d 1 2 3 4 5
   bspc monitor "$sec" -d 6 7 8 9 10
}

cyclops() {
   xrandr --output LVDS1 --primary --auto --scale 1.0x1.0 "$(echo "$M" | awk '! /LVDS1/ {print "--output", $1, "--off"}' | paste -sd ' ')"
   bspc monitor -d 1 2 3 4 5 6 7 8 9 10
}

if [ "$NUM" = 1 ]; then
   cyclops
elif [ "$NUM" = 2 ]; then
   ettin
fi
```

Las primeas lineas usan bspc para obtener una lista de monitores y
la pasan por awk para darle un orden, luego es cuestión de crear un
par de funciones que, según la cantidad de monitores asignan los
workspaces.

En `ettin` tengo hardcodeado LVDS1 (el monitor de mi laptop) como
pantalla principal y uso lo que sea que este conectado como
secundario, pero para modificarlo solo es cuestión de asignar mas
variables a los diferentes monitores que puedan llegar a existir y
darles workspaces.

En `cyclops` defino mi único monitor como principal mientras que
apago todos los otros generando el resto del comando con la
combinación de awk y paste.


Volver a un solo monitor
------------------------

También metí esta función dentro de su propio script, por si
necesito desconectar mis monitores secundarios y volver a un solo
monitor. Y para hacerla completa, lo puedo disparar con un atajo de
teclado de sxhkd.

Entre la llamada a xrandr y la asignación de workspaces agregue 2
comandos mas de bspc para asegurarme de no quedar con ningún resto
de la configuración previa. Esto se ve de la siguiente manera:

```
#!/bin/sh

M=$(bspc query -M --names)

cyclops() {
   xrandr --output LVDS1 --primary --auto --scale 1.0x1.0 "$(echo "$M" | awk '! /LVDS1/ {print "--output", $1, "--off"}' | paste -sd ' ')"
   bspc config remove_disabled_monitors
   bspc config remove_unplugged_monitors
   bspc monitor -d 1 2 3 4 5 6 7 8 9 10
}

cyclops
```


Complementos
------------

Estas funciones también son un buen lugar para asignar reglas a
programas, por ejemplo si quisiéramos que nuestro navegador
aparezca siempre en el mismo workspace o algo así.
Es un buen lugar para configurar nuestro fondo de escritorio, en
caso de ser una imagen, ya que es muy posible que si tenemos
monitores de distintas resoluciones, la imagen quede convertida en
un mosaico o desfasada de alguna manera.


Uso
---

La mejor manera de usar esto es ponerlo al principio del bspwmrc.
En realidad es la única, porque bspwm requiere la asignación de
workspaces no bien arranca.

Y listo. Eso es todo. No mas quejas, no mas tratar de averiguar que
pasa mirando posts viejos y tratar de hacer historias raras que
funcionan por la mitad.

[1] https://reddit.com/r/bspwm