Configuración propia del bloqueador de pantalla slock
22 de junio de 2026 • fjbalon
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.
Puede encontrar mi propia versión del código en mi servidor de git: /git/slock/.
En términos generales, slock crea una ventana fullscreen que cubre todos los monitores, toma el teclado y el ratón (
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.
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.
Por lo tanto, lo que más estético me ha parecido es aplicar el llamado parche Blured or pixelated screenshot:
diff --git a/config.mk b/config.mk
index 74429ae..987819e 100644
--- a/config.mk
+++ b/config.mk
@@ -12,7 +12,7 @@ X11LIB = /usr/X11R6/lib
# includes and libs
INCS = -I. -I/usr/include -I${X11INC}
-LIBS = -L/usr/lib -lc -lcrypt -L${X11LIB} -lX11 -lXext -lXrandr
+LIBS = -L/usr/lib -lc -lcrypt -L${X11LIB} -lX11 -lXext -lXrandr -lImlib2
# flags
CPPFLAGS = -DVERSION=\"${VERSION}\" -D_DEFAULT_SOURCE -DHAVE_SHADOW_H
diff --git a/slock.c b/slock.c
index 5ae738c..7c63f34 100644
--- a/slock.c
+++ b/slock.c
@@ -18,6 +18,7 @@
#include <X11/keysym.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
+#include <Imlib2.h>
#include "arg.h"
#include "util.h"
@@ -35,6 +36,7 @@ struct lock {
int screen;
Window root, win;
Pixmap pmap;
+ Pixmap bgmap;
unsigned long colors[NUMCOLS];
};
@@ -46,6 +48,8 @@ struct xrandr {
#include "config.h"
+Imlib_Image image;
+
static void
die(const char *errstr, ...)
{
@@ -190,9 +194,10 @@ readpw(Display *dpy, struct xrandr *rr, struct lock **locks, int nscreens,
color = len ? INPUT : ((failure || failonclear) ? FAILED : INIT);
if (running && oldc != color) {
for (screen = 0; screen < nscreens; screen++) {
- XSetWindowBackground(dpy,
- locks[screen]->win,
- locks[screen]->colors[color]);
+ if(locks[screen]->bgmap)
+ XSetWindowBackgroundPixmap(dpy, locks[screen]->win, locks[screen]->bgmap);
+ else
+ XSetWindowBackground(dpy, locks[screen]->win, locks[screen]->colors[0]);
XClearWindow(dpy, locks[screen]->win);
}
oldc = color;
@@ -235,6 +240,17 @@ lockscreen(Display *dpy, struct xrandr *rr, int screen)
lock->screen = screen;
lock->root = RootWindow(dpy, lock->screen);
+ if(image)
+ {
+ lock->bgmap = XCreatePixmap(dpy, lock->root, DisplayWidth(dpy, lock->screen), DisplayHeight(dpy, lock->screen), DefaultDepth(dpy, lock->screen));
+ imlib_context_set_image(image);
+ imlib_context_set_display(dpy);
+ imlib_context_set_visual(DefaultVisual(dpy, lock->screen));
+ imlib_context_set_colormap(DefaultColormap(dpy, lock->screen));
+ imlib_context_set_drawable(lock->bgmap);
+ imlib_render_image_on_drawable(0, 0);
+ imlib_free_image();
+ }
for (i = 0; i < NUMCOLS; i++) {
XAllocNamedColor(dpy, DefaultColormap(dpy, lock->screen),
colorname[i], &color, &dummy);
@@ -251,6 +267,8 @@ lockscreen(Display *dpy, struct xrandr *rr, int screen)
CopyFromParent,
DefaultVisual(dpy, lock->screen),
CWOverrideRedirect | CWBackPixel, &wa);
+ if(lock->bgmap)
+ XSetWindowBackgroundPixmap(dpy, lock->win, lock->bgmap);
lock->pmap = XCreateBitmapFromData(dpy, lock->win, curs, 8, 8);
invisible = XCreatePixmapCursor(dpy, lock->pmap, lock->pmap,
&color, &color, 0, 0);
@@ -354,7 +372,16 @@ main(int argc, char **argv) {
die("slock: setgid: %s\n", strerror(errno));
if (setuid(duid) < 0)
die("slock: setuid: %s\n", strerror(errno));
-
+
+ /*Create screenshot Image*/
+ Screen *scr = ScreenOfDisplay(dpy, DefaultScreen(dpy));
+ image = imlib_create_image(scr->width,scr->height);
+ imlib_context_set_image(image);
+ imlib_context_set_display(dpy);
+ 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);
+
/* check for Xrandr support */
rr.active = XRRQueryExtension(dpy, &rr.evbase, &rr.errbase);
diff --git a/config.h b/config.h
index c8e52d6..fcc1b39 100644
--- a/config.h
+++ b/config.h
@@ -10,3 +10,6 @@ static const char *colorname[NUMCOLS] = {
/* treat a cleared input like a wrong password (color) */
static const int failonclear = 1;
+
+/*Set Blur radius*/
+static const int blurRadius=5;
\ No newline at end of file
diff --git a/slock.c b/slock.c
index 7c63f34..0f24cd7 100644
--- a/slock.c
+++ b/slock.c
@@ -372,7 +372,7 @@ main(int argc, char **argv) {
die("slock: setgid: %s\n", strerror(errno));
if (setuid(duid) < 0)
die("slock: setuid: %s\n", strerror(errno));
-
+
/*Create screenshot Image*/
Screen *scr = ScreenOfDisplay(dpy, DefaultScreen(dpy));
image = imlib_create_image(scr->width,scr->height);
@@ -381,6 +381,7 @@ main(int argc, char **argv) {
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);
+ imlib_image_blur(blurRadius);
/* check for Xrandr support */
rr.active = XRRQueryExtension(dpy, &rr.evbase, &rr.errbase);
diff --git a/config.h b/config.h
index fcc1b39..1c1aef3 100644
--- a/config.h
+++ b/config.h
@@ -12,4 +12,5 @@ static const char *colorname[NUMCOLS] = {
static const int failonclear = 1;
/*Set Blur radius*/
-static const int blurRadius=5;
\ No newline at end of file
+static const int blurRadius=0;
+static const int pixelSize=5;
diff --git a/slock.c b/slock.c
index 0f24cd7..33ca569 100644
--- a/slock.c
+++ b/slock.c
@@ -381,7 +381,49 @@ main(int argc, char **argv) {
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);
+
+ /*Blur function*/
imlib_image_blur(blurRadius);
+
+
+ /*Pixelation*/
+ int width = scr->width;
+ int height = scr->height;
+
+ for(int y = 0; y < height; y += pixelSize)
+ {
+ for(int x = 0; x < width; x += pixelSize)
+ {
+ int red = 0;
+ int green = 0;
+ int blue = 0;
+
+ Imlib_Color pixel;
+ Imlib_Color* pp;
+ pp = &pixel;
+ for(int j = 0; j < pixelSize && j < height; j++)
+ {
+ for(int i = 0; i < pixelSize && i < width; i++)
+ {
+ imlib_image_query_pixel(x+i,y+j,pp);
+ red += pixel.red;
+ green += pixel.green;
+ blue += pixel.blue;
+ }
+ }
+ red /= (pixelSize*pixelSize);
+ green /= (pixelSize*pixelSize);
+ blue /= (pixelSize*pixelSize);
+ printf("R/G/B: %i/%i/%i\n",red,green,blue);
+ imlib_context_set_color(red,green,blue,pixel.alpha);
+ imlib_image_fill_rectangle(x,y,pixelSize,pixelSize);
+ red = 0;
+ green = 0;
+ blue = 0;
+ }
+ }
+
+
/* check for Xrandr support */
rr.active = XRRQueryExtension(dpy, &rr.evbase, &rr.errbase);
diff --git a/slock.c b/slock.c
index 33ca569..f54c459 100644
--- a/slock.c
+++ b/slock.c
@@ -414,7 +414,6 @@ main(int argc, char **argv) {
red /= (pixelSize*pixelSize);
green /= (pixelSize*pixelSize);
blue /= (pixelSize*pixelSize);
- printf("R/G/B: %i/%i/%i\n",red,green,blue);
imlib_context_set_color(red,green,blue,pixel.alpha);
imlib_image_fill_rectangle(x,y,pixelSize,pixelSize);
red = 0;
diff --git a/config.mk b/config.mk
index 987819e..d0c2f01 100644
--- a/config.mk
+++ b/config.mk
@@ -16,7 +16,7 @@ LIBS = -L/usr/lib -lc -lcrypt -L${X11LIB} -lX11 -lXext -lXrandr -lImlib2
# flags
CPPFLAGS = -DVERSION=\"${VERSION}\" -D_DEFAULT_SOURCE -DHAVE_SHADOW_H
-CFLAGS = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS}
+CFLAGS = -std=c99 -pedantic -Wall -Ofast ${INCS} ${CPPFLAGS}
LDFLAGS = -s ${LIBS}
COMPATSRC = explicit_bzero.c
diff --git a/config.h b/config.h
index 1c1aef3..5407953 100644
--- a/config.h
+++ b/config.h
@@ -11,6 +11,11 @@ static const char *colorname[NUMCOLS] = {
/* treat a cleared input like a wrong password (color) */
static const int failonclear = 1;
-/*Set Blur radius*/
-static const int blurRadius=0;
-static const int pixelSize=5;
+/*Enable blur*/
+#define BLUR
+/*Set blur radius*/
+static const int blurRadius=5;
+/*Enable Pixelation*/
+//#define PIXELATION
+/*Set pixelation radius*/
+static const int pixelSize=0;
diff --git a/slock.c b/slock.c
index f54c459..1a4d6e3 100644
--- a/slock.c
+++ b/slock.c
@@ -381,11 +381,14 @@ main(int argc, char **argv) {
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);
-
+
+#ifdef BLUR
+
/*Blur function*/
imlib_image_blur(blurRadius);
+#endif // BLUR
-
+#ifdef PIXELATION
/*Pixelation*/
int width = scr->width;
int height = scr->height;
@@ -423,7 +426,7 @@ main(int argc, char **argv) {
}
-
+#endif
/* check for Xrandr support */
rr.active = XRRQueryExtension(dpy, &rr.evbase, &rr.errbase);
De tal forma que, una vez aplicados los cambios de software, al ser ejecutado captura la pantalla completa usando
Quedando un fondo como el siguiente ejemplo:
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
diff --git a/config.h b/config.h
@@ -62,11 +62,13 @@ static const Layout layouts[] = {
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 };
+static const char *slockcmd[] = { "slock", NULL };
static const Key keys[] = {
/* modifier key function argument */
{ MODKEY, XK_r, spawn, {.v = dmenucmd } },
{ MODKEY, XK_Return, spawn, {.v = termcmd } },
+ { MODKEY|ShiftMask, XK_l, spawn, { .v = slockcmd} },
{ MODKEY, XK_b, togglebar, {0} },
{ MODKEY, XK_j, focusstack, {.i = +1 } },
{ MODKEY, XK_k, focusstack, {.i = -1 } },
De tal forma que, con la pulsación de teclas Mod4+Shift+l se ejecuta slock y se bloquea la pantalla.
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.
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.
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
Lo que he hecho es crear un script en
#!/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
Evidentemente con sus privilegios necesarios y el reinicio del demonio
chmod +x /lib64/elogind/system-sleep/lock-slock
/etc/rc.d/rc.elogind restart
/lib64/elogind/system-sleep/lock-slock pre suspend
De tal forma, el equipo se bloqueará usando slock justo antes de ser suspendido, garantizando la seguridad de la máquina una vez despierta.