Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

displaymode

Menú TUI para cambiar el modo de pantalla en Hyprland o niri (duplicado / extendido / solo externa / solo interna), tipo el Win+P de Windows. Pensado para laptop + monitor externo por HDMI/DP.

Tres archivos, lógica separada de interfaz y de compositor:

  • displaymode-hyprland.sh — lógica para Hyprland (config Lua 0.55+), vía hyprctl eval.
  • displaymode-niri.sh — lógica para niri, vía niri msg output.
  • displaymode-tui.sh — interfaz visual (gum). Detecta sola qué compositor corre ($HYPRLAND_INSTANCE_SIGNATURE / $NIRI_SOCKET) y llama al script de lógica correspondiente. No tiene lógica propia.

Cualquiera de los dos scripts de lógica se puede usar solo, sin la TUI, directo desde CLI o un keybind.

El problema que resuelve (Hyprland)

Con el config Lua nuevo de Hyprland (0.55+) — el que usa archivos .lua en vez de hyprland.conf — el comando clásico para cambiar monitores no funciona:

$ hyprctl keyword monitor "HDMI-A-1,preferred,0x0,1"
keyword can't work with non-legacy parsers. Use eval.

Y herramientas como wdisplays o nwg-displays solo prenden/apagan pantallas, no permiten elegir mirror vs extend vs solo-una como en Windows. displaymode-hyprland.sh usa hyprctl eval + la función Lua hl.monitor{} que sí funciona con el config nuevo.

Sobre niri

niri usa su propio IPC (niri msg output <salida> on|off|position|mode|...), sin nada de lo anterior — displaymode-niri.sh es una implementación aparte, no un parche del script de Hyprland.

niri no tiene mirror/duplicado de pantalla a nivel compositor — no existe esa acción en niri msg output --help a la fecha. displaymode-niri.sh lo simula con wl-mirror: lanza una ventana fullscreen sobre la pantalla externa que muestra un screencopy en vivo de la interna. Visualmente es lo mismo que un mirror real, pero es un proceso aparte (no una config de salida) — por eso cualquier otro modo lo mata primero. Necesita wl-mirror instalado; si no está, la TUI esconde esa opción sola.

Requisitos

  • Hyprland (config Lua 0.55+) o niri
  • jq
  • gum (opcional, solo para displaymode-tui.sh — la lógica sola no lo necesita)
  • wl-mirror (opcional, solo para el modo mirror en niri)

Instalación

git clone https://github.com/MxguelS/displaymode.git ~/.local/share/displaymode
ln -s ~/.local/share/displaymode/displaymode-hyprland.sh ~/.local/bin/displaymode-hyprland.sh
ln -s ~/.local/share/displaymode/displaymode-niri.sh ~/.local/bin/displaymode-niri.sh
ln -s ~/.local/share/displaymode/displaymode-tui.sh ~/.local/bin/displaymode-tui.sh

(o copiá la carpeta a donde quieras, no tiene rutas hardcodeadas — displaymode-tui.sh encuentra a los otros dos solo, por estar en el mismo directorio)

Uso

displaymode-hyprland.sh mirror|extend|external|internal   # Hyprland, directo
displaymode-niri.sh mirror|extend|external|internal        # niri, directo (mirror necesita wl-mirror)
displaymode-hyprland.sh --list                              # nombres de pantalla detectados
displaymode-hyprland.sh --help

displaymode-tui.sh                                          # menú interactivo, detecta el compositor solo

Bindear una tecla

Hyprland (config Lua):

hl.bind("SUPER + P", hl.dsp.exec_cmd("kitty --title displaymode -e /ruta/a/displaymode-tui.sh"))

niri (config.kdl):

binds {
    Mod+P { spawn "kitty" "--title" "displaymode" "-e" "/ruta/a/displaymode-tui.sh"; }
}

(cualquier terminal sirve, no tiene que ser kitty)

Cómo detecta las pantallas

Pantalla interna = la primera que matchee eDP-* (estándar en laptops). Pantalla externa = la primera pantalla conectada que no sea la interna. Pensado para el caso típico laptop + 1 monitor externo — con 2+ externos toma el primero que encuentre.

Notas / gotchas encontrados en el camino

Hyprland

  • hyprctl monitors -j (sin all) oculta las pantallas que están en mirror — hay que usar hyprctl monitors all -j para detectarlas bien.
  • En hl.monitor{}, el campo mirror hay que pasarlo explícito como "none" para salir de un mirror previo; si lo omitís, Hyprland no lo limpia solo.
  • Al apagar una pantalla y prender otra muy rápido seguido, el driver puede pisarse asignando CRTCs y dejar ambas en negro por un momento (visto en hardware real, log de aquamarine: drm: eDP-1 is disabled, releasing crtc 95). Por eso el script siempre prende el destino primero y apaga la otra después, nunca al revés — así nunca hay una ventana de tiempo con cero pantallas activas. Si aun así te quedan las pantallas en negro: hyprctl reload desde otra terminal (o TTY, Ctrl+Alt+F2) las recupera.
  • Si usás submaps Lua para binds (hl.define_submap), para salir hay que hacer hl.dsp.submap("reset")"reset" es la palabra especial, no "default" ni cualquier otro nombre. Usar el nombre equivocado deja todos los binds fuera del submap sin responder, sin ningún error visible.

niri

  • Mismo criterio de seguridad que en Hyprland: prender destino antes de apagar la otra, nunca al revés.
  • El "mirror" es wl-mirror corriendo aparte, no una config de compositor — por eso extend/external/internal siempre lo matan primero (pkill -x wl-mirror), para no dejarlo colgado mostrando una pantalla que ya cambió de layout.
  • displaymode-niri.sh external/internal (que apagan una pantalla) no se probaron con hardware real todavía — se armaron contra la sintaxis documentada de niri msg output --help, pero no hubo un segundo monitor conectado a mano para el test en vivo. Si algo sale raro, avisá / abrí un issue.

Licencia

Uso libre, sin garantías — probado en un setup específico (Arch + Hyprland/niri + Caelestia/iNiR), puede necesitar ajustes en otros setups.

About

Cambia entre duplicado/extendido/solo-externa/solo-interna en Hyprland (config Lua 0.55+) — tipo Win+P, con TUI. Arregla el bug de hyprctl keyword monitor roto en el parser nuevo.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages