slock

Simple X display locker (fork)
git clone https://git.sinitax.com/sinitax/slock
Log | Files | Refs | README | LICENSE | Upstream | sfeed.txt

commit 764b955f0678f34c23ba27b87b23bce280ce909c
parent fad6aca78f2b54089c44a33da5124f2fd994bf33
Author: Louis Burda <quent.burda@gmail.com>
Date:   Thu, 28 Sep 2023 02:16:32 +0200

Display message when screen is locked

Diffstat:
Mconfig.def.h | 10++++++++++
Mconfig.mk | 1+
Mslock.1 | 7+++++++
Mslock.c | 138++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
4 files changed, 151 insertions(+), 5 deletions(-)

diff --git a/config.def.h b/config.def.h @@ -14,6 +14,16 @@ static const int controlkeyclear = 0; /* time in seconds before the monitor shuts down */ static const int monitortime = 30; +/* default message */ +static const char * lock_message = "locked."; + +/* text color */ +static const char * text_fg_color = "#fff"; +static const char * text_bg_color = "#f00"; + +/* text size (must be a valid size) */ +static const char * font_name = "fixed"; + /* treat a cleared input like a wrong password (color) */ static const int failonclear = 1; diff --git a/config.mk b/config.mk @@ -13,6 +13,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 \ + -lXinerama \ -lImlib2 \ diff --git a/slock.1 b/slock.1 @@ -6,6 +6,8 @@ .Sh SYNOPSIS .Nm .Op Fl v +.Op Fl f +.Op Fl m Ar message .Op Ar cmd Op Ar arg ... .Sh DESCRIPTION .Nm @@ -16,6 +18,11 @@ is executed after the screen has been locked. .Bl -tag -width Ds .It Fl v Print version information to stdout and exit. +.It Fl f +List all valid X fonts and exit. +.It Fl m Ar message +Overrides default slock lock message. +.TP .El .Sh SECURITY CONSIDERATIONS To make sure a locked screen can not be bypassed by switching VTs diff --git a/slock.c b/slock.c @@ -15,6 +15,7 @@ #include <unistd.h> #include <sys/types.h> #include <X11/extensions/Xrandr.h> +#include <X11/extensions/Xinerama.h> #include <X11/extensions/dpms.h> #include <X11/keysym.h> #include <X11/Xlib.h> @@ -26,6 +27,9 @@ char *argv0; +/* global count to prevent repeated error messages */ +int count_error = 0; + enum { INIT, INPUT, @@ -88,6 +92,106 @@ dontkillme(void) } #endif +static void +writemessage(Display *dpy, Window win, int screen, const char* message) +{ + int msg_len, max_line_len, max_line_width, xoffset, yoffset, screen_width, + screen_height, i, j, k, line_count, tab_replace, tab_size, font_height; + XGCValues gr_values; + XFontStruct *fontinfo; + XColor fg_color, bg_color, dummy; + XineramaScreenInfo *xsi; + GC fg_gc, bg_gc; + fontinfo = XLoadQueryFont(dpy, font_name); + + if (fontinfo == NULL) { + if (count_error == 0) { + fprintf(stderr, "slock: Unable to load font \"%s\"\n", font_name); + fprintf(stderr, "slock: Try listing fonts with 'slock -f'\n"); + count_error++; + } + return; + } + + tab_size = 4 * XTextWidth(fontinfo, " ", 1); + + XAllocNamedColor(dpy, DefaultColormap(dpy, screen), + text_fg_color, &fg_color, &dummy); + + gr_values.font = fontinfo->fid; + gr_values.foreground = fg_color.pixel; + fg_gc = XCreateGC(dpy, win, GCFont+GCForeground, &gr_values); + + XAllocNamedColor(dpy, DefaultColormap(dpy, screen), + text_bg_color, &bg_color, &dummy); + + gr_values.foreground = bg_color.pixel; + bg_gc = XCreateGC(dpy, win, GCFont+GCForeground, &gr_values); + + /* To prevent "Uninitialized" warnings. */ + xsi = NULL; + + msg_len = strlen(message); + + /* Calculate max line length, j : last line, k : longest line */ + max_line_len = 0; + line_count = 0; + for (i = j = k = 0; i <= msg_len; i++) { + if (i == msg_len || message[i] == '\n') { + if (i - j > max_line_len) { + max_line_len = i - j; + k = j; + } + line_count++; + j = i + 1; + } + } + + max_line_width = XTextWidth(fontinfo, message + k, max_line_len); + + if (XineramaIsActive(dpy)) { + xsi = XineramaQueryScreens(dpy, &i); + screen_width = xsi[0].width; + screen_height = xsi[0].height; + } else { + screen_width = DisplayWidth(dpy, screen); + screen_height = DisplayHeight(dpy, screen); + } + + font_height = fontinfo->ascent + fontinfo->descent; + yoffset = screen_height * 3 / 7 - line_count * font_height / 3; + xoffset = (screen_width - max_line_width) / 2; + + /* Draw background rect */ + XFillRectangle(dpy, win, bg_gc, xoffset - 1, yoffset - fontinfo->ascent, + max_line_width + 2, line_count * font_height); + + /* Print line by line, j : last line, k : line counter */ + for (i = j = k = 0; i <= msg_len; i++) { + if (i == msg_len || message[i] == '\n') { + tab_replace = 0; + while (message[j] == '\t' && j < i) { + tab_replace++; + j++; + } + + XDrawString(dpy, win, fg_gc, xoffset + tab_size * tab_replace, + yoffset + 20 * k, message + j, i - j); + while (i < msg_len && message[i] == '\n') { + i++; + j = i; + k++; + } + } + } + + /* xsi should not be NULL anyway if Xinerama is active, but to be safe */ + if (XineramaIsActive(dpy) && xsi != NULL) + XFree(xsi); +} + + + static const char * gethash(void) { @@ -194,13 +298,22 @@ readpw(Display *dpy, struct xrandr *rr, struct lock **locks, int nscreens, break; } color = len ? INPUT : ((failure || failonclear) ? FAILED : INIT); - if (running && oldc != color) { + if (running) { for (screen = 0; screen < nscreens; screen++) { 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); + if (len) { + char* passwd_mask = malloc(len + 1); + memset(passwd_mask, '*', len); + passwd_mask[len] = '\0'; + writemessage(dpy, locks[screen]->win, screen, passwd_mask); + free(passwd_mask); + } else { + writemessage(dpy, locks[screen]->win, screen, lock_message); + } } oldc = color; } @@ -320,7 +433,7 @@ lockscreen(Display *dpy, struct xrandr *rr, int screen) static void usage(void) { - die("usage: slock [-v] [cmd [arg ...]]\n"); + die("usage: slock [-v] [-f] [-m message] [cmd [arg ...]]\n"); } int @@ -333,13 +446,26 @@ main(int argc, char **argv) { gid_t dgid; const char *hash; Display *dpy; - int s, nlocks, nscreens; + int i, s, nlocks, nscreens; + int count_fonts; + char **font_names; CARD16 standby, suspend, off; ARGBEGIN { case 'v': fprintf(stderr, "slock-"VERSION"\n"); return 0; + case 'm': + lock_message = EARGF(usage()); + break; + case 'f': + if (!(dpy = XOpenDisplay(NULL))) + die("slock: cannot open display\n"); + font_names = XListFonts(dpy, "*", 10000 /* list 10000 fonts*/, &count_fonts); + for (i=0; i<count_fonts; i++) { + fprintf(stderr, "%s\n", *(font_names+i)); + } + return 0; default: usage(); } ARGEND @@ -438,10 +564,12 @@ main(int argc, char **argv) { if (!(locks = calloc(nscreens, sizeof(struct lock *)))) die("slock: out of memory\n"); for (nlocks = 0, s = 0; s < nscreens; s++) { - if ((locks[s] = lockscreen(dpy, &rr, s)) != NULL) + if ((locks[s] = lockscreen(dpy, &rr, s)) != NULL) { + writemessage(dpy, locks[s]->win, s, lock_message); nlocks++; - else + } else { break; + } } XSync(dpy, 0);