├── LICENSE ├── Makefile ├── README.md ├── arg.h ├── config.def.h ├── config.mk ├── screenshot.png ├── slock.1 ├── slock.c ├── stackblur.c ├── stackblur.h └── util.h /LICENSE: -------------------------------------------------------------------------------- 1 | MIT/X Consortium License 2 | 3 | © 2014 Dimitris Papastamos 4 | © 2006-2014 Anselm R Garbe 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a 7 | copy of this software and associated documentation files (the "Software"), 8 | to deal in the Software without restriction, including without limitation 9 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 | and/or sell copies of the Software, and to permit persons to whom the 11 | Software is furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 | DEALINGS IN THE SOFTWARE. 23 | 24 | 25 | ------------------------------------------------------ 26 | 27 | 28 | THE STACK-BLUR PART OF THE CODE IS BASED ON GREATE WORK BY: 29 | Mario Klingemann 30 | Link to the original work: 31 | http://incubator.quasimondo.com/processing/fast_blur_deluxe.php 32 | The original source code of stack-blur: 33 | http://incubator.quasimondo.com/processing/stackblur.pde 34 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # slock - simple screen locker 2 | # See LICENSE file for copyright and license details. 3 | 4 | include config.mk 5 | 6 | SRC = slock.c stackblur.c ${COMPATSRC} 7 | OBJ = ${SRC:.c=.o} 8 | 9 | all: options slock 10 | 11 | options: 12 | @echo slock build options: 13 | @echo "CFLAGS = ${CFLAGS}" 14 | @echo "LDFLAGS = ${LDFLAGS}" 15 | @echo "CC = ${CC}" 16 | 17 | .c.o: 18 | @echo CC $< 19 | @${CC} -c ${CFLAGS} $< 20 | 21 | ${OBJ}: config.h config.mk arg.h util.h 22 | 23 | config.h: 24 | @echo creating $@ from config.def.h 25 | @cp config.def.h $@ 26 | 27 | slock: ${OBJ} 28 | @echo CC -o $@ 29 | @${CC} -pthread -o $@ ${OBJ} ${LDFLAGS} 30 | 31 | clean: 32 | @echo cleaning 33 | @rm -f slock ${OBJ} slock-blur-${VERSION}.tar.gz 34 | 35 | dist: clean 36 | @echo creating dist tarball 37 | @mkdir -p slock-blur-${VERSION} 38 | @cp -R LICENSE Makefile README slock.1 config.mk \ 39 | ${SRC} explicit_bzero.c config.def.h arg.h util.h slock-blur-${VERSION} 40 | @tar -cf slock-blur-${VERSION}.tar slock-blur-${VERSION} 41 | @gzip slock-blur-${VERSION}.tar 42 | @rm -rf slock-blur-${VERSION} 43 | 44 | install: all 45 | @echo installing executable file to ${DESTDIR}${PREFIX}/bin 46 | @mkdir -p ${DESTDIR}${PREFIX}/bin 47 | @cp -f slock ${DESTDIR}${PREFIX}/bin 48 | @chmod 755 ${DESTDIR}${PREFIX}/bin/slock 49 | @chmod u+s ${DESTDIR}${PREFIX}/bin/slock 50 | @echo installing manual page to ${DESTDIR}${MANPREFIX}/man1 51 | @mkdir -p ${DESTDIR}${MANPREFIX}/man1 52 | @sed "s/VERSION/${VERSION}/g" ${DESTDIR}${MANPREFIX}/man1/slock.1 53 | @chmod 644 ${DESTDIR}${MANPREFIX}/man1/slock.1 54 | 55 | uninstall: 56 | @echo removing executable file from ${DESTDIR}${PREFIX}/bin 57 | @rm -f ${DESTDIR}${PREFIX}/bin/slock 58 | @echo removing manual page from ${DESTDIR}${MANPREFIX}/man1 59 | @rm -f ${DESTDIR}${MANPREFIX}/man1/slock.1 60 | 61 | .PHONY: all options clean dist install uninstall 62 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | slock-blur - simple screen locker 2 | ============================ 3 | Super fast and highly stable blur version of the simple screen locker 4 | utility for X. It takes a screenshot of your desktop and blurs it and 5 | remain there until you enter your password. 6 | 7 | ![Screenshot](screenshot.png?raw=true "Fully CPU Based No OpenGL Static Blur Effect") 8 | 9 | Debian Patches 10 | -------------- 11 | Applied Debian Sid patches to support PAM instead of using Shadow. 12 | More information at: 13 | https://packages.debian.org/source/sid/suckless-tools 14 | All patches applied: 15 | - slock-Fix-resize-with-multiple-monitors-and-portrait-mode.patch 16 | - Use-PAM-for-authentication.patch 17 | - slock-there-can-only-be-one-window-in-the-event.patch 18 | - Don-t-exit-if-failed-to-adjust-OOM-score.patch 19 | - Remove-custom-library-search-paths-from-Makefiles.patch 20 | - slock-Properly-clear-the-last-entered-character.patch 21 | - slock-Do-not-drop-privileges.patch 22 | Also added man file from debian package. 23 | 24 | Requirements 25 | ------------ 26 | In order to build slock you need the Xlib header files. 27 | 28 | DO NOT PANIC! 29 | ------------ 30 | - This blur effect does not crash 31 | - This blur effect does not need OpenGL 32 | - This blur effect only relies on Xlib and your CPU for rendering 33 | - This blur effect is multi-threaded (It takes less that 30ms for bluring 34 | whole desktop of a 10inch Intel Atom Laptop) 35 | 36 | Installation 37 | ------------ 38 | Edit config.mk to match your local setup (slock is installed into 39 | the /usr/local namespace by default). 40 | 41 | Afterwards enter the following command to build and install slock 42 | (if necessary as root): 43 | 44 | make clean install 45 | 46 | 47 | Running slock 48 | ------------- 49 | Simply invoke the 'slock' command. To get out of it, enter your password. 50 | . 51 | 52 | ## THE STACK-BLUR PART OF THE CODE IS BASED ON GREATE WORK BY: 53 | Mario Klingemann 54 | 55 | Link to the original work: 56 | - http://incubator.quasimondo.com/processing/fast_blur_deluxe.php 57 | 58 | The original source code of stack-blur: 59 | - http://incubator.quasimondo.com/processing/stackblur.pde 60 | -------------------------------------------------------------------------------- /arg.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copy me if you can. 3 | * by 20h 4 | */ 5 | 6 | #ifndef ARG_H__ 7 | #define ARG_H__ 8 | 9 | extern char *argv0; 10 | 11 | /* use main(int argc, char *argv[]) */ 12 | #define ARGBEGIN for (argv0 = *argv, argv++, argc--;\ 13 | argv[0] && argv[0][0] == '-'\ 14 | && argv[0][1];\ 15 | argc--, argv++) {\ 16 | char argc_;\ 17 | char **argv_;\ 18 | int brk_;\ 19 | if (argv[0][1] == '-' && argv[0][2] == '\0') {\ 20 | argv++;\ 21 | argc--;\ 22 | break;\ 23 | }\ 24 | for (brk_ = 0, argv[0]++, argv_ = argv;\ 25 | argv[0][0] && !brk_;\ 26 | argv[0]++) {\ 27 | if (argv_ != argv)\ 28 | break;\ 29 | argc_ = argv[0][0];\ 30 | switch (argc_) 31 | 32 | /* Handles obsolete -NUM syntax */ 33 | #define ARGNUM case '0':\ 34 | case '1':\ 35 | case '2':\ 36 | case '3':\ 37 | case '4':\ 38 | case '5':\ 39 | case '6':\ 40 | case '7':\ 41 | case '8':\ 42 | case '9' 43 | 44 | #define ARGEND }\ 45 | } 46 | 47 | #define ARGC() argc_ 48 | 49 | #define ARGNUMF() (brk_ = 1, estrtonum(argv[0], 0, INT_MAX)) 50 | 51 | #define EARGF(x) ((argv[0][1] == '\0' && argv[1] == NULL)?\ 52 | ((x), abort(), (char *)0) :\ 53 | (brk_ = 1, (argv[0][1] != '\0')?\ 54 | (&argv[0][1]) :\ 55 | (argc--, argv++, argv[0]))) 56 | 57 | #define ARGF() ((argv[0][1] == '\0' && argv[1] == NULL)?\ 58 | (char *)0 :\ 59 | (brk_ = 1, (argv[0][1] != '\0')?\ 60 | (&argv[0][1]) :\ 61 | (argc--, argv++, argv[0]))) 62 | 63 | #define LNGARG() &argv[0][0] 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /config.def.h: -------------------------------------------------------------------------------- 1 | /* user and group to drop privileges to */ 2 | static const char *user = "nobody"; 3 | static const char *group = "nogroup"; 4 | 5 | static const int blurlevel[NUMLEVELS] = { 6 | 45, /* after initialization */ 7 | 30, /* during input */ 8 | 60, /* failed/cleared the input */ 9 | }; 10 | static const Bool failonclear = False; 11 | 12 | //Used for multi-threaded blur effect 13 | #define CPU_THREADS 4 14 | -------------------------------------------------------------------------------- /config.mk: -------------------------------------------------------------------------------- 1 | # slock version 2 | VERSION = 1.2 3 | 4 | # Customize below to fit your system 5 | 6 | # paths 7 | PREFIX = /usr/local 8 | 9 | X11INC = /usr/X11R6/include 10 | X11LIB = /usr/X11R6/lib 11 | 12 | # includes and libs 13 | INCS = -I. -I/usr/include -I${X11INC} 14 | LIBS = -L/usr/lib -lc -lpam -L${X11LIB} -lX11 -lXext -lXrandr 15 | 16 | # flags 17 | CPPFLAGS = -DVERSION=\"${VERSION}\" -DHAVE_PAM 18 | CFLAGS = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS} 19 | LDFLAGS = -s ${LIBS} 20 | 21 | # On *BSD remove -DHAVE_SHADOW_H from CPPFLAGS and add -DHAVE_BSD_AUTH 22 | # On OpenBSD and Darwin remove -lcrypt from LIBS 23 | 24 | # compiler and linker 25 | CC = cc 26 | 27 | # Install mode. On BSD systems MODE=2755 and GROUP=auth 28 | # On others MODE=4755 and GROUP=root 29 | #MODE=2755 30 | #GROUP=auth 31 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aario/slock-blur/c70d3e9c8e01dae2f30ac2c0d379cac6e09e1a54/screenshot.png -------------------------------------------------------------------------------- /slock.1: -------------------------------------------------------------------------------- 1 | .Dd 2016-08-23 2 | .Dt SLOCK 1 3 | .Sh NAME 4 | .Nm slock 5 | .Nd simple X screen locker 6 | .Sh SYNOPSIS 7 | .Nm 8 | .Op Fl v 9 | .Op Ar cmd Op Ar arg ... 10 | .Sh DESCRIPTION 11 | .Nm 12 | is a simple X screen locker. If provided, 13 | .Ar cmd Op Ar arg ... 14 | is executed after the screen has been locked. 15 | .Sh OPTIONS 16 | .Bl -tag -width Ds 17 | .It Fl v 18 | Print version information to stdout and exit. 19 | .El 20 | .Sh SECURITY CONSIDERATIONS 21 | To make sure a locked screen can not be bypassed by switching VTs 22 | or killing the X server with Ctrl+Alt+Backspace, it is recommended 23 | to disable both in 24 | .Xr xorg.conf 5 25 | for maximum security: 26 | .Bd -literal -offset left 27 | Section "ServerFlags" 28 | Option "DontVTSwitch" "True" 29 | Option "DontZap" "True" 30 | EndSection 31 | .Ed 32 | .Sh EXAMPLES 33 | $ 34 | .Nm 35 | /usr/sbin/s2ram 36 | .Sh CUSTOMIZATION 37 | .Nm 38 | can be customized by creating a custom config.h from config.def.h and 39 | (re)compiling the source code. This keeps it fast, secure and simple. 40 | -------------------------------------------------------------------------------- /slock.c: -------------------------------------------------------------------------------- 1 | /* See LICENSE file for license details. */ 2 | #define _XOPEN_SOURCE 500 3 | #if HAVE_SHADOW_H 4 | #include 5 | #endif 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include "stackblur.h" 22 | 23 | #include "arg.h" 24 | #include "util.h" 25 | 26 | char *argv0; 27 | 28 | #ifdef HAVE_PAM 29 | #include 30 | #define PAM_SERVICE_NAME "slock" 31 | 32 | static const char *pam_passwd; 33 | static pam_handle_t *pamh = NULL; 34 | 35 | static void pam_init(void); 36 | static void pam_destroy(void); 37 | static int pam_auth(const char *passwd); 38 | #endif 39 | 40 | enum { 41 | INIT, 42 | INPUT, 43 | FAILED, 44 | NUMLEVELS 45 | }; 46 | 47 | struct lock { 48 | int screen; 49 | Window root, win; 50 | Pixmap pmap; 51 | unsigned long colors[NUMLEVELS]; 52 | XImage *image, *originalimage; 53 | }; 54 | 55 | struct xrandr { 56 | int active; 57 | int evbase; 58 | int errbase; 59 | }; 60 | 61 | #include "config.h" 62 | 63 | static void 64 | blurlockwindow(Display *dpy, struct lock *lock, int radius) 65 | { 66 | XWindowAttributes gwa; 67 | XGetWindowAttributes(dpy, lock->root, &gwa); 68 | if (lock->image != NULL) { 69 | free(lock->image); 70 | free(lock->image->data); 71 | } 72 | lock->image=malloc(sizeof(XImage)); 73 | memcpy(lock->image,lock->originalimage,sizeof(XImage)); 74 | unsigned long bytes2copy=sizeof(char)*lock->originalimage->bytes_per_line*lock->originalimage->height; 75 | lock->image->data=malloc(bytes2copy); 76 | memcpy(lock->image->data,lock->originalimage->data,bytes2copy); 77 | stackblur(lock->image,0,0,lock->image->width,lock->image->height,radius, CPU_THREADS); 78 | XMapRaised(dpy, lock->win); 79 | GC gc = XCreateGC (dpy, lock->win, 0, 0); 80 | XPutImage(dpy, lock->win, gc, lock->image, 0, 0, 0, 0, gwa.width, gwa.height); 81 | XFlush(dpy); 82 | } 83 | 84 | static void 85 | die(const char *errstr, ...) 86 | { 87 | va_list ap; 88 | 89 | va_start(ap, errstr); 90 | vfprintf(stderr, errstr, ap); 91 | va_end(ap); 92 | exit(1); 93 | } 94 | 95 | #ifdef __linux__ 96 | #include 97 | #include 98 | 99 | static void 100 | dontkillme(void) 101 | { 102 | FILE *f; 103 | const char oomfile[] = "/proc/self/oom_score_adj"; 104 | 105 | if (!(f = fopen(oomfile, "w"))) { 106 | if (errno == ENOENT) 107 | return; 108 | fprintf(stderr, "cannot disable the out-of-memory" 109 | " killer for this process\n"); 110 | return; 111 | } 112 | fprintf(f, "%d", OOM_SCORE_ADJ_MIN); 113 | if (fclose(f)) { 114 | if (errno == EACCES) 115 | fprintf(stderr, "cannot disable the out-of-memory" 116 | " killer for this process\n"); 117 | else 118 | fprintf(stderr, "cannot disable the out-of-memory" 119 | " killer for this process\n"); 120 | } 121 | } 122 | #endif 123 | 124 | static const char * 125 | gethash(void) 126 | { 127 | const char *hash; 128 | struct passwd *pw; 129 | 130 | /* Check if the current user has a password entry */ 131 | errno = 0; 132 | if (!(pw = getpwuid(getuid()))) { 133 | if (errno) 134 | die("slock: getpwuid: %s\n", strerror(errno)); 135 | else 136 | die("slock: cannot retrieve password entry\n"); 137 | } 138 | hash = pw->pw_passwd; 139 | 140 | #if HAVE_SHADOW_H 141 | if (!strcmp(hash, "x")) { 142 | struct spwd *sp; 143 | if (!(sp = getspnam(pw->pw_name))) 144 | die("slock: getspnam: cannot retrieve shadow entry. " 145 | "Make sure to suid or sgid slock.\n"); 146 | hash = sp->sp_pwdp; 147 | } 148 | #else 149 | if (!strcmp(hash, "*")) { 150 | #ifdef __OpenBSD__ 151 | if (!(pw = getpwuid_shadow(getuid()))) 152 | die("slock: getpwnam_shadow: cannot retrieve shadow entry. " 153 | "Make sure to suid or sgid slock.\n"); 154 | hash = pw->pw_passwd; 155 | #else 156 | die("slock: getpwuid: cannot retrieve shadow entry. " 157 | "Make sure to suid or sgid slock.\n"); 158 | #endif /* __OpenBSD__ */ 159 | } 160 | #endif /* HAVE_SHADOW_H */ 161 | 162 | return hash; 163 | } 164 | 165 | static void 166 | readpw(Display *dpy, struct xrandr *rr, struct lock **locks, int nscreens, 167 | const char *hash) 168 | { 169 | XRRScreenChangeNotifyEvent *rre; 170 | char buf[32], passwd[256], *inputhash; 171 | int num, screen, running, failure, oldc; 172 | unsigned int len, level; 173 | KeySym ksym; 174 | XEvent ev; 175 | static int oldl = INIT; 176 | 177 | len = 0; 178 | running = 1; 179 | failure = 0; 180 | oldc = INIT; 181 | 182 | while (running && !XNextEvent(dpy, &ev)) { 183 | if (ev.type == KeyPress) { 184 | explicit_bzero(&buf, sizeof(buf)); 185 | num = XLookupString(&ev.xkey, buf, sizeof(buf), &ksym, 0); 186 | if (IsKeypadKey(ksym)) { 187 | if (ksym == XK_KP_Enter) 188 | ksym = XK_Return; 189 | else if (ksym >= XK_KP_0 && ksym <= XK_KP_9) 190 | ksym = (ksym - XK_KP_0) + XK_0; 191 | } 192 | if (IsFunctionKey(ksym) || 193 | IsKeypadKey(ksym) || 194 | IsMiscFunctionKey(ksym) || 195 | IsPFKey(ksym) || 196 | IsPrivateKeypadKey(ksym)) 197 | continue; 198 | switch (ksym) { 199 | case XK_Return: 200 | passwd[len] = '\0'; 201 | errno = 0; 202 | #ifdef HAVE_PAM 203 | running = !!pam_auth(passwd); 204 | #else 205 | if (!(inputhash = crypt(passwd, hash))) 206 | fprintf(stderr, "slock: crypt: %s\n", strerror(errno)); 207 | else 208 | running = !!strcmp(inputhash, hash); 209 | #endif 210 | if (running) { 211 | XBell(dpy, 100); 212 | failure = 1; 213 | } 214 | explicit_bzero(&passwd, sizeof(passwd)); 215 | len = 0; 216 | break; 217 | case XK_Escape: 218 | explicit_bzero(&passwd, sizeof(passwd)); 219 | len = 0; 220 | break; 221 | case XK_BackSpace: 222 | if (len) 223 | passwd[--len] = '\0'; 224 | break; 225 | default: 226 | if (num && !iscntrl((int)buf[0]) && 227 | (len + num < sizeof(passwd))) { 228 | memcpy(passwd + len, buf, num); 229 | len += num; 230 | } 231 | break; 232 | } 233 | level = len ? INPUT : ((failure || failonclear) ? FAILED : INIT); 234 | if (running && oldc != level) { 235 | for (screen = 0; screen < nscreens; screen++) 236 | blurlockwindow(dpy,locks[screen],blurlevel[level]); 237 | oldl = level; 238 | } 239 | } else if (rr->active && ev.type == rr->evbase + RRScreenChangeNotify) { 240 | rre = (XRRScreenChangeNotifyEvent*)&ev; 241 | for (screen = 0; screen < nscreens; screen++) { 242 | if (locks[screen]->win == rre->window) { 243 | if (rre->rotation == RR_Rotate_90 || 244 | rre->rotation == RR_Rotate_270) 245 | XResizeWindow(dpy, locks[screen]->win, 246 | rre->height, rre->width); 247 | else 248 | XResizeWindow(dpy, locks[screen]->win, 249 | rre->width, rre->height); 250 | blurlockwindow(dpy,locks[screen],blurlevel[INIT]); 251 | break; 252 | } 253 | } 254 | } else for (screen = 0; screen < nscreens; screen++) 255 | XRaiseWindow(dpy, locks[screen]->win); 256 | } 257 | } 258 | 259 | static struct lock * 260 | lockscreen(Display *dpy, struct xrandr *rr, int screen) 261 | { 262 | char curs[] = {0, 0, 0, 0, 0, 0, 0, 0}; 263 | int i, ptgrab, kbgrab; 264 | struct lock *lock; 265 | XColor color; 266 | XSetWindowAttributes wa; 267 | Cursor invisible; 268 | 269 | if (dpy == NULL || screen < 0 || !(lock = malloc(sizeof(struct lock)))) 270 | return NULL; 271 | 272 | lock->screen = screen; 273 | lock->root = RootWindow(dpy, lock->screen); 274 | 275 | /* init */ 276 | wa.override_redirect = 1; 277 | wa.background_pixel = lock->colors[INIT]; 278 | lock->win = XCreateWindow(dpy, lock->root, 0, 0, 279 | DisplayWidth(dpy, lock->screen), 280 | DisplayHeight(dpy, lock->screen), 281 | 0, DefaultDepth(dpy, lock->screen), 282 | CopyFromParent, 283 | DefaultVisual(dpy, lock->screen), 284 | CWOverrideRedirect | CWBackPixel, &wa); 285 | lock->pmap = XCreateBitmapFromData(dpy, lock->win, curs, 8, 8); 286 | invisible = XCreatePixmapCursor(dpy, lock->pmap, lock->pmap, 287 | &color, &color, 0, 0); 288 | XDefineCursor(dpy, lock->win, invisible); 289 | XWindowAttributes gwa; 290 | XGetWindowAttributes(dpy, lock->root, &gwa); 291 | lock->originalimage=XGetImage(dpy,lock->root, 0, 0, gwa.width, gwa.height, AllPlanes, ZPixmap); 292 | lock->image=NULL; 293 | blurlockwindow(dpy,lock,blurlevel[INIT]); 294 | 295 | /* Try to grab mouse pointer *and* keyboard for 600ms, else fail the lock */ 296 | for (i = 0, ptgrab = kbgrab = -1; i < 6; i++) { 297 | if (ptgrab != GrabSuccess) { 298 | ptgrab = XGrabPointer(dpy, lock->root, False, 299 | ButtonPressMask | ButtonReleaseMask | 300 | PointerMotionMask, GrabModeAsync, 301 | GrabModeAsync, None, invisible, CurrentTime); 302 | } 303 | if (kbgrab != GrabSuccess) { 304 | kbgrab = XGrabKeyboard(dpy, lock->root, True, 305 | GrabModeAsync, GrabModeAsync, CurrentTime); 306 | } 307 | 308 | /* input is grabbed: we can lock the screen */ 309 | if (ptgrab == GrabSuccess && kbgrab == GrabSuccess) { 310 | XMapRaised(dpy, lock->win); 311 | if (rr->active) 312 | XRRSelectInput(dpy, lock->win, RRScreenChangeNotifyMask); 313 | 314 | XSelectInput(dpy, lock->root, SubstructureNotifyMask); 315 | return lock; 316 | } 317 | 318 | /* retry on AlreadyGrabbed but fail on other errors */ 319 | if ((ptgrab != AlreadyGrabbed && ptgrab != GrabSuccess) || 320 | (kbgrab != AlreadyGrabbed && kbgrab != GrabSuccess)) 321 | break; 322 | 323 | usleep(100000); 324 | } 325 | 326 | /* we couldn't grab all input: fail out */ 327 | if (ptgrab != GrabSuccess) 328 | fprintf(stderr, "slock: unable to grab mouse pointer for screen %d\n", 329 | screen); 330 | if (kbgrab != GrabSuccess) 331 | fprintf(stderr, "slock: unable to grab keyboard for screen %d\n", 332 | screen); 333 | return NULL; 334 | } 335 | 336 | static void 337 | usage(void) 338 | { 339 | die("usage: slock [-v] [cmd [arg ...]]\n"); 340 | } 341 | 342 | int 343 | main(int argc, char **argv) { 344 | struct xrandr rr; 345 | struct lock **locks; 346 | const char *hash; 347 | Display *dpy; 348 | int s, nlocks, nscreens; 349 | 350 | ARGBEGIN { 351 | case 'v': 352 | fprintf(stderr, "slock-"VERSION"\n"); 353 | return 0; 354 | default: 355 | usage(); 356 | } ARGEND 357 | 358 | 359 | #ifdef __linux__ 360 | dontkillme(); 361 | #endif 362 | 363 | #ifdef HAVE_PAM 364 | pam_init(); 365 | #else 366 | hash = gethash(); 367 | errno = 0; 368 | if (!crypt("", hash)) 369 | die("slock: crypt: %s\n", strerror(errno)); 370 | #endif 371 | 372 | if (!(dpy = XOpenDisplay(NULL))) 373 | die("slock: cannot open display\n"); 374 | 375 | 376 | /* check for Xrandr support */ 377 | rr.active = XRRQueryExtension(dpy, &rr.evbase, &rr.errbase); 378 | 379 | /* get number of screens in display "dpy" and blank them */ 380 | nscreens = ScreenCount(dpy); 381 | if (!(locks = calloc(nscreens, sizeof(struct lock *)))) 382 | die("slock: out of memory\n"); 383 | for (nlocks = 0, s = 0; s < nscreens; s++) { 384 | if ((locks[s] = lockscreen(dpy, &rr, s)) != NULL) 385 | nlocks++; 386 | else 387 | break; 388 | } 389 | XSync(dpy, 0); 390 | 391 | /* did we manage to lock everything? */ 392 | if (nlocks != nscreens) 393 | return 1; 394 | 395 | /* run post-lock command */ 396 | if (argc > 0) { 397 | switch (fork()) { 398 | case -1: 399 | die("slock: fork failed: %s\n", strerror(errno)); 400 | case 0: 401 | if (close(ConnectionNumber(dpy)) < 0) 402 | die("slock: close: %s\n", strerror(errno)); 403 | execvp(argv[0], argv); 404 | fprintf(stderr, "slock: execvp %s: %s\n", argv[0], strerror(errno)); 405 | _exit(1); 406 | } 407 | } 408 | 409 | /* everything is now blank. Wait for the correct password */ 410 | readpw(dpy, &rr, locks, nscreens, hash); 411 | 412 | #ifdef HAVE_PAM 413 | pam_destroy(); 414 | #endif 415 | 416 | return 0; 417 | } 418 | 419 | 420 | #ifdef HAVE_PAM 421 | static int pam_conv(int num_msg, const struct pam_message **msg, 422 | struct pam_response **resp, void *appdata_ptr) 423 | { 424 | int i; 425 | 426 | *resp = calloc(num_msg, sizeof(**resp)); 427 | if (*resp == NULL) 428 | return PAM_BUF_ERR; 429 | 430 | for (i = 0; i < num_msg; i++) { 431 | /* return code is currently not used but should be set to zero */ 432 | resp[i]->resp_retcode = 0; 433 | 434 | if (msg[i]->msg_style == PAM_PROMPT_ECHO_OFF || 435 | msg[i]->msg_style == PAM_PROMPT_ECHO_ON) 436 | resp[i]->resp = strdup(pam_passwd); 437 | } 438 | 439 | return PAM_SUCCESS; 440 | } 441 | 442 | static int pam_auth(const char *passwd) 443 | { 444 | int pamret; 445 | 446 | /* Authenticate user */ 447 | pam_passwd = passwd; 448 | pamret = pam_authenticate(pamh, 0); 449 | 450 | /* Check account status */ 451 | if (pamret == PAM_SUCCESS) 452 | pamret = pam_acct_mgmt(pamh, 0); 453 | 454 | return (pamret == PAM_SUCCESS) ? 0 : 1; 455 | } 456 | 457 | static void pam_init(void) 458 | { 459 | int pamret; 460 | struct passwd *pw; 461 | struct pam_conv conv = {pam_conv, NULL}; 462 | 463 | pw = getpwuid(getuid()); 464 | if (!pw) { 465 | if (errno) 466 | die("slock: getpwuid: %s\n", strerror(errno)); 467 | else 468 | die("slock: cannot retrieve username for user ID %d" 469 | " from password file entry\n", getuid()); 470 | } 471 | 472 | /* Start PAM */ 473 | pamret = pam_start(PAM_SERVICE_NAME, pw->pw_name, &conv, &pamh); 474 | if (pamret != PAM_SUCCESS) 475 | die("slock: pam_start() failed"); 476 | } 477 | 478 | static void pam_destroy(void) 479 | { 480 | /* Close PAM handle */ 481 | pam_end(pamh, PAM_SUCCESS); 482 | } 483 | #endif 484 | -------------------------------------------------------------------------------- /stackblur.c: -------------------------------------------------------------------------------- 1 | #include "stackblur.h" 2 | #include 3 | 4 | void *HStackRenderingThread(void *arg) { 5 | StackBlurRenderingParams *rp=(StackBlurRenderingParams*)arg; 6 | int rinsum,ginsum,binsum,routsum,goutsum,boutsum,rsum,gsum,bsum,x,y,i,yi,yw,rbs,p,sp; 7 | int div=rp->radius+rp->radius+1; 8 | int *stackr=malloc(div*sizeof(int)); 9 | int *stackg=malloc(div*sizeof(int)); 10 | int *stackb=malloc(div*sizeof(int)); 11 | yw=yi=rp->y*rp->w; 12 | int r1=rp->radius+1; 13 | for (y=rp->y;yy2;y++){ 14 | rinsum=ginsum=binsum=routsum=goutsum=boutsum=rsum=gsum=bsum=0; 15 | for(i=-rp->radius;i<=rp->radius;i++){ 16 | p=(yi+MIN(rp->wm,MAX(i,0)))*4; 17 | sp=i+rp->radius; 18 | stackr[sp]=rp->pix[p]; 19 | stackg[sp]=rp->pix[p+1]; 20 | stackb[sp]=rp->pix[p+2]; 21 | rbs=r1-abs(i); 22 | rsum+=stackr[sp]*rbs; 23 | gsum+=stackg[sp]*rbs; 24 | bsum+=stackb[sp]*rbs; 25 | if (i>0){ 26 | rinsum+=stackr[sp]; 27 | ginsum+=stackg[sp]; 28 | binsum+=stackb[sp]; 29 | } else { 30 | routsum+=stackr[sp]; 31 | goutsum+=stackg[sp]; 32 | boutsum+=stackb[sp]; 33 | } 34 | } 35 | int stackpointer; 36 | int stackstart; 37 | stackpointer=rp->radius; 38 | 39 | for (x=rp->x;xw;x++){ 40 | rp->r[yi]=rp->dv[rsum]; 41 | rp->g[yi]=rp->dv[gsum]; 42 | rp->b[yi]=rp->dv[bsum]; 43 | 44 | rsum-=routsum; 45 | gsum-=goutsum; 46 | bsum-=boutsum; 47 | 48 | stackstart=stackpointer-rp->radius+div; 49 | sp=stackstart%div; 50 | 51 | routsum-=stackr[sp]; 52 | goutsum-=stackg[sp]; 53 | boutsum-=stackb[sp]; 54 | 55 | p=(yw+rp->vminx[x])*4; 56 | stackr[sp]=rp->pix[p]; 57 | stackg[sp]=rp->pix[p+1]; 58 | stackb[sp]=rp->pix[p+2]; 59 | 60 | rinsum+=stackr[sp]; 61 | ginsum+=stackg[sp]; 62 | binsum+=stackb[sp]; 63 | 64 | rsum+=rinsum; 65 | gsum+=ginsum; 66 | bsum+=binsum; 67 | 68 | stackpointer=(stackpointer+1)%div; 69 | sp=stackpointer%div; 70 | 71 | routsum+=stackr[sp]; 72 | goutsum+=stackg[sp]; 73 | boutsum+=stackb[sp]; 74 | 75 | rinsum-=stackr[sp]; 76 | ginsum-=stackg[sp]; 77 | binsum-=stackb[sp]; 78 | 79 | yi++; 80 | } 81 | yw+=rp->w; 82 | } 83 | free(stackr); 84 | free(stackg); 85 | free(stackb); 86 | stackr=stackg=stackb=NULL; 87 | pthread_exit(NULL); 88 | } 89 | 90 | void *VStackRenderingThread(void *arg) { 91 | StackBlurRenderingParams *rp=(StackBlurRenderingParams*)arg; 92 | int rinsum,ginsum,binsum,routsum,goutsum,boutsum,rsum,gsum,bsum,x,y,i,yi,yp,rbs,p,sp; 93 | int div=rp->radius+rp->radius+1; 94 | int divsum=(div+1)>>1; 95 | divsum*=divsum; 96 | int *stackr=malloc(div*sizeof(int)); 97 | int *stackg=malloc(div*sizeof(int)); 98 | int *stackb=malloc(div*sizeof(int)); 99 | int r1=rp->radius+1; 100 | int hm=rp->H-rp->y-1; 101 | for (x=rp->x;xw;x++) { 102 | rinsum=ginsum=binsum=routsum=goutsum=boutsum=rsum=gsum=bsum=0; 103 | yp=(rp->y-rp->radius)*rp->w; 104 | for(i=-rp->radius;i<=rp->radius;i++) { 105 | yi=MAX(0,yp)+x; 106 | sp=i+rp->radius; 107 | 108 | stackr[sp]=rp->r[yi]; 109 | stackg[sp]=rp->g[yi]; 110 | stackb[sp]=rp->b[yi]; 111 | 112 | rbs=r1-abs(i); 113 | 114 | rsum+=rp->r[yi]*rbs; 115 | gsum+=rp->g[yi]*rbs; 116 | bsum+=rp->b[yi]*rbs; 117 | 118 | if (i>0){ 119 | rinsum+=stackr[sp]; 120 | ginsum+=stackg[sp]; 121 | binsum+=stackb[sp]; 122 | } else { 123 | routsum+=stackr[sp]; 124 | goutsum+=stackg[sp]; 125 | boutsum+=stackb[sp]; 126 | } 127 | 128 | if(iw; 130 | } 131 | } 132 | yi=rp->y*rp->w+x; 133 | int stackpointer; 134 | int stackstart; 135 | stackpointer=rp->radius; 136 | 137 | for (y=rp->y;yy2;y++) { 138 | p=yi*4; 139 | #ifdef DEBUG 140 | // fprintf(stdout,"y: %i %i %i 1\n",rp->y, x, y); 141 | #endif 142 | rp->pix[p]=(unsigned char)(rp->dv[rsum]); 143 | rp->pix[p+1]=(unsigned char)(rp->dv[gsum]); 144 | rp->pix[p+2]=(unsigned char)(rp->dv[bsum]); 145 | rp->pix[p+3]=0xff; 146 | #ifdef DEBUG 147 | // fprintf(stdout,"y: %i 2\n",rp->y); 148 | #endif 149 | 150 | rsum-=routsum; 151 | gsum-=goutsum; 152 | bsum-=boutsum; 153 | 154 | stackstart=stackpointer-rp->radius+div; 155 | sp=stackstart%div; 156 | 157 | routsum-=stackr[sp]; 158 | goutsum-=stackg[sp]; 159 | boutsum-=stackb[sp]; 160 | 161 | p=x+rp->vminy[y]; 162 | stackr[sp]=rp->r[p]; 163 | stackg[sp]=rp->g[p]; 164 | stackb[sp]=rp->b[p]; 165 | 166 | rinsum+=stackr[sp]; 167 | ginsum+=stackg[sp]; 168 | binsum+=stackb[sp]; 169 | 170 | rsum+=rinsum; 171 | gsum+=ginsum; 172 | bsum+=binsum; 173 | 174 | stackpointer=(stackpointer+1)%div; 175 | 176 | routsum+=stackr[stackpointer]; 177 | goutsum+=stackg[stackpointer]; 178 | boutsum+=stackb[stackpointer]; 179 | 180 | rinsum-=stackr[stackpointer]; 181 | ginsum-=stackg[stackpointer]; 182 | binsum-=stackb[stackpointer]; 183 | 184 | yi+=rp->w; 185 | } 186 | } 187 | free(stackr); 188 | free(stackg); 189 | free(stackb); 190 | stackr=stackg=stackb=NULL; 191 | pthread_exit(NULL); 192 | } 193 | 194 | void stackblur(XImage *image,int x, int y,int w,int h,int radius, unsigned int num_threads) { 195 | if (radius<1) 196 | return; 197 | char *pix=image->data; 198 | int wh=w*h; 199 | int *r=malloc(wh*sizeof(int)); 200 | int *g=malloc(wh*sizeof(int)); 201 | int *b=malloc(wh*sizeof(int)); 202 | int i; 203 | 204 | int div=radius+radius+1; 205 | int divsum=(div+1)>>1; 206 | divsum*=divsum; 207 | int *dv=malloc(256*divsum*sizeof(int)); 208 | for (i=0;i<256*divsum;i++) { 209 | dv[i]=(i/divsum); 210 | } 211 | int *vminx=malloc(w*sizeof(int)); 212 | for (i=0;i 5 | 6 | // One of my first steps with Processing. I am a fan 7 | // of blurring. Especially as you can use blurred images 8 | // as a base for other effects. So this is something I 9 | // might get back to in later experiments. 10 | // 11 | // What you see is an attempt to implement a Gaussian Blur algorithm 12 | // which is exact but fast. I think that this one should be 13 | // relatively fast because it uses a special trick by first 14 | // making a horizontal blur on the original image and afterwards 15 | // making a vertical blur on the pre-processed image-> This 16 | // is a mathematical correct thing to do and reduces the 17 | // calculation a lot. 18 | // 19 | // In order to avoid the overhead of function calls I unrolled 20 | // the whole convolution routine in one method. This may not 21 | // look nice, but brings a huge performance boost. 22 | // 23 | // 24 | // v1.1: I replaced some multiplications by additions 25 | // and added aome minor pre-caclulations. 26 | // Also add correct rounding for float->int conversion 27 | // 28 | // v1.2: I completely got rid of all floating point calculations 29 | // and speeded up the whole process by using a 30 | // precalculated multiplication table. Unfortunately 31 | // a precalculated division table was becoming too 32 | // huge. But maybe there is some way to even speed 33 | // up the divisions. 34 | // 35 | // v1.3: Fixed a bug that caused blurs that start at y>0 36 | // to go wrong. Thanks to Jeroen Schellekens for 37 | // finding it! 38 | 39 | #include 40 | #include 41 | 42 | typedef struct { 43 | unsigned char *pix; 44 | int x; 45 | int y; 46 | int w; 47 | int y2; 48 | int H; 49 | int wm; 50 | int wh; 51 | int *r; 52 | int *g; 53 | int *b; 54 | int *dv; 55 | int radius; 56 | int *vminx; 57 | int *vminy; 58 | } StackBlurRenderingParams; 59 | 60 | #include 61 | 62 | #define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) 63 | #define MAX(X, Y) (((X) > (Y)) ? (X) : (Y)) 64 | 65 | void *HStackRenderingThread(void *arg); 66 | 67 | void *VStackRenderingThread(void *arg); 68 | 69 | void stackblur(XImage *image,int x, int y,int w,int h,int radius, unsigned int num_threads); 70 | 71 | 72 | -------------------------------------------------------------------------------- /util.h: -------------------------------------------------------------------------------- 1 | #undef explicit_bzero 2 | void explicit_bzero(void *, size_t); 3 | --------------------------------------------------------------------------------