commit e845f974ddc6a1a51c903180206f260122bf9272 parent 2546416989a6a34d3a959c867e07c1597891a937 Author: fjbalon <fjbalon@templier.es> Date: Sun, 4 Oct 2026 23:56:39 +0200 Restaurado artículos sobre dwm Diffstat:
30 files changed, 1024 insertions(+), 1 deletion(-)
diff --git a/dirs-to-index.sh b/dirs-to-index.sh @@ -0,0 +1,77 @@ +#!/usr/bin/env bash + +TMP=$(mktemp) + +for file in */index.html; do + [ -f "$file" ] || continue + + dir=$(dirname "$file") + + title=$(grep -oP '(?<=<p class="title">).*?(?=</p>)' "$file" | head -n1) + + date=$(grep -oP '(?<=<p class="date">).*?(?= • )' "$file" | head -n1) + + author=$(grep -oP '(?<= • ).*?(?=</p>)' "$file" | head -n1) + + excerpt=$( + awk ' + /<\/header>/ {inside=1; next} + inside && /<p>/ { + gsub(/<[^>]+>/,"") + print + exit + } + ' "$file" | cut -c1-200 + ) + + order_date=$( + python3 - <<EOF +from datetime import datetime + +months = { + "enero":1, + "febrero":2, + "marzo":3, + "abril":4, + "mayo":5, + "junio":6, + "julio":7, + "agosto":8, + "septiembre":9, + "octubre":10, + "noviembre":11, + "diciembre":12 +} + +s = "$date".lower() + +try: + day, _, month, _, year = s.split() + print(f"{year}{months[month]:02d}{int(day):02d}") +except: + print("00000000") +EOF + ) + + printf "%s\t%s\t%s\t%s\t%s\n" \ + "$order_date" "$dir" "$title" "$date" "$author|$excerpt" \ + >> "$TMP" + +done + +sort -r "$TMP" | while IFS=$'\t' read -r _ dir title date rest +do + author=${rest%%|*} + excerpt=${rest#*|} + + cat <<EOF +<a href="./$dir/" class="article"> + <p class="title">$title</p> + <p class="info">$date · $author</p><p>$excerpt...</p> +</a> + +EOF + +done + +rm "$TMP" +\ No newline at end of file diff --git a/dwm-dmenu/index.html b/dwm-dmenu/index.html @@ -0,0 +1,322 @@ +<!DOCTYPE html> +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<meta name="viewport" content="width=device-width, initial-scale=1" /> +<title>Configuración propia del lanzador de aplicación dmenu</title> +<link rel="icon" type="image/png" href="/favicon.png" /> +<link rel="stylesheet" type="text/css" href="../article.css" /> +</head> +<body> +<header> +<p class="title">Configuración propia del lanzador de aplicación dmenu</p> +<p class="date">25 de junio de 2026 • fjbalon</p> +</header> +<p>dmenu es un lanzador de aplicaciones, extremadamente ligero y rápido para el sistemas de ventanas X, diseñado originalmente para el gestor de ventanas dwm, de suckless. Es una herramienta que, para mí, casa matrimonialmente con dwm; no pudiendo ser verdaderamente usable uno sin el otro. Al menos, dwm no sería tan útil sin él.</p> +<p>Puede encontrar mi propia versión del código en mi servidor de git: <a href="https://templier.es/git/dmenu/">/git/dmenu/</a>.</p> +<p>La versión inicial es muy sencilla, al ser llamado mediante el comando <emb>dmenu</emb>, que por defecto dwm trae con acceso directo mediante teclas (<kbd>Mod1</kbd>+<kbd>p</kbd>, aunque yo personalmente lo he modificado a <kbd>Mod4</kbd>+<kbd>r</kbd>, me gusta más), ejecuta en la barra superior el lanzador, que conforme escribes irá indicando una lista de coincidencias, con una siempre seleccionada.</p> +<p>Pero el código tiene algunas limitaciones para con mi forma de trabajar, por lo que he aplicado algunos cambios para que sea más ameno y útil su uso. Estos son los cambios que he realizado:</p> + +<ol> +<li>Originalmente, como suele ser en el entorno de Linux, es <i>case sensitive</i>. Generalmente lo prefiero así, es más preciso. Sin embargo, siendo que se trata de un lanzador que quiero que sea rápido, o que me ayude a buscar con facilidad; prefiero que sea <i>case insensitive</i>. En suckless hay un parche oficial para ello (<a href="https://tools.suckless.org/dmenu/patches/case-insensitive/">case-insensitive</a>), que he aplicado: +<pre><code class="diff"><span class="info">diff --git a/dmenu.c b/dmenu.c</span> +<span class="hunk">@@ -54,8 +54,9 @@ static Clr *scheme[SchemeLast];</span> + + #include "config.h" + +<span class="del">-static int (*fstrncmp)(const char *, const char *, size_t) = strncmp;</span> +<span class="del">-static char *(*fstrstr)(const char *, const char *) = strstr;</span> +<span class="add">+static char * cistrstr(const char *s, const char *sub);</span> +<span class="add">+static int (*fstrncmp)(const char *, const char *, size_t) = strncasecmp;</span> +<span class="add">+static char *(*fstrstr)(const char *, const char *) = cistrstr;</span> + + static unsigned int + textw_clamp(const char *str, unsigned int n) +<span class="hunk">@@ -733,9 +734,9 @@ main(int argc, char *argv[])</span> + topbar = 0; + else if (!strcmp(argv[i], "-f")) /* grabs keyboard before reading stdin */ + fast = 1; +<span class="del">- else if (!strcmp(argv[i], "-i")) { /* case-insensitive item matching */</span> +<span class="del">- fstrncmp = strncasecmp;</span> +<span class="del">- fstrstr = cistrstr;</span> +<span class="add">+ else if (!strcmp(argv[i], "-s")) { /* case-sensitive item matching */</span> +<span class="add">+ fstrncmp = strncmp;</span> +<span class="add">+ fstrstr = strstr;</span> + } else if (i + 1 == argc) + usage(); + /* these options take one argument */</code></pre> +</li> +<li>Del mismo modo, y con una pretensión de pérdida de cierta precisión con el objetivo de ganar eficiencia y velocidad de lanzamiento, implemento <b>búsqueda difusa</b> mediante la aplicación del parche <a href="https://tools.suckless.org/dmenu/patches/fuzzymatch/">fuzzymatch</a>, que garantiza que el contenido resultado no tiene por qué coincidir matemáticamente con el patrón de búsqueda (por ejemplo, la búsqueda de <emb>rvt</emb> podrá dar como resultado <emb>urxvt</emb>), en combinación con el parche <a href="https://tools.suckless.org/dmenu/patches/fuzzyhighlight/">fuzzyhighlight</a>, que resalta las coincidencias en la búsqueda. +<pre><code class="diff"><span class="info">diff --git a/config.h b/config.h</span> +<span class="info">index 1edb647..64eab2a 100644</span> +<span class="info">--- a/config.h</span> +<span class="info">+++ b/config.h</span> +<span class="hunk">@@ -11,6 +11,8 @@ static const char *colors[SchemeLast][2] = {</span> + /* fg bg */ + [SchemeNorm] = { "#bbbbbb", "#222222" }, + [SchemeSel] = { "#eeeeee", "#005577" }, +<span class="add">+ [SchemeSelHighlight] = { "#ffc978", "#005577" },</span> +<span class="add">+ [SchemeNormHighlight] = { "#ffc978", "#222222" },</span> + [SchemeOut] = { "#000000", "#00ffff" }, + }; + /* -l option; if nonzero, dmenu uses vertical list with given number of lines */ +<span class="info">diff --git a/dmenu.c b/dmenu.c</span> +<span class="info">index 40f93e0..662131a 100644</span> +<span class="info">--- a/dmenu.c</span> +<span class="info">+++ b/dmenu.c</span> +<span class="hunk">@@ -25,7 +25,9 @@</span> + #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) + + /* enums */ +<span class="del">-enum { SchemeNorm, SchemeSel, SchemeOut, SchemeLast }; /* color schemes */</span> +<span class="add">+enum { SchemeNorm, SchemeSel, SchemeNormHighlight, SchemeSelHighlight,</span> +<span class="add">+ SchemeOut, SchemeLast }; /* color schemes */</span> +<span class="add">+</span> + + struct item { + char *text; +<span class="hunk">@@ -129,9 +131,47 @@ cistrstr(const char *h, const char *n)</span> + return NULL; + } + +<span class="add">+static void</span> +<span class="add">+drawhighlights(struct item *item, int x, int y, int maxw)</span> +<span class="add">+{</span> +<span class="add">+ int i, indent;</span> +<span class="add">+ char c, *highlight;</span> +<span class="add">+</span> +<span class="add">+ if (!(strlen(item->text) && strlen(text)))</span> +<span class="add">+ return;</span> +<span class="add">+</span> +<span class="add">+ drw_setscheme(drw, scheme[item == sel</span> +<span class="add">+ ? SchemeSelHighlight</span> +<span class="add">+ : SchemeNormHighlight]);</span> +<span class="add">+ for (i = 0, highlight = item->text; *highlight && text[i];) {</span> +<span class="add">+ if (!fstrncmp(highlight, &text[i], 1)) {</span> +<span class="add">+ /* get indentation */</span> +<span class="add">+ c = *highlight;</span> +<span class="add">+ *highlight = '\0';</span> +<span class="add">+ indent = TEXTW(item->text);</span> +<span class="add">+ *highlight = c;</span> +<span class="add">+</span> +<span class="add">+ /* highlight character */</span> +<span class="add">+ c = highlight[1];</span> +<span class="add">+ highlight[1] = '\0';</span> +<span class="add">+ drw_text(</span> +<span class="add">+ drw,</span> +<span class="add">+ x + indent - (lrpad / 2.),</span> +<span class="add">+ y,</span> +<span class="add">+ MIN(maxw - indent, TEXTW(highlight) - lrpad),</span> +<span class="add">+ bh, 0, highlight, 0</span> +<span class="add">+ );</span> +<span class="add">+ highlight[1] = c;</span> +<span class="add">+ ++i;</span> +<span class="add">+ }</span> +<span class="add">+ ++highlight;</span> +<span class="add">+ }</span> +<span class="add">+}</span> +<span class="add">+</span> + static int + drawitem(struct item *item, int x, int y, int w) + { +<span class="add">+ int r;</span> + if (item == sel) + drw_setscheme(drw, scheme[SchemeSel]); + else if (item->out) +<span class="hunk">@@ -139,7 +179,9 @@ drawitem(struct item *item, int x, int y, int w)</span> + else + drw_setscheme(drw, scheme[SchemeNorm]); + +<span class="del">- return drw_text(drw, x, y, w, bh, lrpad / 2, item->text, 0);</span> +<span class="add">+ r = drw_text(drw, x, y, w, bh, lrpad / 2, item->text, 0);</span> +<span class="add">+ drawhighlights(item, x, y, w);</span> +<span class="add">+ return r;</span> + } + + static void +<span class="hunk">@@ -716,7 +758,8 @@ static void</span> + usage(void) + { + die("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" +<span class="del">- " [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]");</span> +<span class="add">+ " [-nb color] [-nf color] [-sb color] [-sf color]\n"</span> +<span class="add">+ " [-nhb color] [-nhf color] [-shb color] [-shf color] [-w windowid]");</span> + } + + int +<span class="hunk">@@ -756,6 +799,14 @@ main(int argc, char *argv[])</span> + colors[SchemeSel][ColBg] = argv[++i]; + else if (!strcmp(argv[i], "-sf")) /* selected foreground color */ + colors[SchemeSel][ColFg] = argv[++i]; +<span class="add">+ else if (!strcmp(argv[i], "-nhb")) /* normal hi background color */</span> +<span class="add">+ colors[SchemeNormHighlight][ColBg] = argv[++i];</span> +<span class="add">+ else if (!strcmp(argv[i], "-nhf")) /* normal hi foreground color */</span> +<span class="add">+ colors[SchemeNormHighlight][ColFg] = argv[++i];</span> +<span class="add">+ else if (!strcmp(argv[i], "-shb")) /* selected hi background color */</span> +<span class="add">+ colors[SchemeSelHighlight][ColBg] = argv[++i];</span> +<span class="add">+ else if (!strcmp(argv[i], "-shf")) /* selected hi foreground color */</span> +<span class="add">+ colors[SchemeSelHighlight][ColFg] = argv[++i];</span> + else if (!strcmp(argv[i], "-w")) /* embedding window id */ + embed = argv[++i]; + else</code></pre> +<pre><code class="diff"><span class="info">diff --git a/config.h b/config.h</span> +<span class="info">index 1edb647..a4e6174 100644</span> +<span class="info">--- a/config.h</span> +<span class="info">+++ b/config.h</span> +<span class="hunk">@@ -2,6 +2,7 @@</span> + /* Default settings; can be overriden by command line. */ + + static int topbar = 1; /* -b option; if 0, dmenu appears at bottom */ +<span class="add">+static int fuzzy = 1; /* -F option; if 0, dmenu doesn't use fuzzy matching */</span> + /* -fn option overrides fonts[0]; default X11 font or font set */ + static const char *fonts[] = { + "monospace:size=10" +<span class="info">diff --git a/config.mk b/config.mk</span> +<span class="info">index 137f7c8..6a19175 100644</span> +<span class="info">--- a/config.mk</span> +<span class="info">+++ b/config.mk</span> +<span class="hunk">@@ -21,7 +21,7 @@ FREETYPEINC = /usr/include/freetype2</span> + + # includes and libs + INCS = -I$(X11INC) -I$(FREETYPEINC) +<span class="del">-LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS)</span> +<span class="add">+LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS) -lm</span> + + # flags + CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" $(XINERAMAFLAGS) +<span class="info">diff --git a/dmenu.c b/dmenu.c</span> +<span class="info">index 40f93e0..03e1f45 100644</span> +<span class="info">--- a/dmenu.c</span> +<span class="info">+++ b/dmenu.c</span> +<span class="hunk">@@ -1,6 +1,7 @@</span> + /* See LICENSE file for copyright and license details. */ + #include <ctype.h> + #include <locale.h> +<span class="add">+#include <math.h></span> + #include <stdio.h> + #include <stdlib.h> + #include <string.h> +<span class="hunk">@@ -31,6 +32,7 @@ struct item {</span> + char *text; + struct item *left, *right; + int out; +<span class="add">+ double distance;</span> + }; + + static char text[BUFSIZ] = ""; +<span class="hunk">@@ -226,9 +228,93 @@ grabkeyboard(void)</span> + die("cannot grab keyboard"); + } + +<span class="add">+int</span> +<span class="add">+compare_distance(const void *a, const void *b)</span> +<span class="add">+{</span> +<span class="add">+ struct item *da = *(struct item **) a;</span> +<span class="add">+ struct item *db = *(struct item **) b;</span> +<span class="add">+</span> +<span class="add">+ if (!db)</span> +<span class="add">+ return 1;</span> +<span class="add">+ if (!da)</span> +<span class="add">+ return -1;</span> +<span class="add">+</span> +<span class="add">+ return da->distance == db->distance ? 0 : da->distance < db->distance ? -1 : 1;</span> +<span class="add">+}</span> +<span class="add">+</span> +<span class="add">+void</span> +<span class="add">+fuzzymatch(void)</span> +<span class="add">+{</span> +<span class="add">+ /* bang - we have so much memory */</span> +<span class="add">+ struct item *it;</span> +<span class="add">+ struct item **fuzzymatches = NULL;</span> +<span class="add">+ char c;</span> +<span class="add">+ int number_of_matches = 0, i, pidx, sidx, eidx;</span> +<span class="add">+ int text_len = strlen(text), itext_len;</span> +<span class="add">+</span> +<span class="add">+ matches = matchend = NULL;</span> +<span class="add">+</span> +<span class="add">+ /* walk through all items */</span> +<span class="add">+ for (it = items; it && it->text; ++it) {</span> +<span class="add">+ if (text_len) {</span> +<span class="add">+ itext_len = strlen(it->text);</span> +<span class="add">+ pidx = 0; /* pointer */</span> +<span class="add">+ sidx = eidx = -1; /* start of match, end of match */</span> +<span class="add">+ /* walk through item text */</span> +<span class="add">+ for (i = 0; i < itext_len && (c = it->text[i]); ++i) {</span> +<span class="add">+ /* fuzzy match pattern */</span> +<span class="add">+ if (!fstrncmp(&text[pidx], &c, 1)) {</span> +<span class="add">+ if(sidx == -1)</span> +<span class="add">+ sidx = i;</span> +<span class="add">+ ++pidx;</span> +<span class="add">+ if (pidx == text_len) {</span> +<span class="add">+ eidx = i;</span> +<span class="add">+ break;</span> +<span class="add">+ }</span> +<span class="add">+ }</span> +<span class="add">+ }</span> +<span class="add">+ /* build list of matches */</span> +<span class="add">+ if (eidx != -1) {</span> +<span class="add">+ /* compute distance */</span> +<span class="add">+ /* add penalty if match starts late (log(sidx+2))</span> +<span class="add">+ * add penalty for long a match without many matching characters */</span> +<span class="add">+ it->distance = log(sidx + 2) + (double)(eidx - sidx - text_len);</span> +<span class="add">+ /* fprintf(stderr, "distance %s %f\n", it->text, it->distance); */</span> +<span class="add">+ appenditem(it, &matches, &matchend);</span> +<span class="add">+ ++number_of_matches;</span> +<span class="add">+ }</span> +<span class="add">+ } else {</span> +<span class="add">+ appenditem(it, &matches, &matchend);</span> +<span class="add">+ }</span> +<span class="add">+ }</span> +<span class="add">+</span> +<span class="add">+ if (number_of_matches) {</span> +<span class="add">+ /* initialize array with matches */</span> +<span class="add">+ if (!(fuzzymatches = realloc(fuzzymatches,</span> +<span class="add">+ number_of_matches * sizeof(struct item *))))</span> +<span class="add">+ die("cannot realloc %u bytes:", number_of_matches * sizeof(struct item *));</span> +<span class="add">+ for (i = 0, it = matches; it && i < number_of_matches; ++i, it = it->right)</span> +<span class="add">+ fuzzymatches[i] = it;</span> +<span class="add">+ /* sort matches according to distance */</span> +<span class="add">+ qsort(fuzzymatches, number_of_matches, sizeof(struct item*), compare_distance);</span> +<span class="add">+ /* rebuild list of matches */</span> +<span class="add">+ matches = matchend = NULL;</span> +<span class="add">+ for (i = 0, it = fuzzymatches[i]; i < number_of_matches && it &&</span> +<span class="add">+ it->text; ++i, it = fuzzymatches[i])</span> +<span class="add">+ appenditem(it, &matches, &matchend);</span> +<span class="add">+ free(fuzzymatches);</span> +<span class="add">+ }</span> +<span class="add">+ curr = sel = matches;</span> +<span class="add">+ calcoffsets();</span> +<span class="add">+}</span> +<span class="add">+</span> + static void + match(void) + { +<span class="add">+ if (fuzzy) {</span> +<span class="add">+ fuzzymatch();</span> +<span class="add">+ return;</span> +<span class="add">+ }</span> + static char **tokv = NULL; + static int tokn = 0; + +<span class="hunk">@@ -715,7 +801,7 @@ setup(void)</span> + static void + usage(void) + { +<span class="del">- die("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n"</span> +<span class="add">+ die("usage: dmenu [-bFfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n"</span> + " [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]"); + } + +<span class="hunk">@@ -732,6 +818,8 @@ main(int argc, char *argv[])</span> + exit(0); + } else if (!strcmp(argv[i], "-b")) /* appears at the bottom of the screen */ + topbar = 0; +<span class="add">+ else if (!strcmp(argv[i], "-F")) /* disables fuzzy matching */</span> +<span class="add">+ fuzzy = 0;</span> + else if (!strcmp(argv[i], "-f")) /* grabs keyboard before reading stdin */ + fast = 1; + else if (!strcmp(argv[i], "-i")) { /* case-insensitive item matching */</code></pre> +</li> +</ol> +</body> +</html> diff --git a/dwm-howto/index.html b/dwm-howto/index.html @@ -0,0 +1,100 @@ +<!DOCTYPE html> +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<meta name="viewport" content="width=device-width, initial-scale=1" /> +<title>Configuración y uso personal de dwm</title> +<link rel="icon" type="image/png" href="/favicon.png" /> +<link rel="stylesheet" type="text/css" href="../article.css" /> +</head> +<body> +<header> +<p class="title">Configuración y uso personal de dwm</p> +<p class="date">9 de octubre de 2021 • fjbalon</p> +</header> +<p>En orden a construir <emb>dwm</emb> necesita los archivos de cabecera de Xlib. Edite config.mk para localizar tu configuración local (<emb>dwm</emb> es instalado en usr/local por defecto). La instalación se realiza directamente compilando el código, para ello dispone de un archivo <emb>makefile</emb>. Para limpieza de archivos compilados y temporales en directorio de trabajo, dispone de la orden <emb>clean</p>emb>.</p> +<p><emb>dwm</emb> se configura mediante el archivo <emb>config.h</emb> y (re)compilando.</p> +<p>Existen parches ya programados y publicados por la comunidad de suckless que permiten extender fácilmente el windows manager según los parámetros requeridos por el usuario. En mi caso, utilizo éstos de base:</p> +<ul> +<li>Parches estéticos</li> +<ul> +<li><a href="https://dwm.suckless.org/patches/actualfullscreen">actualfullscreen</a>: Alterna la pantalla completa para una ventana, en lugar de alternar la barra de estado y el diseño monocle2.</li> +<li><a href="https://dwm.suckless.org/patches/titlecolor">titlecolor</a>: Añade un nuevo esquema de color utilizado por el título de la ventana en la barra, de modo que sus colores (primer plano y fondo) se pueden cambiar de forma independiente.</li> +<li><a href="https://dwm.suckless.org/patches/noborder">noborderfloating</a>: Elimina el borde cuando sólo haya una ventana visible.</li> +</ul> +<li>Parches funcionales</li> +<ul> +<li><a href="https://dwm.suckless.org/patches/movestack">movestack</a>: Permite mover clientes en la pila e intercambiarlos con el maestro.</li> +<li><a href="https://dwm.suckless.org/patches/pertag">pertag</a>: Mantiene layout, mwfact, barpos y nmaster por etiqueta (tag).</li> +</ul> +</ul> +<p>Basado en el artículo <a href="https://ratfactor.com/dwm">Dave's Visual Guide to dwm</a> y usando, con su permiso, algunas imágenes de su autoría; voy a exponer cómo uso, o conduzco, <emb>dwm</emb> obteniendo toda su potencia gráfica. A priori, puede parecer un uso complejo y complicado, y de hecho así lo es en un inicio. Sin embargo, como aquel que controla maquinaria pesada o programas complejos, con el uso rutinario que se convierte en hábito, se convierte en un poderoso arma de productividad y enfoque táctico.</p> +<p>Lo primero que hay que definir es la tecla principal, que en mi caso es <kbd>Mod4</kbd>. Cabe destacar que por defecto es <kbd>Alt</kbd>.</p> +<h2>Layouts</h2> +<p>Un layout, en el contexto de diseño gráfico y de interfaces de usuario, es la disposición visual y organizativa de los elementos en una pantalla. <emb>dwm</emb> cuenta con 3 layouts:</p> +<ol start="0"> +<li> +<p><kbd>Mod4</kbd>+<kbd>t</kbd> Tiled (mosaico): reorganiza las ventanas en la configuración maestra/pila de mosaicos dinámicos.</p> +<img style="width: 45%;" src="resources/tiled_layout.png"/> +<p>Es el layout por defecto al abrir una tag. La ventana creada comienza a pantalla completa. A medida que se agregan ventanas, se abren en el área master (zona izquierda); mientras que las más antiguas se empujan al área stack(zona derecha, apiladas).</p> +<img style="width: 60%;" src="resources/dwm_master_stack_layout.png"/> +</li> +<li> +<p><kbd>Mod4</kbd>+<kbd>f</kbd> Floating (flotante): las ventanas pueden superponerse, moverse y dimensionarse manualmente.</p> +<img style="width: 20%;" src="resources/floating_layout.png"/> +</li> +<li> +<p><kbd>Mod4</kbd>+<kbd>m</kbd> Monocle (monóculo): una sóla ventana completa enfocada se empuja hacia el frente, el resto, esperan detrás a ser enfocadas.</p> +<img style="width: 45%;" src="resources/monocle_layout.png"/> +</li> +</ol> +<p>Además, alterna entre los dos layouts más actuales con <kbd>Mod4</kbd>+<kbd>Space</kbd>. Para cambiar entre los estados de mosaico y flotante en la ventana enfocada <kbd>Mod4</kbd>+<kbd>Shift</kbd>+<kbd>Space</kbd>.</p> +<img style="width: 45%;" src="resources/toggle_window_floating.png"/> +<h2>Administración de ventanas</h2> +<p>De forma predeterminada, hay dos formas de abrir una nueva ventana: abrir una shell (por defecto <emb>st</emb>) o ejecutar <emb>dmenu</emb>. Ambas son aplicaciones separadas que se construyeron específicamente y modularmente para trabajar con <emb>dwm</emb> (aunque pueden usarse fuera de éste sin problemas). En mi caso uso ambas, cuyas combinaciones de teclas predeterminadas para cada una son:</p> +<p><kbd>Mod4</kbd>+<kbd>Return</kbd> abre específicamente <emb>st</emb>, si desea que abra otra terminal, como <emb>xterm</emb> o <emb>urxvt</emb>, deberá configurar <emb>config.h</emb>.</p> +<img style="width: 45%;" src="resources/new_term.png"/> +<p><kbd>Mod4</kbd>+<kbd>r</kbd> ejecuta el pequeño menú dinámico llamado dmenu en la barra superior de <emb>dwm</emb>.</p> +<p>Para cerrar una ventana, puede cerrarla desde la aplicación o indicar que cierre la ventana con <kbd>Mod4</kbd>+<kbd>Shift</kbd>+<kbd>c</kbd> sobre la ventana enfocada. No podemos empezar a usar un programa si no sabemos terminarlo o salir de él. En el caso de <emb>dwm</emb>, saldremos de él mediante <kbd>Mod4</kbd>+<kbd>Shift</kbd>+<kbd>q</kbd>.</p> +<img style="width: 45%;" src="resources/close_window.png"/> +<h2>Administración del foco</h2> +<p>Para mover el foco entre ventanas, utilizo <kbd>Mod4</kbd>+<kbd>j</kbd> para moverlo hacia la siguiente. Esto sirve para todos los layouts. En modo mosaico, vamos en dirección de la agujas del reloj.</p> +<img style="width: 45%;" src="resources/focus_next_tiled.png"/><img style="width: 45%;" src="resources/focus_next_floating.png"/> +<p>Para mover el foco a la ventana anterior utilizo <kbd>Mod4</kbd>+<kbd>k</kbd>.</p> +<img style="width: 45%;" src="resources/focus_prev_tiled.png"/><img style="width: 45%;" src="resources/focus_prev_floating.png"/> +<h2>Administración de mosaico (tiled layout)</h2> +<p>Para aumentar el número de ventanas divididas en el área master (lo que moverá las ventanas en caso de haberlas fuera del área de pila según sea necesario) utilizo <kbd>Mod4</kbd>+<kbd>i</kbd> (increment master).</p> +<img style="width: 70%;" src="resources/master_increase.png"/> +<p>Del mismo modo a la inversa, para reducir el número de ventanas divididas utilizo <kbd>Mod4</kbd>+<kbd>d</kbd> (decrement master).</p> +<img style="width: 70%;" src="resources/master_decrease.png"/> +<p>Para incrementar el área física que ocupa master utilizo <kbd>Mod4</kbd>+<kbd>l</kbd>.</p> +<img style="width: 45%;" src="resources/master_bigger.png"/> +<p>Para reducir el área física que ocupa master utilizo <kbd>Mod4</kbd>+<kbd>h</kbd>.</p> +<img style="width: 45%;" src="resources/master_smaller.png"/> +<p>Para aplicar zoom, o en palabras más técnicas, alternar la ventana entre las áreas master y stack, utilizo <kbd>Mod4</kbd>+<kbd>Shift</kbd>+<kbd>Return</kbd>. Si la ventana enfocada está en stack se moverá a master y viceversa.</p> +<img style="width: 45%;" src="resources/zoom.png"/> +<h2>Administración de etiquetas (tags)</h2> +<p>Si esta familiarizado con el concepto de escritorios múltiples o escritorios virtuales lo entenderá rápidamente. Las etiquetas o tags brindan la misma funcionalidad, pero con más flexibilidad y velocidad. Cada etiqueta es un escritorio, que administra un conjunto específico de ventanas que tiene abiertas.</p> +<p>Si hay alguna diferencia con los escritorios virtuales clásicos, es que una ventana puede pertenecer a más de una tag, e incluso puede ver todas las etiquetas a la vez, combinarlas, etc.</p> +<p>Para movernos entre tags, basta con <kbd>Mod4</kbd>+<kbd>1...n</kbd>, donde <emb>n</emb> es el número de tag que queremos visualizar. <kbd>Mod4</kbd>+<kbd>Tab</kbd> conmuta entre las 2 tags más recientes.</p> +<img style="width: 45%;" src="resources/view_tagged_windows.png"/> +<p>Para asignar un nuevo tag a una ventana, en otras palabras, mover una ventana entre tags, uso <kbd>Mod4</kbd>+<kbd>Shift</kbd>+<kbd>1...n</kbd>, que moverá la ventana enfocada al tag <emb>n</emb>.</p> +<img style="width: 45%;" src="resources/assign_window_tag.png"/> +<p>Para universalizar la ventana enfocada, uso <kbd>Mod4</kbd>+<kbd>Shift</kbd>+<kbd>0</kbd>; de tal forma que la ventana se mostrará en todos los escritorios. Para agregar o eliminar la visualización del foco en una tag <emb>n</emb> concreta, en lugar de en todas, uso <kbd>Mod4</kbd>+<kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>1...n</kbd>.</p> +<img style="width: 45%;" src="resources/assign_all_window_tags.png"/> +<p>Para visualizar todas las ventanas de todas las tags uso <kbd>Mod4</kbd>+<kbd>0</kbd>. Si lo que queremos es combinar x tags concretas en lugar de todas, podemos conmutarlas con <kbd>Mod4</kbd>+<kbd>Ctrl</kbd>+<kbd>1...n</kbd>.</p> +<img style="width: 45%;" src="resources/view_all_windows.png"/> +<h2>Administración de barra (bar)</h2> +<p>La barra o bar puede ocultarse o mostrarse simplemente usando <kbd>Mod4</kbd>+<kbd>b</kbd>. Es muy útil a veces.</p> +<img style="width: 45%;" src="resources/toggle_bar.png"/> +<h2>Administración del ratón (mousing)</h2> +<p>Aunque como sabemos, <emb>dwm</emb> está diseñado para que no se requiera el ratón. A veces puede ser un añadido muy útil, en especial cuando ya estamos usándolo en programas que por diseño lo requieren, como el navegador, programas gráficos o algún juego.</p> +<p>Si queremos activar la administración del ratón, sólo tenemos que mantener pulsado <kbd>Mod4</kbd> durante su uso.</p> +<p><kbd>Mod4</kbd>+<kbd>Button1</kbd> mueve la ventana en modo flotante. Si la ventana se encontraba incrustada en el mosaico, cambiará su modo a flotante.</p> +<img style="width: 20%;" src="resources/mouse_controls.png"/> +<p><kbd>Mod4</kbd>+<kbd>Button2</kbd> alterna la ventana entre el estado flotante y mosaico. <kbd>Mod4</kbd>+<kbd>Button3</kbd> redimensiona la ventana. Al igual que con el movimiento, si la ventana estaba embaldosada, se flotará. Otro uso del ratón a tener en cuenta es como enfocador. Si el ratón se superpone sobre una ventana esta adquirirá automáticamente el foco. Igual en varios monitores.</p> +<h2>Administración de monitores</h2> +<p>En ocasiones, trabajamos con más de un monitor. En ese caso, cada monitor extenderá el escritorio de <emb>dwm</emb>, manteniendo 9 tags independientes -por defecto- en cada escritorio.</p> +<p>Cada escritorio puede ser comportado como una tag superior, moviendo el foco de escritorio con <kbd>Mod4</kbd>+<kbd>,</kbd> y <kbd>Mod4</kbd>+<kbd>.</kbd>. Para enviar una ventana a la tag enfocada del siguiente escritorio uso <kbd>Mod4</kbd>+<kbd>Shift</kbd>+<kbd>,</kbd>, <kbd>Mod4</kbd>+<kbd>Shift</kbd>+<kbd>.</kbd> para enviarla al escritorio anterior.</p> +</body> +</html> +\ No newline at end of file diff --git a/dwm-howto/resources/assign_all_window_tags.png b/dwm-howto/resources/assign_all_window_tags.png Binary files differ. diff --git a/dwm-howto/resources/assign_window_tag.png b/dwm-howto/resources/assign_window_tag.png Binary files differ. diff --git a/dwm-howto/resources/close_window.png b/dwm-howto/resources/close_window.png Binary files differ. diff --git a/dwm-howto/resources/dwm_master_stack_layout.png b/dwm-howto/resources/dwm_master_stack_layout.png Binary files differ. diff --git a/dwm-howto/resources/floating_layout.png b/dwm-howto/resources/floating_layout.png Binary files differ. diff --git a/dwm-howto/resources/focus_next_floating.png b/dwm-howto/resources/focus_next_floating.png Binary files differ. diff --git a/dwm-howto/resources/focus_next_tiled.png b/dwm-howto/resources/focus_next_tiled.png Binary files differ. diff --git a/dwm-howto/resources/focus_prev_floating.png b/dwm-howto/resources/focus_prev_floating.png Binary files differ. diff --git a/dwm-howto/resources/focus_prev_tiled.png b/dwm-howto/resources/focus_prev_tiled.png Binary files differ. diff --git a/dwm-howto/resources/master_bigger.png b/dwm-howto/resources/master_bigger.png Binary files differ. diff --git a/dwm-howto/resources/master_decrease.png b/dwm-howto/resources/master_decrease.png Binary files differ. diff --git a/dwm-howto/resources/master_increase.png b/dwm-howto/resources/master_increase.png Binary files differ. diff --git a/dwm-howto/resources/master_smaller.png b/dwm-howto/resources/master_smaller.png Binary files differ. diff --git a/dwm-howto/resources/monocle_layout.png b/dwm-howto/resources/monocle_layout.png Binary files differ. diff --git a/dwm-howto/resources/mouse_controls.png b/dwm-howto/resources/mouse_controls.png Binary files differ. diff --git a/dwm-howto/resources/new_term.png b/dwm-howto/resources/new_term.png Binary files differ. diff --git a/dwm-howto/resources/tiled_layout.png b/dwm-howto/resources/tiled_layout.png Binary files differ. diff --git a/dwm-howto/resources/toggle_bar.png b/dwm-howto/resources/toggle_bar.png Binary files differ. diff --git a/dwm-howto/resources/toggle_window_floating.png b/dwm-howto/resources/toggle_window_floating.png Binary files differ. diff --git a/dwm-howto/resources/view_all_windows.png b/dwm-howto/resources/view_all_windows.png Binary files differ. diff --git a/dwm-howto/resources/view_tagged_windows.png b/dwm-howto/resources/view_tagged_windows.png Binary files differ. diff --git a/dwm-howto/resources/zoom.png b/dwm-howto/resources/zoom.png Binary files differ. diff --git a/dwm-slock/index.html b/dwm-slock/index.html @@ -0,0 +1,345 @@ +<!DOCTYPE html> +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<meta name="viewport" content="width=device-width, initial-scale=1" /> +<title>Configuración propia del bloqueador de pantalla slock</title> +<link rel="icon" type="image/png" href="/favicon.png" /> +<link rel="stylesheet" type="text/css" href="../article.css" /> +</head> +<body> +<header> +<p class="title">Configuración propia del bloqueador de pantalla slock</p> +<p class="date">22 de junio de 2026 • fjbalon</p> +</header> +<p>Un software que me gusta bastante de la caja de herramientas de suckless es slock, un bloqueador de pantalla minimalista; tan minimalista que yo creo que es el bloqueador de pantalla x más sencillo que existe. Una vez ejecutado, bloquea la sesión y solo se desbloquea al introducir la contraseña del usuario. No es un programa innovador ni de nicho: el concepto de bloqueador de pantalla existe prácticamente desde los inicios de X11.</p> +<p>Puede encontrar mi propia versión del código en mi servidor de git: <a href="https://templier.es/git/slock/">/git/slock/</a>.</p> +<p>En términos generales, slock crea una ventana fullscreen que cubre todos los monitores, toma el teclado y el ratón (<emb>XGrabKeyboard</emb> + <emb>XGrabPointer</emb>) y entra en bucle donde lee la entrada del teclado. Compara la contraseña introducida (usando <emb>crypt()</emb> o <emb>PAM/shadow</emb>) contra la del usuario. Si coincide, suelta el grab y cierra la ventana.</p> +<p>Por su funcionamiento, radicalmente mínimo y unido al sistema operativo, podemos verlo como un sistema muy seguro. Eso sí, cuenta con las limitaciones propias de todos los bloqueadores de pantalla de X11, como que el usuario puede cambiar a otra tty, otro usuario o sesión podría matar X y cosas así. No son errores, ni si quiera problemas de seguridad, pues la sesión se mantendría protegida aun matándola o cambiando de tty; pero son limitaciones que el usuario debe conocer, desde luego.</p> +<p>La estética inicial es tan sobria como un par de colores que indican si el usuario ha empezado a escribir la contraseña (azul), si ha fallado al introducirla (rojo) o si ha accedido (no hay color, entra en la sesión con normalidad). Si bien esta forma visual es extremadamente vaga, para mi gusto.</p> +<p>Por lo tanto, lo que más estético me ha parecido es aplicar el llamado parche <i>Blured or pixelated screenshot</i>:</p> + +<pre><code class="diff"><span class="info">diff --git a/config.mk b/config.mk</span> +<span class="info">index 74429ae..987819e 100644</span> +<span class="info">--- a/config.mk</span> +<span class="info">+++ b/config.mk</span> +<span class="hunk">@@ -12,7 +12,7 @@ X11LIB = /usr/X11R6/lib</span> + + # includes and libs + INCS = -I. -I/usr/include -I${X11INC} +<span class="del">-LIBS = -L/usr/lib -lc -lcrypt -L${X11LIB} -lX11 -lXext -lXrandr</span> +<span class="add">+LIBS = -L/usr/lib -lc -lcrypt -L${X11LIB} -lX11 -lXext -lXrandr -lImlib2</span> + + # flags + CPPFLAGS = -DVERSION=\"${VERSION}\" -D_DEFAULT_SOURCE -DHAVE_SHADOW_H +<span class="info">diff --git a/slock.c b/slock.c</span> +<span class="info">index 5ae738c..7c63f34 100644</span> +<span class="info">--- a/slock.c</span> +<span class="info">+++ b/slock.c</span> +<span class="hunk">@@ -18,6 +18,7 @@</span> + #include <X11/keysym.h> + #include <X11/Xlib.h> + #include <X11/Xutil.h> +<span class="add">+#include <Imlib2.h></span> + + #include "arg.h" + #include "util.h" +<span class="hunk">@@ -35,6 +36,7 @@ struct lock {</span> + int screen; + Window root, win; + Pixmap pmap; +<span class="add">+ Pixmap bgmap;</span> + unsigned long colors[NUMCOLS]; + }; + +<span class="hunk">@@ -46,6 +48,8 @@ struct xrandr {</span> + + #include "config.h" + +<span class="add">+Imlib_Image image;</span> +<span class="add">+</span> + static void + die(const char *errstr, ...) + { +<span class="hunk">@@ -190,9 +194,10 @@ readpw(Display *dpy, struct xrandr *rr, struct lock **locks, int nscreens,</span> + color = len ? INPUT : ((failure || failonclear) ? FAILED : INIT); + if (running && oldc != color) { + for (screen = 0; screen < nscreens; screen++) { +<span class="del">- XSetWindowBackground(dpy,</span> +<span class="del">- locks[screen]->win,</span> +<span class="del">- locks[screen]->colors[color]);</span> +<span class="add">+ if(locks[screen]->bgmap)</span> +<span class="add">+ XSetWindowBackgroundPixmap(dpy, locks[screen]->win, locks[screen]->bgmap);</span> +<span class="add">+ else</span> +<span class="add">+ XSetWindowBackground(dpy, locks[screen]->win, locks[screen]->colors[0]);</span> + XClearWindow(dpy, locks[screen]->win); + } + oldc = color; +<span class="hunk">@@ -235,6 +240,17 @@ lockscreen(Display *dpy, struct xrandr *rr, int screen)</span> + lock->screen = screen; + lock->root = RootWindow(dpy, lock->screen); + +<span class="add">+ if(image) </span> +<span class="add">+ {</span> +<span class="add">+ lock->bgmap = XCreatePixmap(dpy, lock->root, DisplayWidth(dpy, lock->screen), DisplayHeight(dpy, lock->screen), DefaultDepth(dpy, lock->screen));</span> +<span class="add">+ imlib_context_set_image(image);</span> +<span class="add">+ imlib_context_set_display(dpy);</span> +<span class="add">+ imlib_context_set_visual(DefaultVisual(dpy, lock->screen));</span> +<span class="add">+ imlib_context_set_colormap(DefaultColormap(dpy, lock->screen));</span> +<span class="add">+ imlib_context_set_drawable(lock->bgmap);</span> +<span class="add">+ imlib_render_image_on_drawable(0, 0);</span> +<span class="add">+ imlib_free_image();</span> +<span class="add">+ }</span> + for (i = 0; i < NUMCOLS; i++) { + XAllocNamedColor(dpy, DefaultColormap(dpy, lock->screen), + colorname[i], &color, &dummy); +<span class="hunk">@@ -251,6 +267,8 @@ lockscreen(Display *dpy, struct xrandr *rr, int screen)</span> + CopyFromParent, + DefaultVisual(dpy, lock->screen), + CWOverrideRedirect | CWBackPixel, &wa); +<span class="add">+ if(lock->bgmap)</span> +<span class="add">+ XSetWindowBackgroundPixmap(dpy, lock->win, lock->bgmap);</span> + lock->pmap = XCreateBitmapFromData(dpy, lock->win, curs, 8, 8); + invisible = XCreatePixmapCursor(dpy, lock->pmap, lock->pmap, + &color, &color, 0, 0); +<span class="hunk">@@ -354,7 +372,16 @@ main(int argc, char **argv) {</span> + die("slock: setgid: %s\n", strerror(errno)); + if (setuid(duid) < 0) + die("slock: setuid: %s\n", strerror(errno)); +<span class="del">-</span> +<span class="add">+ </span> +<span class="add">+ /*Create screenshot Image*/</span> +<span class="add">+ Screen *scr = ScreenOfDisplay(dpy, DefaultScreen(dpy));</span> +<span class="add">+ image = imlib_create_image(scr->width,scr->height);</span> +<span class="add">+ imlib_context_set_image(image);</span> +<span class="add">+ imlib_context_set_display(dpy);</span> +<span class="add">+ imlib_context_set_visual(DefaultVisual(dpy,0));</span> +<span class="add">+ imlib_context_set_drawable(RootWindow(dpy,XScreenNumberOfScreen(scr))); </span> +<span class="add">+ imlib_copy_drawable_to_image(0,0,0,scr->width,scr->height,0,0,1);</span> +<span class="add">+ </span> + /* check for Xrandr support */ + rr.active = XRRQueryExtension(dpy, &rr.evbase, &rr.errbase);</code></pre> + +<pre><code class="diff"><span class="info">diff --git a/config.h b/config.h</span> +<span class="info">index c8e52d6..fcc1b39 100644</span> +<span class="info">--- a/config.h</span> +<span class="info">+++ b/config.h</span> +<span class="hunk">@@ -10,3 +10,6 @@ static const char *colorname[NUMCOLS] = {</span> + + /* treat a cleared input like a wrong password (color) */ + static const int failonclear = 1; +<span class="add">+</span> +<span class="add">+/*Set Blur radius*/</span> +<span class="add">+static const int blurRadius=5;</span> +\ No newline at end of file +<span class="info">diff --git a/slock.c b/slock.c</span> +<span class="info">index 7c63f34..0f24cd7 100644</span> +<span class="info">--- a/slock.c</span> +<span class="info">+++ b/slock.c</span> +<span class="hunk">@@ -372,7 +372,7 @@ main(int argc, char **argv) {</span> + die("slock: setgid: %s\n", strerror(errno)); + if (setuid(duid) < 0) + die("slock: setuid: %s\n", strerror(errno)); +<span class="del">- </span> +<span class="add">+</span> + /*Create screenshot Image*/ + Screen *scr = ScreenOfDisplay(dpy, DefaultScreen(dpy)); + image = imlib_create_image(scr->width,scr->height); +<span class="hunk">@@ -381,6 +381,7 @@ main(int argc, char **argv) {</span> + imlib_context_set_visual(DefaultVisual(dpy,0)); + imlib_context_set_drawable(RootWindow(dpy,XScreenNumberOfScreen(scr))); + imlib_copy_drawable_to_image(0,0,0,scr->width,scr->height,0,0,1); +<span class="add">+ imlib_image_blur(blurRadius);</span> + + /* check for Xrandr support */ + rr.active = XRRQueryExtension(dpy, &rr.evbase, &rr.errbase);</code></pre> + +<pre><code class="diff"><span class="info">diff --git a/config.h b/config.h</span> +<span class="info">index fcc1b39..1c1aef3 100644</span> +<span class="info">--- a/config.h</span> +<span class="info">+++ b/config.h</span> +<span class="hunk">@@ -12,4 +12,5 @@ static const char *colorname[NUMCOLS] = {</span> + static const int failonclear = 1; + + /*Set Blur radius*/ +<span class="del">-static const int blurRadius=5;</span> +\ No newline at end of file +<span class="add">+static const int blurRadius=0;</span> +<span class="add">+static const int pixelSize=5;</span> +<span class="info">diff --git a/slock.c b/slock.c</span> +<span class="info">index 0f24cd7..33ca569 100644</span> +<span class="info">--- a/slock.c</span> +<span class="info">+++ b/slock.c</span> +<span class="hunk">@@ -381,7 +381,49 @@ main(int argc, char **argv) {</span> + imlib_context_set_visual(DefaultVisual(dpy,0)); + imlib_context_set_drawable(RootWindow(dpy,XScreenNumberOfScreen(scr))); + imlib_copy_drawable_to_image(0,0,0,scr->width,scr->height,0,0,1); +<span class="add">+ </span> +<span class="add">+ /*Blur function*/</span> + imlib_image_blur(blurRadius); +<span class="add">+</span> +<span class="add">+</span> +<span class="add">+ /*Pixelation*/</span> +<span class="add">+ int width = scr->width;</span> +<span class="add">+ int height = scr->height;</span> +<span class="add">+ </span> +<span class="add">+ for(int y = 0; y < height; y += pixelSize)</span> +<span class="add">+ {</span> +<span class="add">+ for(int x = 0; x < width; x += pixelSize)</span> +<span class="add">+ {</span> +<span class="add">+ int red = 0;</span> +<span class="add">+ int green = 0;</span> +<span class="add">+ int blue = 0;</span> +<span class="add">+</span> +<span class="add">+ Imlib_Color pixel; </span> +<span class="add">+ Imlib_Color* pp;</span> +<span class="add">+ pp = &pixel;</span> +<span class="add">+ for(int j = 0; j < pixelSize && j < height; j++)</span> +<span class="add">+ {</span> +<span class="add">+ for(int i = 0; i < pixelSize && i < width; i++)</span> +<span class="add">+ {</span> +<span class="add">+ imlib_image_query_pixel(x+i,y+j,pp);</span> +<span class="add">+ red += pixel.red;</span> +<span class="add">+ green += pixel.green;</span> +<span class="add">+ blue += pixel.blue;</span> +<span class="add">+ }</span> +<span class="add">+ }</span> +<span class="add">+ red /= (pixelSize*pixelSize);</span> +<span class="add">+ green /= (pixelSize*pixelSize);</span> +<span class="add">+ blue /= (pixelSize*pixelSize);</span> +<span class="add">+ printf("R/G/B: %i/%i/%i\n",red,green,blue);</span> +<span class="add">+ imlib_context_set_color(red,green,blue,pixel.alpha);</span> +<span class="add">+ imlib_image_fill_rectangle(x,y,pixelSize,pixelSize);</span> +<span class="add">+ red = 0;</span> +<span class="add">+ green = 0;</span> +<span class="add">+ blue = 0;</span> +<span class="add">+ }</span> +<span class="add">+ }</span> +<span class="add">+ </span> +<span class="add">+ </span> + + /* check for Xrandr support */ + rr.active = XRRQueryExtension(dpy, &rr.evbase, &rr.errbase);</code></pre> + +<pre><code class="diff"><span class="info">diff --git a/slock.c b/slock.c</span> +<span class="info">index 33ca569..f54c459 100644</span> +<span class="info">--- a/slock.c</span> +<span class="info">+++ b/slock.c</span> +<span class="hunk">@@ -414,7 +414,6 @@ main(int argc, char **argv) {</span> + red /= (pixelSize*pixelSize); + green /= (pixelSize*pixelSize); + blue /= (pixelSize*pixelSize); +<span class="del">- printf("R/G/B: %i/%i/%i\n",red,green,blue);</span> + imlib_context_set_color(red,green,blue,pixel.alpha); + imlib_image_fill_rectangle(x,y,pixelSize,pixelSize); + red = 0;</code></pre> + +<pre><code class="diff"><span class="info">diff --git a/config.mk b/config.mk</span> +<span class="info">index 987819e..d0c2f01 100644</span> +<span class="info">--- a/config.mk</span> +<span class="info">+++ b/config.mk</span> +<span class="hunk">@@ -16,7 +16,7 @@ LIBS = -L/usr/lib -lc -lcrypt -L${X11LIB} -lX11 -lXext -lXrandr -lImlib2</span> + + # flags + CPPFLAGS = -DVERSION=\"${VERSION}\" -D_DEFAULT_SOURCE -DHAVE_SHADOW_H +<span class="del">-CFLAGS = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS}</span> +<span class="add">+CFLAGS = -std=c99 -pedantic -Wall -Ofast ${INCS} ${CPPFLAGS}</span> + LDFLAGS = -s ${LIBS} + COMPATSRC = explicit_bzero.c</code></pre> + +<pre><code class="diff"><span class="info">diff --git a/config.h b/config.h</span> +<span class="info">index 1c1aef3..5407953 100644</span> +<span class="info">--- a/config.h</span> +<span class="info">+++ b/config.h</span> +<span class="hunk">@@ -11,6 +11,11 @@ static const char *colorname[NUMCOLS] = {</span> + /* treat a cleared input like a wrong password (color) */ + static const int failonclear = 1; + +<span class="del">-/*Set Blur radius*/</span> +<span class="del">-static const int blurRadius=0;</span> +<span class="del">-static const int pixelSize=5;</span> +<span class="add">+/*Enable blur*/</span> +<span class="add">+#define BLUR</span> +<span class="add">+/*Set blur radius*/</span> +<span class="add">+static const int blurRadius=5;</span> +<span class="add">+/*Enable Pixelation*/</span> +<span class="add">+//#define PIXELATION</span> +<span class="add">+/*Set pixelation radius*/</span> +<span class="add">+static const int pixelSize=0;</span> +<span class="info">diff --git a/slock.c b/slock.c</span> +<span class="info">index f54c459..1a4d6e3 100644</span> +<span class="info">--- a/slock.c</span> +<span class="info">+++ b/slock.c</span> +<span class="hunk">@@ -381,11 +381,14 @@ main(int argc, char **argv) {</span> + imlib_context_set_visual(DefaultVisual(dpy,0)); + imlib_context_set_drawable(RootWindow(dpy,XScreenNumberOfScreen(scr))); + imlib_copy_drawable_to_image(0,0,0,scr->width,scr->height,0,0,1); +<span class="del">- </span> +<span class="add">+</span> +<span class="add">+#ifdef BLUR</span> +<span class="add">+</span> + /*Blur function*/ + imlib_image_blur(blurRadius); +<span class="add">+#endif // BLUR </span> + +<span class="del">-</span> +<span class="add">+#ifdef PIXELATION</span> + /*Pixelation*/ + int width = scr->width; + int height = scr->height; +<span class="hunk">@@ -423,7 +426,7 @@ main(int argc, char **argv) {</span> + } + + +<span class="del">- </span> +<span class="add">+#endif</span> + /* check for Xrandr support */ + rr.active = XRRQueryExtension(dpy, &rr.evbase, &rr.errbase);</code></pre> +<p>De tal forma que, una vez aplicados los cambios de software, al ser ejecutado captura la pantalla completa usando <emb>imlib2</emb> (<emb>imlib_copy_drawable_to_image</emb> desde <emb>RootWindow</emb>), aplica desenfoque directamente sobre es imagen en memoria con <emb>imlib_image_blur(blurRadius)</emb> y la convierte en un Pixmap, que pone como fondo de ventana de bloqueo con <emb>XSetWindowBackgroundPixmap</emb>.</p> +<p>Quedando un fondo como el siguiente ejemplo:</p> +<img src="slock-blur.gif" /> +<p>Una vez instalado el programa y siendo posible invocarlo desde cualquier terminal o dmenu, el siguiente es, para mí, crearle un acceso directo de teclas para, desde el gestor de ventanas que utilizo (dwm) poder invocarlo más rápidamente cuando quiera bloquear la pantalla manualmente. Esto lo he hecho sencillamente modificando el <emb>config.h</emb>, y añadiendo:</p> +<pre><code class="diff"><span class="info">diff --git a/config.h b/config.h</span> +<span class="hunk">@@ -62,11 +62,13 @@ static const Layout layouts[] = {</span> + 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_cyan, "-sf", col_gray4, NULL }; + static const char *termcmd[] = { "xterm", NULL }; +<span class="add">+static const char *slockcmd[] = { "slock", NULL };</span> + + static const Key keys[] = { + /* modifier key function argument */ + { MODKEY, XK_r, spawn, {.v = dmenucmd } }, + { MODKEY, XK_Return, spawn, {.v = termcmd } }, +<span class="add">+ { MODKEY|ShiftMask, XK_l, spawn, { .v = slockcmd} },</span> + { MODKEY, XK_b, togglebar, {0} }, + { MODKEY, XK_j, focusstack, {.i = +1 } }, + { MODKEY, XK_k, focusstack, {.i = -1 } },</code></pre> +<p>De tal forma que, con la pulsación de teclas <kbd>Mod4</kbd>+<kbd>Shift</kbd>+<kbd>l</kbd> se ejecuta slock y se bloquea la pantalla.</p> +<p>Cuando cierro la tapa del portátil, el equipo se suspende. Esto provoca el equipo apague casi todos los componentes físicos, pero mantenga una leve alimentación a la memoria RAM, la cual contiene todo el contenido tal cual estaba. De tal forma, al despertar (o abrir la tapa) el equipo alimenta todos los componentes de nuevo, e inicia rápidamente, casi instantáneamente, pues la información ya estaba en RAM. Por lo que cuando voy a desplazarme, cierro y abro la tapa manteniendo la sesión íntegra.</p> +<p>Sin embargo, si no he ejecutado slock antes, al abrir la sesión no estará protegida. Esto es un riesgo de seguridad, pues un tercero podría hacerse con la máquina suspendida, despertarla y tener acceso a toda la sesión sin protección de ningún tipo. Por lo tanto, es interesante añadir una ejecución de slock automática al suspender el equipo.</p> +<p>Eso sí, a menudo tengo el equipo conectado por HDMI a algún monitor o TV, siendo que me interesa cerrar la tapa directamente y mantener el equipo en funcionamiento en otro monitor, por lo que hacerlo automático al cerrar la tapa no sería útil; sino, en concreto, suspender el equipo. La forma, pues, más limpia y fiable será usar, con <emb>elogind</emb>, los hooks de <emb>system-sleep</emb>. Estos son los scripts que se ejecutan automáticamente antes y después de cualquier suspensión o hibernación, independientemente si se activa por cerrar la tapa o por cualquier otro motivo programado. <emb>elogind</emb> es un módulo de systemd que gestiona el login de usuarios, sesiones gráficas y el manejo de energía, pero separada y sin depender de todo systemd, claro (si no, no sería software nativo en Slackware 15).</p> +<p>Lo que he hecho es crear un script en <emb>/lib64/elogind/system-sleep</emb> como el siguiente:</p> +<pre><code>#!/bin/sh +#/lib64/elogind/system-sleep/lock-slock + +USER="javier" +USERHOME="/home/$USER" +DISPLAY=:0 +XAUTHORITY="$USERHOME/.Xauthority" + +case "$1" in + pre) + export DISPLAY XAUTHORITY + su - "$USER" -c "slock" & + sleep 1.5 + ;; + post) + ;; +esac</code></pre> +<p>Evidentemente con sus privilegios necesarios y el reinicio del demonio <emb>elogind</emb>. También podemos ejecutar el último comando para corroborar que, efectivamente, se bloquea la pantalla:</p> +<pre><code>chmod +x /lib64/elogind/system-sleep/lock-slock +/etc/rc.d/rc.elogind restart +/lib64/elogind/system-sleep/lock-slock pre suspend</code></pre> +<p>De tal forma, el equipo se bloqueará usando slock justo antes de ser suspendido, garantizando la seguridad de la máquina una vez despierta.</p> +</body> +</html> diff --git a/dwm-slock/slock-blur.gif b/dwm-slock/slock-blur.gif Binary files differ. diff --git a/dwm-slstatus/index.html b/dwm-slstatus/index.html @@ -0,0 +1,100 @@ +<!DOCTYPE html> +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<meta name="viewport" content="width=device-width, initial-scale=1" /> +<title>Configuración de slstatus</title> +<link rel="icon" type="image/png" href="/favicon.png" /> +<link rel="stylesheet" type="text/css" href="../article.css" /> +</head> +<body> +<header> +<p class="title">Configuración de slstatus</p> +<p class="date">22 de junio de 2026 • fjbalon</p> +</header> +<p>slstatus es un monitor de estado minimalista para dwm, desarrollado, evidentemente por suckless. Lo que hace es añadir información a la barra de estado, arriba a la derecha por defecto, de tal forma que el usuario puede, en dwm, configurar una vista de la fecha y hora, de la capacidad de batería, del estado del brillo y del volumen, de la IP de salida actual, etcétera. Lo que el usuario parametrice.</p> +<p>Puede encontrar mi propia versión del código en mi servidor de git: <a href="https://templier.es/git/slstatus/">/git/slstatus/</a>.</p> +<p>Su uso es extremadamente sencillo, siendo que por defecto; la configuración de <emb>config.h</emb> es la siguiente:</p> +<pre><code>const unsigned int interval = 1000; +static const char unknown_str[] = "n/a"; +#define MAXLEN 2048 + +static const struct arg args[] = { + { datetime, "%s", "%F %T" }, +};</code></pre> +<p>La configuración por defecto de <emb>datetime</emb> la he dejado con una configuración que me gusta algo más: <emb>{ datetime, " %s", "%d/%m/%y %H:%M" },</emb>, de tal forma que la fecha mostrada es <emb>22/07/26 16:59</emb>.</p> +<p>Lo que más nos interesa por el momento es la estructura <emb>arg</emb>, que es un array de elementos a mostrar por pantalla. En un inicio, sólo mostrará la fecha y hora. Pero hay muchas más opciones ya programadas en el código base, como <emb>battery_perc</emb>. <emb>battery_remaining</emb> y <emb>battery_state</emb>, que muestra el porcentaje de batería, el cálculo del tiempo restante y el estado de la batería (en carga, en descarga, completa...), respectivamente.</p> +<p>De tal forma añado, en mi caso, el siguiente contenido para su muestra en la barra de estado:</p> +<pre><code>{ battery_state, "%s", "BAT0" }, +{ battery_perc, "%s", "BAT0" }, +{ battery_remaining, " %s", "BAT0" },</code></pre> +<p>Por gusto personal he cambiado también el código de <emb>components/battery.c</emb>, para que al descargar muestre <emb>ϟ</emb> y al cargar, <emb>ϟϟ</emb>.</p> +<pre><code class="diff"><span class="info">diff --git a/components/battery.c b/components/battery.c</span> +<span class="hunk">@@ -56,8 +56,8 @@</span> + char *state; + char *symbol; + } map[] = { +<span class="del">- { "Charging", "+" },</span> +<span class="del">- { "Discharging", "-" },</span> +<span class="add">+ { "Charging", "ϟϟ" },</span> +<span class="add">+ { "Discharging", "ϟ" },</span> + { "Full", "o" }, + { "Not charging", "o" }, + };</code></pre> + +<!-- + * battery_perc battery percentage battery name (BAT0) + * NULL on OpenBSD/FreeBSD + * battery_remaining battery remaining HH:MM battery name (BAT0) + * NULL on OpenBSD/FreeBSD + * battery_state battery charging state battery name (BAT0) + * NULL on OpenBSD/FreeBSD + * cat read arbitrary file path + * cpu_freq cpu frequency in MHz NULL + * cpu_perc cpu usage in percent NULL + * datetime date and time format string (%F %T) + * disk_free free disk space in GB mountpoint path (/) + * disk_perc disk usage in percent mountpoint path (/) + * disk_total total disk space in GB mountpoint path (/) + * disk_used used disk space in GB mountpoint path (/) + * entropy available entropy NULL + * gid GID of current user NULL + * hostname hostname NULL + * ipv4 IPv4 address interface name (eth0) + * ipv6 IPv6 address interface name (eth0) + * kernel_release `uname -r` NULL + * keyboard_indicators caps/num lock indicators format string (c?n?) + * see keyboard_indicators.c + * keymap layout (variant) of current NULL + * keymap + * load_avg load average NULL + * netspeed_rx receive network speed interface name (wlan0) + * netspeed_tx transfer network speed interface name (wlan0) + * num_files number of files in a directory path + * (/home/foo/Inbox/cur) + * ram_free free memory in GB NULL + * ram_perc memory usage in percent NULL + * ram_total total memory size in GB NULL + * ram_used used memory in GB NULL + * run_command custom shell command command (echo foo) + * swap_free free swap in GB NULL + * swap_perc swap usage in percent NULL + * swap_total total swap size in GB NULL + * swap_used used swap in GB NULL + * temp temperature in degree celsius sensor file + * (/sys/class/thermal/...) + * NULL on OpenBSD + * thermal zone on FreeBSD + * (tz0, tz1, etc.) + * uid UID of current user NULL + * up interface is running interface name (eth0) + * uptime system uptime NULL + * username username of current user NULL + * vol_perc OSS/ALSA volume in percent mixer file (/dev/mixer) + * NULL on OpenBSD/FreeBSD + * wifi_essid WiFi ESSID interface name (wlan0) + * wifi_perc WiFi signal in percent interface name (wlan0) +--> + +</body> +</html> diff --git a/dwm/index.html b/dwm/index.html @@ -0,0 +1,53 @@ +<!DOCTYPE html> +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<meta name="viewport" content="width=device-width, initial-scale=1" /> +<title>Del por qué uso gestor de ventanas en lugar de un entorno de escritorio y del por qué dwm</title> +<link rel="icon" type="image/png" href="/favicon.png" /> +<link rel="stylesheet" type="text/css" href="../article.css" /> +</head> +<body> +<header> +<p class="title">Del por qué uso gestor de ventanas (dwm) en lugar de un entorno de escritorio</p> +<p class="date">8 de octubre de 2021 • fjbalon</p> +</header> +<p>Unix tiene algo esotérico, algo de carácter iniciático. Hay una verdadera barrera entre el usuario y el verdadero emperador de su sistema: el root. Los sistemas Unix son, en esencia, un arte arcaico. Un sistema operativo que se revela sólo ante los que están dispuestos al sacrificio, a descender a a más bajo nivel, a susurrar a la máquina.</p> +<p>Yo fui iniciado allá por 2011. Y como tal, aprendí y pivotaba de una distribución a otra. <em>Distrohopping </em>lo llaman ahora. Es una regla no escrita en los iniciados. Inicié con Ubuntu 10.10 y en seguida profundicé en Debian; vacilé con algunas distribuciones hijas, pero me quedé en el buen Debian hasta por allá de 2013. Entonces, instalé Archlinux y me convertí en fiel adepto de su grimorio y su estructura, de Pacman y de su procedimiento de instalación. He sido hijo de Archlinux muchos años, hasta que en 2019 abracé Slackware, la más antigua y la más Unix de las distribuciones de Linux.</p> +<p>Pero este texto no versa sobre distribuciones, sino por el uso que el usuario general de sistemas operativos basados en Unix hace gráficamente. La interfaz de texto es la forma humano-máquina perfecta, más precisa, más metódica, más natural. Son hechizos que se hacen en la shell, una puerta del conocimiento cuasi gnóstico de las tripas del sistema, heredada de su propia filosofía y doctrina minimalista y modular. Unix siempre ha rechazado la opulencia y la complejidad, rechaza la vanidad. La interfaz de texto invita a una comprensión mucho más profunda, quien entiende la shell entiende cómo funciona el sistema operativo y entiende cómo funciona Linux.</p> +<p>Sin embargo, a pesar de su superioridad, hoy día es necesario poder visualizar y ejecutar aplicaciones gráficas en el sistema, ordenarlas visualmente, utilizar el ratón, interactuar con algo más que texto, etcétera. Esto no es impedimento para la profundización en el sistema, sino un añadido, una capa más que se superpone a la shell (otra de las muchas razones por las que, esencial y estructuralmente, los sistemas herederos de Unix son superiores a los de Microsoft). Para ello existe lo que se denomina entorno de escritorio.</p> +<p>Un entorno de escritorio es un conjunto, una suite, de aplicaciones gráficas que proveen al usuario de estas funciones. Al igual que el conocido <em>distrohopping</em>, existe algo similar en los iniciados con los entornos gráficos. Estos entornos se hacen lo más amigable posibles, lo más cercano a usuarios inexpertos, se hacen cómodas de usar; ocultan su maquinaria interna. Al igual que haciendo pivotado entre distros, también desde bien temprano conocimiento pivoté por Gnome, Mate, KDE -después Plasma-, XFCE. Usé varios años LXDE. Probé Enlightenment y Cinnamon. Incluso Unity. Sin embargo, a ninguno amé. Reconozco que LXDE, que use más tiempo que el resto, puede ser un gran candidato, por simplicidad y minimalismo. Pero estos entornos están esencialmente limitados a sí mismos. </p> +<p>Unix te exigirá más.</p> +<p>Es entonces que conocerás al gestor de ventanas, o windows manager. El gestor de ventanas es el programa, que por cierto forma parte fundamental de todo entorno gráfico, cuya función es manejar la disposición de las ventanas; determina cómo las ventanas se organizan en el espacio y cómo interactúan entre sí, actúa como motor para el modelo matemático y geométrico del comportamiento de la interfaz gráfica.</p> +<p>Controlar el gestor de ventanas te dota, usuario, de una capacidad matemática y computacional mayor, interfaz humano-máquina superior, puesto que controla la geometría para determinar cómo las ventanas se superponen o se organizan en mosaicos, pilas, etcétera. El código interactúa directamente con las bibliotecas gráficas para dibujar y manipular estas ventanas. El gestor de ventanas habla con el servidor gráfico. </p> +<p>Las razones por las utilizar un gestor de ventanas y no sobrevitaminarlo con entorno de escritorio alguno son variadas, e incluso contradictorias según el usuario. Yo me he quedado con el uso de gestor de ventanas por:</p> +<ol> +<li>El software empleado es mínimo, tanto a nivel técnico como a nivel estético. Haciendo que sea fácil su modificación y que funcione de la misma forma en máquinas de bajos recursos hardware. Además, ocupan muy poco en memoria.</li> +<li>Como programador, la capacidad de tener control absoluto sobre su software, en este caso sobre la matemática y la geometría de sus ventanas, y la interfaz humano-máquina, es absoluta.</li> +<li>Al carecer de añadidos estéticos como animaciones, la velocidad de uso es exponencial a la experiencia adquirida. El ahorro de tiempo y la mejora en productividad es un valor añadido.</li> +<li>Los distintos modos de pantalla (mosaico, flotante...) permiten una personalización y adaptación de uso como ningún otro entorno.</li> +<li>La primacía del teclado y la independencia del ratón.</li> +<li>Y por supuesto, el hecho de pertenecer a ese selecto grupo de hackers del mosaico, esa comunidad descentralizada que a los ojos de los profanos son de intelecto superior. La secta de Linux.</li> +</ol> +<p>Mis primeras pruebas las realicé sobre i3 y Openbox, pero no fue hasta que probé AwesomeWM que su velocidad, personalización en el lenguaje de programación Lua y complementación para con mi uso diario le hicieran el gestor de ventanas que comenzaría a utilizar, allá por 2014 hasta 2019. Son unos 5 años de uso diario y exclusivo de este gestor de ventanas, por lo que tengo un cariño especial a éste y su mítico fondo.</p> +<p>A principios de 2020 migré, paulatinamente, a dwm (dynamic windows manager) de suckless. No considero éste un cambio de pensamiento o conversión, en absoluto, sino más bien el haber alcanzado una plenitud -más a bajo nivel- de AwesomeWM; una evolución. dwm es la base de AwesomeWM, siendo el último un fork el primero con XCB, EWMH, Lua script, Xft, D-Bus, multihead support..., y al estar a más bajo nivel, he ganado simplificación de código (éste está íntegramente escrito en C, y no cuenta con archivos de configuración en Lua), velocidad (dwm es absurdamente rápido), y una notable mejora de rendimiento y eficiencia.</p> +<p>dwm cuenta con una serie de características que, para mí, en mi experiencia diaria, son fundamentales:</p> +<ol> +<li>Mantiene prácticamente la totalidad de la superficie de pantalla utilizable.</li> +<li>Se inicia instantáneamente, incluso en máquinas de baja potencia.</li> +<li>Es independiente. Puede ser compilado y ejecutado en cualquier heredero de Unix, sea GNU/Linux, sea BSD, sea Solaris.</li> +<li>Implementa un reflejo, efigie perfecta de mis propios patrones de uso:</li> +<ol> +<li>No quiero redimensionar o mover una ventana manualmente de primeras, a no ser que quiera hacerlo.</li> +<li>Normalmente tengo al menos dos ventanas abiertas, una al lado de la otra; una maestra y otra esclava.</li> +<li>A veces quiero mutar una ventana a pantalla completa rápidamente, y volver al estado anterior con la misma velocidad.</li> +<li>Siempre quiero usar todo el espacio de pantalla disponible para mostrar contenido.</li> +<li>Me gusta usar varios escritorios para trabajar. A menudo, también varios monitores.</li> +<li>Quiero atajos de teclado para todo. La primacía del teclado sobre el ratón es fundamental. El ratón queda relegado a tareas indispensables, como el uso del navegador o de otras aplicaciones concretas.</li> +</ol> +<li>Intuitivamente, dwm coloca las ventanas exactamente donde yo las hubiera colocado.</li> +<li>De hecho, dwm hace que sea tan fácil mover ventanas que casi nunca echo de menos tener varios monitores. En mi casa o trabajo los tengo, pero cuando viajo no.</li> +<li>Me declaro adepto de la filosofía de suckless, así como su modelo de implementación de parches y minimalismo.</li> +</ol> +</body> +</html> +\ No newline at end of file diff --git a/index.html b/index.html @@ -18,7 +18,30 @@ <section class="blog"> -Hola mundo. +<a href="./dwm-dmenu/" class="article"> + <p class="title">Configuración propia del lanzador de aplicación dmenu</p> + <p class="info">25 de junio de 2026 · fjbalon</p><p>dmenu es un lanzador de aplicaciones, extremadamente ligero y rápido para el sistemas de ventanas X, diseñado originalmente para el gestor de ventanas dwm, de suckless. Es una herramienta que, para ...</p> +</a> + +<a href="./dwm-slstatus/" class="article"> + <p class="title">Configuración de slstatus</p> + <p class="info">22 de junio de 2026 · fjbalon</p><p>slstatus es un monitor de estado minimalista para dwm, desarrollado, evidentemente por suckless. Lo que hace es añadir información a la barra de estado, arriba a la derecha por defecto, de tal forma...</p> +</a> + +<a href="./dwm-slock/" class="article"> + <p class="title">Configuración propia del bloqueador de pantalla slock</p> + <p class="info">22 de junio de 2026 · fjbalon</p><p>Un software que me gusta bastante de la caja de herramientas de suckless es slock, un bloqueador de pantalla minimalista; tan minimalista que yo creo que es el bloqueador de pantalla x más sencillo q...</p> +</a> + +<a href="./dwm-howto/" class="article"> + <p class="title">Configuración y uso personal de dwm</p> + <p class="info">9 de octubre de 2021 · fjbalon</p><p>En orden a construir dwm necesita los archivos de cabecera de Xlib. Edite config.mk para localizar tu configuración local (dwm es instalado en usr/local por defecto). La instalación se realiza direc...</p> +</a> + +<a href="./dwm/" class="article"> + <p class="title">Del por qué uso gestor de ventanas (dwm) en lugar de un entorno de escritorio</p> + <p class="info">8 de octubre de 2021 · fjbalon</p><p>Unix tiene algo esotérico, algo de carácter iniciático. Hay una verdadera barrera entre el usuario y el verdadero emperador de su sistema: el root. Los sistemas Unix son, en esencia, un arte arcaic...</p> +</a> </section> </body>