slock-colormessage-20200210-35633d4.diff (7273B)
1 From 53ba5a8d3608ca9c9c406b12c51c2bfdfb3e01d3 Mon Sep 17 00:00:00 2001 2 From: Guy Shefy <guyshefyb@gmail.com> 3 Date: Wed, 10 Feb 2021 00:17:46 +0200 4 Subject: [PATCH] Add a message command with 24 bit color support 5 6 --- 7 config.def.h | 9 +++ 8 config.mk | 2 +- 9 slock.1 | 7 +++ 10 slock.c | 154 +++++++++++++++++++++++++++++++++++++++++++++++++-- 11 4 files changed, 167 insertions(+), 5 deletions(-) 12 13 diff --git a/config.def.h b/config.def.h 14 index 9855e21..c2a0ab2 100644 15 --- a/config.def.h 16 +++ b/config.def.h 17 @@ -10,3 +10,12 @@ 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 +/* text size (must be a valid size) */ 29 +static const char * font_name = "6x10"; 30 diff --git a/config.mk b/config.mk 31 index 74429ae..c4ccf66 100644 32 --- a/config.mk 33 +++ b/config.mk 34 @@ -12,7 +12,7 @@ X11LIB = /usr/X11R6/lib 35 36 # includes and libs 37 INCS = -I. -I/usr/include -I${X11INC} 38 -LIBS = -L/usr/lib -lc -lcrypt -L${X11LIB} -lX11 -lXext -lXrandr 39 +LIBS = -L/usr/lib -lc -lcrypt -L${X11LIB} -lX11 -lXext -lXrandr -lXinerama 40 41 # flags 42 CPPFLAGS = -DVERSION=\"${VERSION}\" -D_DEFAULT_SOURCE -DHAVE_SHADOW_H 43 diff --git a/slock.1 b/slock.1 44 index 82cdcd6..946165f 100644 45 --- a/slock.1 46 +++ b/slock.1 47 @@ -6,6 +6,8 @@ 48 .Sh SYNOPSIS 49 .Nm 50 .Op Fl v 51 +.Op Fl f 52 +.Op Fl m Ar message 53 .Op Ar cmd Op Ar arg ... 54 .Sh DESCRIPTION 55 .Nm 56 @@ -16,6 +18,11 @@ is executed after the screen has been locked. 57 .Bl -tag -width Ds 58 .It Fl v 59 Print version information to stdout and exit. 60 +.It Fl f 61 +List all valid X fonts and exit. 62 +.It Fl m Ar message 63 +Overrides default slock lock message. 64 +.TP 65 .El 66 .Sh SECURITY CONSIDERATIONS 67 To make sure a locked screen can not be bypassed by switching VTs 68 diff --git a/slock.c b/slock.c 69 index 5ae738c..b8b7fe4 100644 70 --- a/slock.c 71 +++ b/slock.c 72 @@ -15,6 +15,7 @@ 73 #include <unistd.h> 74 #include <sys/types.h> 75 #include <X11/extensions/Xrandr.h> 76 +#include <X11/extensions/Xinerama.h> 77 #include <X11/keysym.h> 78 #include <X11/Xlib.h> 79 #include <X11/Xutil.h> 80 @@ -24,6 +25,9 @@ 81 82 char *argv0; 83 84 +/* global count to prevent repeated error messages */ 85 +int count_error = 0; 86 + 87 enum { 88 INIT, 89 INPUT, 90 @@ -83,6 +87,132 @@ dontkillme(void) 91 } 92 #endif 93 94 +static int 95 +readescapedint(const char *str, int *i) { 96 + int n = 0; 97 + if (str[*i]) 98 + ++*i; 99 + while(str[*i] && str[*i] != ';' && str[*i] != 'm') { 100 + n = 10 * n + str[*i] - '0'; 101 + ++*i; 102 + } 103 + return n; 104 +} 105 + 106 +static void 107 +writemessage(Display *dpy, Window win, int screen) 108 +{ 109 + int len, line_len, width, height, s_width, s_height, i, k, tab_size, r, g, b, escaped_int, curr_line_len; 110 + XGCValues gr_values; 111 + XFontStruct *fontinfo; 112 + XColor color, dummy; 113 + XineramaScreenInfo *xsi; 114 + GC gc; 115 + fontinfo = XLoadQueryFont(dpy, font_name); 116 + 117 + if (fontinfo == NULL) { 118 + if (count_error == 0) { 119 + fprintf(stderr, "slock: Unable to load font \"%s\"\n", font_name); 120 + fprintf(stderr, "slock: Try listing fonts with 'slock -f'\n"); 121 + count_error++; 122 + } 123 + return; 124 + } 125 + 126 + tab_size = 8 * XTextWidth(fontinfo, " ", 1); 127 + 128 + XAllocNamedColor(dpy, DefaultColormap(dpy, screen), 129 + text_color, &color, &dummy); 130 + 131 + gr_values.font = fontinfo->fid; 132 + gr_values.foreground = color.pixel; 133 + gc=XCreateGC(dpy,win,GCFont+GCForeground, &gr_values); 134 + 135 + /* To prevent "Uninitialized" warnings. */ 136 + xsi = NULL; 137 + 138 + /* 139 + * Start formatting and drawing text 140 + */ 141 + 142 + len = strlen(message); 143 + 144 + /* Max max line length (cut at '\n') */ 145 + line_len = curr_line_len = 0; 146 + k = 0; 147 + for (i = 0; i < len; i++) { 148 + if (message[i] == '\n') { 149 + curr_line_len = 0; 150 + k++; 151 + } else if (message[i] == 0x1b) { 152 + while (i < len && message[i] != 'm') { 153 + i++; 154 + } 155 + if (i == len) 156 + die("slock: unclosed escape sequence\n"); 157 + } else { 158 + curr_line_len += XTextWidth(fontinfo, message + i, 1); 159 + if (curr_line_len > line_len) 160 + line_len = curr_line_len; 161 + } 162 + } 163 + /* If there is only one line */ 164 + if (line_len == 0) 165 + line_len = len; 166 + 167 + if (XineramaIsActive(dpy)) { 168 + xsi = XineramaQueryScreens(dpy, &i); 169 + s_width = xsi[0].width; 170 + s_height = xsi[0].height; 171 + } else { 172 + s_width = DisplayWidth(dpy, screen); 173 + s_height = DisplayHeight(dpy, screen); 174 + } 175 + height = s_height*3/7 - (k*20)/3; 176 + width = (s_width - line_len)/2; 177 + 178 + line_len = 0; 179 + /* print the text while parsing 24 bit color ANSI escape codes*/ 180 + for (i = k = 0; i < len; i++) { 181 + switch (message[i]) { 182 + case '\n': 183 + line_len = 0; 184 + while (message[i + 1] == '\t') { 185 + line_len += tab_size; 186 + i++; 187 + } 188 + k++; 189 + break; 190 + case 0x1b: 191 + i++; 192 + if (message[i] == '[') { 193 + escaped_int = readescapedint(message, &i); 194 + if (escaped_int == 39) 195 + continue; 196 + if (escaped_int != 38) 197 + die("slock: unknown escape sequence%d\n", escaped_int); 198 + if (readescapedint(message, &i) != 2) 199 + die("slock: only 24 bit color supported\n"); 200 + r = readescapedint(message, &i) & 0xff; 201 + g = readescapedint(message, &i) & 0xff; 202 + b = readescapedint(message, &i) & 0xff; 203 + XSetForeground(dpy, gc, r << 16 | g << 8 | b); 204 + } else 205 + die("slock: unknown escape sequence\n"); 206 + break; 207 + default: 208 + XDrawString(dpy, win, gc, width + line_len, height + 20 * k, message + i, 1); 209 + line_len += XTextWidth(fontinfo, message + i, 1); 210 + } 211 + } 212 + 213 + /* xsi should not be NULL anyway if Xinerama is active, but to be safe */ 214 + if (XineramaIsActive(dpy) && xsi != NULL) 215 + XFree(xsi); 216 +} 217 + 218 + 219 + 220 static const char * 221 gethash(void) 222 { 223 @@ -194,6 +324,7 @@ readpw(Display *dpy, struct xrandr *rr, struct lock **locks, int nscreens, 224 locks[screen]->win, 225 locks[screen]->colors[color]); 226 XClearWindow(dpy, locks[screen]->win); 227 + writemessage(dpy, locks[screen]->win, screen); 228 } 229 oldc = color; 230 } 231 @@ -300,7 +431,7 @@ lockscreen(Display *dpy, struct xrandr *rr, int screen) 232 static void 233 usage(void) 234 { 235 - die("usage: slock [-v] [cmd [arg ...]]\n"); 236 + die("usage: slock [-v] [-f] [-m message] [cmd [arg ...]]\n"); 237 } 238 239 int 240 @@ -313,12 +444,25 @@ main(int argc, char **argv) { 241 gid_t dgid; 242 const char *hash; 243 Display *dpy; 244 - int s, nlocks, nscreens; 245 + int i, s, nlocks, nscreens; 246 + int count_fonts; 247 + char **font_names; 248 249 ARGBEGIN { 250 case 'v': 251 fprintf(stderr, "slock-"VERSION"\n"); 252 return 0; 253 + case 'm': 254 + message = EARGF(usage()); 255 + break; 256 + case 'f': 257 + if (!(dpy = XOpenDisplay(NULL))) 258 + die("slock: cannot open display\n"); 259 + font_names = XListFonts(dpy, "*", 10000 /* list 10000 fonts*/, &count_fonts); 260 + for (i=0; i<count_fonts; i++) { 261 + fprintf(stderr, "%s\n", *(font_names+i)); 262 + } 263 + return 0; 264 default: 265 usage(); 266 } ARGEND 267 @@ -363,10 +507,12 @@ main(int argc, char **argv) { 268 if (!(locks = calloc(nscreens, sizeof(struct lock *)))) 269 die("slock: out of memory\n"); 270 for (nlocks = 0, s = 0; s < nscreens; s++) { 271 - if ((locks[s] = lockscreen(dpy, &rr, s)) != NULL) 272 + if ((locks[s] = lockscreen(dpy, &rr, s)) != NULL) { 273 + writemessage(dpy, locks[s]->win, s); 274 nlocks++; 275 - else 276 + } else { 277 break; 278 + } 279 } 280 XSync(dpy, 0); 281 282 -- 283 2.30.0 284