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