+ XFreeColors(dpy, DefaultColormap(dpy, lock->screen), lock->colors, NUMCOLS, 0);
+ XFreePixmap(dpy, lock->pmap);
+ XDestroyWindow(dpy, lock->win);
+
+ free(lock);
+}
+
+static Lock *
+lockscreen(Display *dpy, int screen)
+{
+ char curs[] = {0, 0, 0, 0, 0, 0, 0, 0};
+ unsigned int len;
+ int i;
+ Lock *lock;
+ XColor color, dummy;
+ XSetWindowAttributes wa;
+ Cursor invisible;
+
+ if (!running || dpy == NULL || screen < 0 || !(lock = malloc(sizeof(Lock))))
+ return NULL;
+
+ lock->screen = screen;
+ lock->root = RootWindow(dpy, lock->screen);
+
+ for (i = 0; i < NUMCOLS; i++) {
+ XAllocNamedColor(dpy, DefaultColormap(dpy, lock->screen), colorname[i], &color, &dummy);
+ lock->colors[i] = color.pixel;
+ }
+
+ /* init */
+ wa.override_redirect = 1;
+ wa.background_pixel = lock->colors[INIT];
+ lock->win = XCreateWindow(dpy, lock->root, 0, 0, DisplayWidth(dpy, lock->screen), DisplayHeight(dpy, lock->screen),
+ 0, DefaultDepth(dpy, lock->screen), CopyFromParent,
+ DefaultVisual(dpy, lock->screen), CWOverrideRedirect | CWBackPixel, &wa);
+ lock->pmap = XCreateBitmapFromData(dpy, lock->win, curs, 8, 8);
+ invisible = XCreatePixmapCursor(dpy, lock->pmap, lock->pmap, &color, &color, 0, 0);
+ XDefineCursor(dpy, lock->win, invisible);
+ XMapRaised(dpy, lock->win);
+ if (rr)
+ XRRSelectInput(dpy, lock->win, RRScreenChangeNotifyMask);
+
+ /* Try to grab mouse pointer *and* keyboard, else fail the lock */
+ for (len = 1000; len; len--) {
+ if (XGrabPointer(dpy, lock->root, False, ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
+ GrabModeAsync, GrabModeAsync, None, invisible, CurrentTime) == GrabSuccess)
+ break;
+ usleep(1000);
+ }
+ if (!len) {
+ fprintf(stderr, "slock: unable to grab mouse pointer for screen %d\n", screen);
+ } else {
+ for (len = 1000; len; len--) {
+ if (XGrabKeyboard(dpy, lock->root, True, GrabModeAsync, GrabModeAsync, CurrentTime) == GrabSuccess) {
+ /* everything fine, we grabbed both inputs */
+ XSelectInput(dpy, lock->root, SubstructureNotifyMask);
+ return lock;
+ }
+ usleep(1000);
+ }
+ fprintf(stderr, "slock: unable to grab keyboard for screen %d\n", screen);
+ }
+ /* grabbing one of the inputs failed */
+ running = 0;
+ unlockscreen(dpy, lock);
+ return NULL;
+}
+
+int
+main(int argc, char **argv)
+{
+#ifndef HAVE_BSD_AUTH
+ const char *pws;
+#endif
+ Display *dpy;
+ int screen;
+
+#ifdef __linux__
+ dontkillme();
+#endif
+
+ if (!getpwuid(getuid()))
+ die("slock: no passwd entry for you\n");
+
+#ifndef HAVE_BSD_AUTH
+ pws = getpw();
+#endif
+
+ if (!(dpy = XOpenDisplay(0)))
+ die("slock: cannot open display\n");
+ rr = XRRQueryExtension(dpy, &rrevbase, &rrerrbase);
+ /* Get the number of screens in display "dpy" and blank them all. */
+ nscreens = ScreenCount(dpy);
+ if (!(locks = malloc(sizeof(Lock*) * nscreens)))
+ die("slock: malloc: %s\n", strerror(errno));
+ int nlocks = 0;
+ for (screen = 0; screen < nscreens; screen++) {
+ if ((locks[screen] = lockscreen(dpy, screen)) != NULL)
+ nlocks++;
+ }
+ XSync(dpy, False);
+
+ /* Did we actually manage to lock something? */
+ if (nlocks == 0) { /* nothing to protect */
+ free(locks);
+ XCloseDisplay(dpy);
+ return 1;
+ }
+
+ if (argc >= 2 && fork() == 0) {
+ if (dpy)
+ close(ConnectionNumber(dpy));
+ execvp(argv[1], argv+1);
+ die("slock: execvp %s failed: %s\n", argv[1], strerror(errno));
+ }
+
+ /* Everything is now blank. Now wait for the correct password. */
+#ifdef HAVE_BSD_AUTH
+ readpw(dpy);
+#else
+ readpw(dpy, pws);
+#endif
+
+ /* Password ok, unlock everything and quit. */
+ for (screen = 0; screen < nscreens; screen++)
+ unlockscreen(dpy, locks[screen]);
+
+ free(locks);