Hace tiempo que no dedicamos una entrada al principio KISS y a su aplicación al mundo del software. En pocas palabras, software sencillo que hace una cosa y la hace bien. Optimizar recursos. Hacer más con menos. Minimalismo.
La filosofía KISS no implica renunciar, sino optimizar. Significa pensar en qué necesitamos y cómo podemos conseguirlo de la manera más eficiente posible. Un concepto muy extendido cuandose habla de minimalismo en el software es el de bloat o bloatware. El significado de bloated es «hinchado, inflamado» y en este contexto hace referencia a código que añade características o funciones innecesarias que incrementan el uso de recursos. Por supuesto, existe un amplio debate en torno a qué es y que no es bloatware, y se trata de una cuestión fundamentalmente subjetiva. A mi el sentido común me dice que si lo utilizas, no es bloatware. Y por tanto, desde el entorno de escritorio más pesado hasta el gestor de ventanas más minimalista pueden ser considerados bloated, o no. Quizá necesites todas y cada una de las funciones de un gestor de archivos con interfaz GUI o quizá te sirva con ranger. Puede que no necesites que tu gestor de ventanas organice tus ventanas automáticamente. O a lo mejor es algo fundamental para tu flujo de trabajo. Gnome puede ser bloatware, dwm puede ser bloatware.
Disertaciones conceptuales a parte, en esto de programar software sencillo, la gente de suckless hace un trabajo excelente. Entre sus herramientas más famosas se encuentran el gestor de ventanas dwm, la suite suckless-tools (con dmenu y slock a la cabeza), el emulador de terminal st (simple terminal) y el navegador web surf. Hoy vamos a echar un vistazo a dwm y a algunas aplicaciones ligeras que conjugan la mar de bien con un flujo de trabajo minimalista. Casi, casi nos lo podemos tomar como un «aplicaciones ligeras (III)». Hay infinidad de sitios donde podéis encontrar información sobre dwm, así que no me voy a extender demasiado.
Conceptos básicos sobre dwm:
- Es un tiling window manager, organiza ventanas automáticamente según una distribución («layout») predefinida para ocupar el máximo espacio posible en pantalla.
- Es sencillo (menos de 2000 líneas de código) y modular (hay una buena colección de parches que permiten personalizarlo.
- Está escrito en C, y se configura editando un header file (config.h) y recompilando.
- En lugar de escritorios virtuales trabaja con tags: la principal diferencia es que una misma ventana puede estar etiquetada en varios tags.
Compilación e instalación
Descargamos el código fuente de la web de suckless:
wget https://dl.suckless.org/dwm/dwm-6.2.tar.gz
Accedemos al directorio y compilamos:
make clean install
Y listo, en 2-3 segundos tenemos dwm compilado con la configuración por defecto. Para personalizarlo, editamos el fichero config.h y recompilamos. Aunque es bastante intuitivo, siempre es recomendable consultar el manual antes de tocar nada.
Aquí os dejo el mío como ejemplo:
/* See LICENSE file for copyright and license details. */ /* appearance */ static const unsigned int borderpx = 2; / border pixel of windows / static const unsigned int snap = 32; / snap pixel / static const int showbar = 1; / 0 means no bar / static const int topbar = 1; / 0means bottom bar / static const char *fonts[] = { "Cascadia Code:size=11", "Font Awesome:size=11" }; static const char dmenufont[] = "Cascadia Code:size=11"; static const char col_gray1[] = "#2E3440"; static const char col_gray2[] = "#444444"; static const char col_gray3[] = "#bbbbbb"; static const char col_gray4[] = "#F1F1F1"; static const char col_white[] = "#FFFFFF"; static const char col_highlight[] = "#81A1C1"; static const char col_highlight2[] = "#88c0d0"; static const char *colors[][3] = { / fg bg border */ [SchemeNorm] = { col_white, col_gray1, col_gray2 }, [SchemeSel] = { col_gray1, col_highlight, col_highlight }, }; /* Gaps */ static const unsigned int gappx = 8; /* tagging */ static const char *tags[] = { "main", "web", "mail", "docs", "media", "rss", "social", "code", "misc" }; static const Rule rules[] = { /* xprop(1): * WM_CLASS(STRING) = instance, class * WM_NAME(STRING) = title / / class instance title tags mask isfloating monitor */ { "Gimp", NULL, NULL, 0, 0, -1 }, { "Firefox", NULL, NULL, 1 << 1, 0, -1 }, { "Keepassx", "^keepassx$", NULL, 0, 1, -1}, { "Lxrandr", "^lxrandr", NULL, 0, 1, -1}, }; /* layout(s) / static const float mfact = 0.50; / factor of master area size [0.05..0.95] / static const int nmaster = 1; / number of clients in master area / static const int resizehints = 0; / 1 means respect size hints in tiled resizals */ static const Layout layouts[] = { /* symbol arrange function / { "[T]", tile }, / first entry is default / { "[F] ", NULL }, / no layout function means floating behavior */ { "[M]", monocle }, }; /* key definitions */ #define MODKEY Mod1Mask #define TAGKEYS(KEY,TAG) \ { MODKEY, KEY, view, {.ui = 1 << TAG} }, \ { MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \ { MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \ { MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} }, #include <X11/XF86keysym.h> /* commands / static char dmenumon[2] = "0"; / component of dmenucmd, manipulated in spawn() */ static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_highlight, "-sf", col_gray1, NULL }; static const char *termcmd[] = { "st", NULL }; static const char *roficmd[] = { "rofi", "-show", "window", NULL }; static const char *browsercmd[] = { "firefox", NULL }; static const char *officecmd[] = { "libreoffice", NULL }; static const char *editorcmd[] = { "mousepad", NULL }; static const char *filecmd[] = { "pcmanfm","/home/user", NULL }; static const char *configcmd[] = { "st","config", NULL }; static const char *brightdowncmd[] = { "xbacklight","-dec", "5", NULL }; static const char *brightupcmd[] = { "xbacklight","-inc", "5", NULL }; static const char *screencmd[] = { "lxrandr", NULL }; static const char *musiccmd[] = { "spotify", NULL }; static const char *mutecmd[] = { "amixer", "sset", "Master", "toggle", NULL }; static const char *volupcmd[] = { "amixer","sset", "Master", "2%+", NULL }; static const char *voldowncmd[] = { "amixer","sset", "Master", "2%-", NULL }; static const char *lockcmd[] = { "slock", NULL }; static const char *capturecmd[] = { "scrot","-s", NULL }; static Key keys[] = { /* modifier key function argument */ { MODKEY, XK_p, spawn, {.v = dmenucmd } }, { MODKEY, XK_F2, spawn, {.v = dmenucmd } }, { MODKEY, XK_Return, spawn, {.v = termcmd } }, { MODKEY, XK_b, togglebar, {0} }, { MODKEY, XK_Right, focusstack, {.i = +1 } }, { MODKEY, XK_Left, focusstack, {.i = -1 } }, { MODKEY, XK_i, incnmaster, {.i = +1 } }, { MODKEY, XK_d, incnmaster, {.i = -1 } }, { MODKEY, XK_h, setmfact, {.f = -0.05} }, { MODKEY, XK_l, setmfact, {.f = +0.05} }, { MODKEY, XK_space, zoom, {0} }, { MODKEY, XK_Tab, view, {0} }, { MODKEY, XK_q, killclient, {0} }, { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, { MODKEY, XK_f, setlayout, {.v = &layouts[1]} }, { MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, { MODKEY, XK_masculine, spawn, {.v = roficmd } }, { MODKEY|ControlMask, XK_n, spawn, {.v = browsercmd } }, { MODKEY|ControlMask, XK_o, spawn, {.v = officecmd } }, { MODKEY|ControlMask, XK_e, spawn, {.v = editorcmd } }, { MODKEY|ControlMask, XK_h, spawn, {.v = filecmd } }, { 0, XF86XK_MonBrightnessDown, spawn, {.v = brightdowncmd } }, { 0, XF86XK_MonBrightnessUp, spawn, {.v = brightupcmd } }, { 0, XF86XK_AudioMute, spawn, {.v = mutecmd } }, { 0, XF86XK_AudioRaiseVolume, spawn, {.v = volupcmd } }, { 0, XF86XK_AudioLowerVolume, spawn, {.v = voldowncmd } }, { 0, XK_Print, spawn, {.v = capturecmd } }, { MODKEY|ControlMask, XK_l, spawn, {.v = lockcmd } }, { MODKEY|ControlMask, XK_space, setlayout, {0} }, { MODKEY|ShiftMask, XK_space, togglefloating, {0} }, { MODKEY, XK_0, view, {.ui = ~0 } }, { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } }, { MODKEY, XK_comma, focusmon, {.i = -1 } }, { MODKEY, XK_period, focusmon, {.i = +1 } }, { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } }, { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, TAGKEYS( XK_1, 0) TAGKEYS( XK_2, 1) TAGKEYS( XK_3, 2) TAGKEYS( XK_4, 3) TAGKEYS( XK_5, 4) TAGKEYS( XK_6, 5) TAGKEYS( XK_7, 6) TAGKEYS( XK_8, 7) TAGKEYS( XK_9, 8) { MODKEY|ShiftMask, XK_q, quit, {0} }, }; /* button definitions / / click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin / static Button buttons[] = { / click event mask button function argument */ { ClkLtSymbol, 0, Button1, setlayout, {0} }, { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, { ClkWinTitle, 0, Button2, zoom, {0} }, { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, { ClkClientWin, MODKEY, Button1, movemouse, {0} }, { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, { ClkTagBar, 0, Button1, view, {0} }, { ClkTagBar, 0, Button3, toggleview, {0} }, { ClkTagBar, MODKEY, Button1, tag, {0} }, { ClkTagBar, MODKEY, Button3, toggletag, {0} }, };
Parcheando dwm
La idea detrás de dwm es ofrecer un software sencillo, que hace una cosa y la hace bien. Sin embargo, hay un montón de parches que permiten añadir distintas funcionalidades a dwm. El procedimiento es sencillo:
patch -p1 < parche
make clean install
El parámetro -p se refiere al nivel de directorio en el que se encuentra el código a parchear. Por ejemplo, si estamos en el mismo directorio, utilizaremos -p1. Aviso de que parchear el código fuente de dwm puede romper cosas, si pensáis utilizar más de un parche idlos incorporando uno a uno (parchear, compilar, parchear, compilar…).
Iniciando una sesión gráfica sin gestor de inicio de sesión
a. Instalamos xinit.
b. Creamos el archivo .xinitrc en nuestra /home:
#! /bin/bash nitrogen --restore & compton -f -D4 & redshift -l LAT:LONG & dunst & sh /ruta/a/clipmenud & while true; do BAT=`cat /sys/class/power_supply/CMB0/capacity`; BAT_STATUS=`cat /sys/class/power_supply/CMB0/status`; MEM=$(($(grep -m1 'MemAvailable:' /proc/meminfo | awk '{print $2}') / 1024)); DISK=`df -h | grep home | cut -d ' ' -f 10`; IP=`ip a s | grep wlp1s0 | grep inet | cut -d ' ' -f 6`; xsetroot -name " $BAT_STATUS ${BAT}% `date +"%d.%m.%Y"` `date +"%R"` "; sleep 1m; done & exec dwm
Aquí podéis lanzar los programas que necesitéis al inicio. Importante, la última orden debe ser el exec dwm
que lanza el gestor de ventanas.
c. Tecleamos startx
después de loguearnos con nuestro usuario y contraseña.
KISS software
Estas son las aplicaciones ligeras que utilizo normalmente:
1) Gestor de ventanas: dwm
2) Compositor: compton
3) Demonio de notificaciones: dunst
4) Lanzador de aplicaciones: dmenu
5) Capturas de pantalla: scrot
6) Terminal: st
7) Editor de texto: vim / nano
8) Editor de texto GUI: mousepad
9) Gestor de fondos de escritorio: nitrogen
10) Gestor de temas GTK: lxappearance
11) Herramienta de configuración de monitores: lxrandr + xrandr
12) Navegador de archivos: pcmanfm / ranger
13) Lector RSS: newsbeuter (debian stable) / newsboat (debian testing/sid)
14) Cliente IRC: irssi
15) Cliente FTP: ftp/sftp en terminal / filezilla
16) Visor de imágenes: viewnior
17) Visor de PDF: zathura + tabbed / qpdfview (tiene pestañas)
18) Gestor de portapapeles: clipmenu
Lógicamente, esto no es una lista exhaustiva de todo el software que utilizo. Faltan muchos imprescindibles (GIMP, Inkscape, Darktable, LibreOffice, Calibre…) que no son tan ligeros y que seguro que todos conocéis.
Dudas, sugerencias y/o críticas en los comentarios.
Happy desktop hacking!!
[Editado 30/12/2019]
Para que las teclas de brillo funcionen con los comandos incluídos en el config.h con tarjeta gráfica intel:
- Creamos el archivo /usr/share/X11/xorg.conf.d/20-intel.conf como root
- Añadimos:
Section "Device" Identifier "card0" Driver "intel" Option "Backlight" "intel_backlight" BusID "PCI:0:2:0" EndSection
Guardamos ¡y listo!
Entradas anteriores: