sites

public wiki contents of suckless.org
git clone git://git.suckless.org/sites
Log | Files | Refs

slock-message-xft-20261008-65cb721.diff (7898B)


      1 From ae7e6d53035be99c24b514cbb26005d37656d632 Mon Sep 17 00:00:00 2001
      2 From: Sourav Nayak <nonameblank007@gmail.com>
      3 Date: Thu, 8 Oct 2026 00:36:01 +0530
      4 Subject: [PATCH] slock: update message patch for upcoming 1.8 version and support system fonts
      5 
      6 ---
      7  config.def.h |  12 ++++
      8  config.mk    |   8 ++-
      9  slock.1      |   7 +++
     10  slock.c      | 156 +++++++++++++++++++++++++++++++++++++++++++++++++--
     11  4 files changed, 177 insertions(+), 6 deletions(-)
     12 
     13 diff --git a/config.def.h b/config.def.h
     14 index 9855e21..d18e03f 100644
     15 --- a/config.def.h
     16 +++ b/config.def.h
     17 @@ -10,3 +10,15 @@ static const char *colorname[NUMCOLS] = {
     18  
     19  /* treat a cleared input like a wrong password (color) */
     20  static const int failonclear = 1;
     21 +
     22 +/* default message */
     23 +static const char * message = "Suckless: Software that sucks less.";
     24 +
     25 +/* text color */
     26 +static const char * text_color = "#ffffff";
     27 +
     28 +/* font name (slock -f/fc-list) */
     29 +static const char * font_name = "monospace";
     30 +
     31 +/* font size (must be a valid size) */
     32 +static const double font_size = 18.0;
     33 \ No newline at end of file
     34 diff --git a/config.mk b/config.mk
     35 index 9fe5bff..921834e 100644
     36 --- a/config.mk
     37 +++ b/config.mk
     38 @@ -10,9 +10,13 @@ MANPREFIX = ${PREFIX}/share/man
     39  X11INC = /usr/X11R6/include
     40  X11LIB = /usr/X11R6/lib
     41  
     42 +# freetype
     43 +FREETYPELIBS = -lfontconfig -lXft
     44 +FREETYPEINC = /usr/include/freetype2
     45 +
     46  # includes and libs
     47 -INCS = -I. -I/usr/include -I${X11INC}
     48 -LIBS = -L/usr/lib -lc -lcrypt -L${X11LIB} -lX11 -lXext -lXrandr
     49 +INCS = -I. -I/usr/include -I${X11INC} -I${FREETYPEINC}
     50 +LIBS = -L/usr/lib -lc -lcrypt -L${X11LIB} ${FREETYPELIBS} -lX11 -lXext -lXrandr -lXinerama
     51  
     52  # flags
     53  CPPFLAGS = -DVERSION=\"${VERSION}\" -D_DEFAULT_SOURCE -DHAVE_SHADOW_H
     54 diff --git a/slock.1 b/slock.1
     55 index e485992..66a5f97 100644
     56 --- a/slock.1
     57 +++ b/slock.1
     58 @@ -7,6 +7,8 @@
     59  .Sh SYNOPSIS
     60  .Nm
     61  .Op Fl v
     62 +.Op Fl f
     63 +.Op Fl m
     64  .Sh DESCRIPTION
     65  .Nm
     66  is a simple X screen locker.
     67 @@ -14,6 +16,11 @@ The options are as follows:
     68  .Bl -tag -width Ds
     69  .It Fl v
     70  Print version information to stdout and exit.
     71 +.It Fl f
     72 +List all valid X fonts and exit.
     73 +.It Fl m
     74 +Overrides default slock lock message.
     75 +.TP
     76  .El
     77  .Sh EXIT STATUS
     78  .Ex -std
     79 diff --git a/slock.c b/slock.c
     80 index 9c587e1..fe6ef5d 100644
     81 --- a/slock.c
     82 +++ b/slock.c
     83 @@ -15,14 +15,20 @@
     84  #include <unistd.h>
     85  #include <sys/types.h>
     86  #include <X11/extensions/Xrandr.h>
     87 +#include <X11/extensions/Xinerama.h>
     88  #include <X11/keysym.h>
     89  #include <X11/Xlib.h>
     90  #include <X11/Xutil.h>
     91 +#include <X11/Xft/Xft.h>
     92 +#include <fontconfig/fontconfig.h>
     93  
     94  #include "util.h"
     95  
     96  char *argv0;
     97  
     98 +/* global count to prevent repeated error messages */
     99 +int count_error = 0;
    100 +
    101  enum {
    102  	INIT,
    103  	INPUT,
    104 @@ -82,6 +88,122 @@ dontkillme(void)
    105  }
    106  #endif
    107  
    108 +static void
    109 +writemessage(Display *dpy, Window win, int screen)
    110 +{
    111 +	int len, line_len, line_start, width, height, s_width, s_height, i, j, k, tab_replace, tab_size;
    112 +	XineramaScreenInfo *xsi = NULL;
    113 +	XftFont *font = NULL;
    114 +	XftDraw *draw;
    115 +	XftColor color;
    116 +	Visual *vis;
    117 +	Colormap cmap;
    118 +	XGlyphInfo ext;
    119 +	char font_pattern[256];
    120 +
    121 +	snprintf(font_pattern, sizeof(font_pattern), "%s:size=%f:antialias=true:autohint=true",
    122 +	         font_name, font_size);
    123 +
    124 +	font = XftFontOpenName(dpy, screen, font_pattern);
    125 +	if (!font)
    126 +		font = XftFontOpenName(dpy, screen, "monospace:size=12");
    127 +
    128 +	if (!font) {
    129 +		if (count_error == 0) {
    130 +			fprintf(stderr, "slock: Unable to load font \"%s\"\n", font_pattern);
    131 +			fprintf(stderr, "slock: Try listing fonts with 'slock -f'\n");
    132 +			count_error++;
    133 +		}
    134 +		return;
    135 +	}
    136 +
    137 +	vis = DefaultVisual(dpy, screen);
    138 +	cmap = DefaultColormap(dpy, screen);
    139 +
    140 +	if (!XftColorAllocName(dpy, vis, cmap, text_color, &color)) {
    141 +		fprintf(stderr, "slock: Unable to allocate color \"%s\"\n", text_color);
    142 +		XftFontClose(dpy, font);
    143 +		return;
    144 +	}
    145 +
    146 +	draw = XftDrawCreate(dpy, win, vis, cmap);
    147 +	if (!draw) {
    148 +		XftColorFree(dpy, vis, cmap, &color);
    149 +		XftFontClose(dpy, font);
    150 +		return;
    151 +	}
    152 +
    153 +	XftTextExtentsUtf8(dpy, font, (FcChar8 *)" ", 1, &ext);
    154 +	tab_size = 8 * (ext.xOff > 0 ? ext.xOff : 8);
    155 +
    156 +	len = strlen(message);
    157 +
    158 +	/* Max max line length (cut at '\n') */
    159 +	line_len = 0;
    160 +	line_start = 0;
    161 +	k = 0;
    162 +	for (i = j = 0; i < len; i++) {
    163 +		if (message[i] == '\n') {
    164 +			if (i - j > line_len) {
    165 +				line_len = i - j;
    166 +				line_start = j;
    167 +			}
    168 +			k++;
    169 +			i++;
    170 +			j = i;
    171 +		}
    172 +	}
    173 +	if (line_len == 0) {
    174 +		line_len = len;
    175 +		line_start = 0;
    176 +	}
    177 +
    178 +	if (XineramaIsActive(dpy)) {
    179 +		xsi = XineramaQueryScreens(dpy, &i);
    180 +		s_width = xsi[0].width;
    181 +		s_height = xsi[0].height;
    182 +	} else {
    183 +		s_width = DisplayWidth(dpy, screen);
    184 +		s_height = DisplayHeight(dpy, screen);
    185 +	}
    186 +
    187 +	XftTextExtentsUtf8(dpy, font, (FcChar8 *)(message + line_start), line_len, &ext);
    188 +	int line_spacing = font->ascent + font->descent + 6;
    189 +	height = s_height * 3 / 7 - (k * line_spacing) / 3;
    190 +	width  = (s_width - ext.xOff) / 2;
    191 +
    192 +	/* Look for '\n' and print the text between them. */
    193 +	for (i = j = k = 0; i <= len; i++) {
    194 +		/* i == len is the special case for the last line */
    195 +		if (i == len || message[i] == '\n') {
    196 +			tab_replace = 0;
    197 +			while (message[j] == '\t' && j < i) {
    198 +				tab_replace++;
    199 +				j++;
    200 +			}
    201 +
    202 +			XftDrawStringUtf8(draw, &color, font,
    203 +			                  width + tab_size * tab_replace,
    204 +			                  height + (k * line_spacing) + font->ascent,
    205 +			                  (FcChar8 *)(message + j), i - j);
    206 +
    207 +			while (i < len && message[i] == '\n') {
    208 +				i++;
    209 +				j = i;
    210 +				k++;
    211 +			}
    212 +		}
    213 +	}
    214 +
    215 +	/* xsi should not be NULL anyway if Xinerama is active, but to be safe */
    216 +	if (XineramaIsActive(dpy) && xsi != NULL)
    217 +			XFree(xsi);
    218 +
    219 +	XftDrawDestroy(draw);
    220 +	XftColorFree(dpy, vis, cmap, &color);
    221 +	XftFontClose(dpy, font);
    222 +}
    223 +
    224  static const char *
    225  gethash(void)
    226  {
    227 @@ -196,6 +318,7 @@ readpw(Display *dpy, struct xrandr *rr, struct lock **locks, int nscreens,
    228  					                     locks[screen]->win,
    229  					                     locks[screen]->colors[color]);
    230  					XClearWindow(dpy, locks[screen]->win);
    231 +					writemessage(dpy, locks[screen]->win, screen);
    232  				}
    233  				oldc = color;
    234  			}
    235 @@ -302,7 +425,7 @@ lockscreen(Display *dpy, struct xrandr *rr, int screen)
    236  static void
    237  usage(void)
    238  {
    239 -	die("usage: slock [-v]\n");
    240 +	die("usage: slock [-v] [-f] [-m message]\n");
    241  }
    242  
    243  int
    244 @@ -315,11 +438,30 @@ main(int argc, char **argv) {
    245  	gid_t dgid;
    246  	const char *hash;
    247  	Display *dpy;
    248 -	int s, nlocks, nscreens;
    249 +	int i, s, nlocks, nscreens;
    250 +	FcFontSet *fs;
    251 +	FcPattern *pat;
    252 +	FcObjectSet *os;
    253  
    254  	if (argc > 1 && !strcmp(argv[1], "-v")) {
    255  		puts("slock-"VERSION);
    256  		return 0;
    257 +	} else if (argc > 1 && !strcmp(argv[1], "-m")) {
    258 +		if (argc < 3)
    259 +			usage();
    260 +		message = argv[2];
    261 +	} else if (argc > 1 && !strcmp(argv[1], "-f")) {
    262 +		if (!FcInit())
    263 +			die("slock: Fontconfig initialization failed\n");
    264 +		pat = FcPatternCreate();
    265 +		os = FcObjectSetBuild(FC_FAMILY, NULL);
    266 +		fs = FcFontList(NULL, pat, os);
    267 +		for (i = 0; fs && i < fs->nfont; i++) {
    268 +			FcChar8 *fam;
    269 +			if (FcPatternGetString(fs->fonts[i], FC_FAMILY, 0, &fam) == FcResultMatch)
    270 +				printf("%s\n", fam);
    271 +		}
    272 +		return 0;
    273  	} else if (argc > 1) {
    274  		usage();
    275  	}
    276 @@ -345,6 +487,10 @@ main(int argc, char **argv) {
    277  	if (!crypt("", hash))
    278  		die("slock: crypt: %s\n", strerror(errno));
    279  
    280 +	/* Initialize Fontconfig cache BEFORE dropping privileges */
    281 +	if (!FcInit())
    282 +		die("slock: Fontconfig initialization failed\n");
    283 +
    284  	if (!(dpy = XOpenDisplay(NULL)))
    285  		die("slock: cannot open display\n");
    286  
    287 @@ -364,10 +510,12 @@ main(int argc, char **argv) {
    288  	if (!(locks = calloc(nscreens, sizeof(struct lock *))))
    289  		die("slock: out of memory\n");
    290  	for (nlocks = 0, s = 0; s < nscreens; s++) {
    291 -		if ((locks[s] = lockscreen(dpy, &rr, s)) != NULL)
    292 +		if ((locks[s] = lockscreen(dpy, &rr, s)) != NULL) {
    293 +			writemessage(dpy, locks[s]->win, s);
    294  			nlocks++;
    295 -		else
    296 +		} else {
    297  			break;
    298 +		}
    299  	}
    300  	XSync(dpy, 0);
    301  
    302 -- 
    303 2.55.0
    304