Este es mi escritorio en Gentoo. Le puse 墨絵 sumi-e, que es la pintura japonesa con tinta: tinta sobre papel oscuro, un solo acento índigo para lo que está activo y kanji en los workspaces. Todo está en Sstandby/dotfiles-sumi, y en este post cuento cómo está armado, pieza por pieza.
El escritorio en movimiento
Lo grabé para r/unixporn. Ahí se ve la barra, los paneles abriéndose, el teclado en pantalla, fastfetch y el cambio de wallpaper.
Las piezas
No es un entorno de escritorio, son programas sueltos que se hablan entre ellos:
| Módulo | Qué es |
|---|---|
xmonad | El gestor de ventanas y los atajos |
eww-neon | La barra y todos los paneles |
kitty | La terminal, con el mismo tema |
i3lock | La pantalla de bloqueo, con un fondo que se compone al bloquear |
firewall | Reglas de nftables, todo bloqueado por defecto |
Además de eso, xmonad levanta picom como compositor, dunst para las notificaciones y feh para el wallpaper. El lanzador de aplicaciones es rofi.
El fastfetch lo resume bien: Gentoo con el kernel 6.18.41-gentoo-dist, XMonad sobre X11, kitty 0.47.4, zsh 5.9 y 1722 paquetes instalados con emerge.
La paleta
Son seis colores y casi todo sale de ahí. Así están definidos en el SCSS de eww:
$ink: #0d0d10;
$bone: #e8e5df;
$ash: #9a9aa4;
$faint: #74747e;
$accent: #8b8fc7;
$rule: #22222a;inkes el fondo, casi negro.bonees el texto principal, un blanco cálido como papel.ashyfaintson los grises para lo secundario.accentes el índigo, y es lo único con color: el workspace activo, el borde de la ventana con foco y el cursor.ruleson las líneas que separan los módulos.
Los mismos valores se repiten en xmonad, en kitty, en el tema de Chromium, en el script de bloqueo y en el instalador, para que todo se vea como una sola cosa. Para la terminal hay además 16 colores apagados, que son los que pinta la vaca de bin/gentoo:
color0 #16161c color8 #43434d
color1 #c98a8a color9 #d9a2a2
color2 #9aab8a color10 #b0bf9f
color3 #c9b98a color11 #dccba0
color4 #8b8fc7 color12 #a9adde
color5 #ab8ac9 color13 #c1a2dd
color6 #8ab6c9 color14 #a2cbdd
color7 #d6d3cd color15 #e8e5dfxmonad
El gestor de ventanas es xmonad y la configuración está en Haskell. La tecla principal es Super (mod4Mask), la terminal es kitty y el borde tiene 2 px: gris oscuro en reposo e índigo cuando la ventana tiene el foco.
inactiveColor, activeColor :: String
inactiveColor = "#22222a"
activeColor = "#8b8fc7"Layouts
Uso cuatro layouts que se cambian con Super + Space: Tall, el mismo girado (Mirror tall), pantalla completa y tres columnas con lupa. Todos llevan 10 px de separación entre ventanas y respetan la barra con avoidStruts.
layouts =
avoidStruts
. spacingRaw False (Border 10 10 10 10) True (Border 10 10 10 10) True
$ tall ||| Mirror tall ||| Full ||| threeColumn
where
tall = Tall masters delta ratio
threeColumn = magnifiercz' 1.3 $ ThreeColMid masters delta ratio
masters = 1
ratio = 1 / 2
delta = 5 / 100Al iniciar
Cuando arranca la sesión, xmonad pone el wallpaper que quedó guardado, configura el teclado en español, levanta dunst, el demonio de eww, la barra y picom:
startup :: X ()
startup = do
spawnOnce wallpaper
spawnOnce "setxkbmap es"
spawnOnce "pkill -f 'notification-daemon' && sleep 0.5 && dunst"
spawnOnce ("killall eww; " ++ eww ++ " daemon")
spawnOnce ("sleep 1 && " ++ eww ++ " open neon_bar")
spawnOnce "killall picom; picom &"Atajos
Todo va con Super:
| Atajo | Qué hace |
|---|---|
Enter | Terminal |
c · d · v · f | Chromium · Discord · virt-manager · rofi |
Ctrl + s | Captura de un área |
← → | Mover el foco |
↑ ↓ | Reordenar la pila |
Hay un detalle que me gusta: cuando el teclado en pantalla está abierto, Super + flechas ya no mueve el foco, mueve el teclado. xmonad lo sabe porque eww deja un archivo state/kb_open mientras el teclado está visible:
moveOrElse :: String -> X () -> X ()
moveOrElse direction action = do
isOpen <- liftIO keyboardOpen
if isOpen
then spawn ("bash " ++ ewwScripts ++ "/kbmove.sh " ++ direction)
else actionLa barra y los paneles
La barra y todos los paneles están hechos con eww. De izquierda a derecha la barra tiene el logo de Gentoo, los nueve workspaces, la ventana activa, CPU, RAM, swap, disco, red, volumen, notificaciones y la hora.
Kanji en los workspaces
Los workspaces no son números, son los kanji del uno al nueve (一 二 三 … 九) en IPAMincho. El activo se pinta con el índigo:
(defwidget mod_workspaces []
(box :class "mod workspaces" :orientation "h" :space-evenly false :valign "center"
(for i in '["0","1","2","3","4","5","6","7","8"]'
(eventbox :cursor "pointer"
(button :class {neon_ws == i ? "ws active" : "ws"}
:onclick "xdotool set_desktop ${i}"
(label :class {neon_ws == i ? "ws-glyph active" : "ws-glyph"}
:markup "<span font_family='IPAMincho'>${i == '0' ? '一' : i == '1' ? '二' : i == '2' ? '三' : i == '3' ? '四' : i == '4' ? '五' : i == '5' ? '六' : i == '6' ? '七' : i == '7' ? '八' : '九'}</span>"))))))El workspace actual lo saca un script que escucha la propiedad _NET_CURRENT_DESKTOP de X y avisa cada vez que cambia, así la barra no tiene que estar preguntando:
#!/usr/bin/env bash
xdotool get_desktop 2>/dev/null || echo 0
xprop -root -spy _NET_CURRENT_DESKTOP 2>/dev/null | while read -r _; do
xdotool get_desktop 2>/dev/null || echo 0
donePaneles
Cada panel se abre con Super + Shift y una letra:
| Atajo | Panel |
|---|---|
Space | Lanzador |
m | 音楽 reproductor |
t | 時間 pomodoro, temporizador y cronómetro |
o | 予定 tareas y calendario |
k | 入力 teclado en pantalla |
Todos pasan por el mismo script, toggle.sh: si el panel ya está abierto lo cierra y si no, lo abre. El teclado en pantalla además recuerda dónde lo dejaste, porque su posición se guarda en state/kbpos.
Los paneles de tareas y de aplicaciones necesitan recibir el teclado, así que xmonad los maneja como flotantes. Al resto de ventanas de eww las ignora:
windowRules =
composeAll
[ needsKeyboard --> doFloat
, className =? "Eww" <&&> fmap not needsKeyboard --> doIgnore
, manageDocks
]
where
needsKeyboard = title =? "Eww - neon_todo" <||> title =? "Eww - neon_apps"El panel de perfil tiene una pestaña device desde donde se cambia el idioma de los paneles entre español e inglés. También se puede desde la terminal:
~/.config/eww-neon/scripts/i18n.py toggleWallpapers
Los wallpapers van en ~/.config/eww-neon/wallpapers/ y el panel los lista con su miniatura. Al elegir uno, wallpaper.sh lo pone con feh y guarda la ruta en current_wallpaper, que es el mismo archivo que lee xmonad al iniciar:
set)
img="$2"
[ -f "$img" ] || { echo "no existe: $img" >&2; exit 1; }
feh --bg-fill --no-fehbg "$img" || exit 1
printf '%s\n' "$img" > "$STATE"
;;Kitty y el shell
La terminal es kitty con Cascadia Code a 11 pt, cursor de barra sin parpadeo, sin campana y las pestañas arriba con estilo powerline inclinado. Los atajos de kitty van todos con Alt, para no pisarse con los de xmonad que van con Super:
font_family Cascadia Code
bold_font Cascadia Code Bold
italic_font Cascadia Code Italic
font_size 11.0
cursor_shape beam
cursor_beam_thickness 1.6
cursor_blink_interval 0
tab_bar_style powerline
tab_powerline_style slantedEl shell es zsh, con el prompt de starship y los plugins de autosugerencias y resaltado de sintaxis.
La vaca
bin/gentoo es un script pequeño que imprime una vaca con la versión del kernel y debajo las dos filas de la paleta. Es la que sale en la captura de arriba:
msg=" Gentoo Linux · $(uname -r) "
len=${#msg}
line=$(printf '─%.0s' $(seq 1 $len))
printf "${D} ╭%s╮${R}\n" "$line"
printf "${D} │${B}%s${D}│${R}\n" "$msg"
printf "${D} ╰%s╯${R}\n" "$line"Pantalla de bloqueo
Super + Shift + z bloquea con i3lock, pero la imagen no es fija. Cada vez que bloqueo, build-lock.py toma la foto base, la oscurece mezclándola con el ink, la desenfoca, le pone una viñeta y escribe encima la hora y la fecha en Cascadia Code:
img = Image.open(SRC).convert("RGB").resize((W, H), Image.LANCZOS)
veil = Image.new("RGB", (W, H), INK)
img = Image.blend(img, veil, 0.38)
img = img.filter(ImageFilter.GaussianBlur(radius=2))Si por algo no se puede generar, cae a la imagen plana.
Firewall
El firewall es nftables y la regla de entrada es negar todo por defecto. Solo pasa lo que ya está establecido, el loopback, Tailscale, las máquinas virtuales de virbr0, DHCP, mDNS e ICMP:
chain input {
type filter hook input priority filter; policy drop;
ct state established,related accept
ct state invalid drop
iif "lo" accept
iifname "tailscale0" accept
iifname "virbr0" accept
udp dport 68 accept
udp dport 5353 accept
ip protocol icmp accept
ip6 nexthdr ipv6-icmp accept
}Como equivocarse con un firewall te puede dejar sin red, hay un try.sh que carga las reglas y programa su propio borrado a los 60 segundos. Si algo se rompe, no tienes que hacer nada: las reglas se caen solas. Si todo funciona, matas ese proceso y ya, y luego install.sh las deja fijas en el sistema.
setsid bash -c "sleep $WINDOW; nft delete table inet filter 2>/dev/null" \
</dev/null >/dev/null 2>&1 &
REVERT=$!Instalación
git clone https://github.com/Sstandby/dotfiles-sumi ~/dotfiles
cd ~/dotfiles && ./install.shEl instalador detecta si estás en Gentoo o en Arch, revisa las dependencias y te da el comando exacto para instalar lo que falte (emerge -av o pacman -S --needed). También revisa las fuentes (Cascadia Code, Symbols Nerd Font e IPA para los kanji), enlaza cada módulo en ~/.config guardando un respaldo de lo que había y compila xmonad.
Lo personal no está en el repo: los wallpapers, el avatar y la imagen de bloqueo los pones tú después. Y dos cosas no se activan solas: el tema de Chromium se carga a mano desde chrome://extensions en modo desarrollador, y el firewall se instala con sudo ~/.config/firewall/install.sh.
