X-Git-Url: https://git.danieliu.xyz/?a=blobdiff_plain;f=slock.c;h=62a9841b4b49516b89a7ca0be75c50088d818d49;hb=9698224090ff2989659717815bfa076d5d436a70;hp=4980325f9fd9df80528cb256e6cf4aa6459a8a2c;hpb=1f66885fbf36c726b7615060d3c98cbf74218d13;p=slock.git diff --git a/slock.c b/slock.c index 4980325..62a9841 100644 --- a/slock.c +++ b/slock.c @@ -46,8 +46,6 @@ typedef struct { static Lock **locks; static int nscreens; -static Bool running = True; -static Bool failure = False; static Bool rr; static int rrevbase; static int rrerrbase; @@ -101,9 +99,9 @@ getpw(void) errno = 0; if (!(pw = getpwuid(getuid()))) { if (errno) - die("getpwuid: %s\n", strerror(errno)); + die("slock: getpwuid: %s\n", strerror(errno)); else - die("cannot retrieve password entry\n"); + die("slock: cannot retrieve password entry\n"); } rval = pw->pw_passwd; @@ -111,7 +109,7 @@ getpw(void) if (rval[0] == 'x' && rval[1] == '\0') { struct spwd *sp; if (!(sp = getspnam(getenv("USER")))) - die("cannot retrieve shadow entry (make sure to suid or sgid slock)\n"); + die("slock: cannot retrieve shadow entry (make sure to suid or sgid slock)\n"); rval = sp->sp_pwdp; } #endif @@ -119,7 +117,7 @@ getpw(void) /* drop privileges */ if (geteuid() == 0 && ((getegid() != pw->pw_gid && setgid(pw->pw_gid) < 0) || setuid(pw->pw_uid) < 0)) - die("cannot drop privileges\n"); + die("slock: cannot drop privileges\n"); return rval; } #endif @@ -132,14 +130,15 @@ readpw(Display *dpy, const char *pws) #endif { char buf[32], passwd[256], *encrypted; - int num, screen; + int num, screen, running, failure; unsigned int len, color; KeySym ksym; XEvent ev; static int oldc = INIT; len = 0; - running = True; + running = 1; + failure = 0; /* As "slock" stands for "Simple X display locker", the DPMS settings * had been removed and you can set it with "xset" or some other @@ -223,6 +222,7 @@ unlockscreen(Display *dpy, Lock *lock) return; XUngrabPointer(dpy, CurrentTime); + XUngrabKeyboard(dpy, CurrentTime); XFreeColors(dpy, DefaultColormap(dpy, lock->screen), lock->colors, NUMCOLS, 0); XFreePixmap(dpy, lock->pmap); XDestroyWindow(dpy, lock->win); @@ -233,6 +233,11 @@ unlockscreen(Display *dpy, Lock *lock) static void cleanup(Display *dpy) { + int s; + + for (s = 0; s < nscreens; ++s) + unlockscreen(dpy, locks[s]); + free(locks); XCloseDisplay(dpy); } @@ -241,13 +246,13 @@ static Lock * lockscreen(Display *dpy, int screen) { char curs[] = {0, 0, 0, 0, 0, 0, 0, 0}; - int i; + int i, ptgrab, kbgrab; Lock *lock; XColor color, dummy; XSetWindowAttributes wa; Cursor invisible; - if (!running || dpy == NULL || screen < 0 || !(lock = malloc(sizeof(Lock)))) + if (dpy == NULL || screen < 0 || !(lock = malloc(sizeof(Lock)))) return NULL; lock->screen = screen; @@ -268,30 +273,43 @@ lockscreen(Display *dpy, int screen) invisible = XCreatePixmapCursor(dpy, lock->pmap, lock->pmap, &color, &color, 0, 0); XDefineCursor(dpy, lock->win, invisible); - /* Try to grab mouse pointer *and* keyboard, else fail the lock */ - if (XGrabPointer(dpy, lock->root, False, ButtonPressMask | - ButtonReleaseMask | PointerMotionMask, GrabModeAsync, GrabModeAsync, - None, invisible, CurrentTime) != GrabSuccess) { - fprintf(stderr, "slock: unable to grab mouse pointer for screen %d\n", screen); - running = 0; - unlockscreen(dpy, lock); - return NULL; - } + /* Try to grab mouse pointer *and* keyboard for 600ms, else fail the lock */ + for (i = 0, ptgrab = kbgrab = -1; i < 6; i++) { + if (ptgrab != GrabSuccess) { + ptgrab = XGrabPointer(dpy, lock->root, False, + ButtonPressMask | ButtonReleaseMask | + PointerMotionMask, GrabModeAsync, + GrabModeAsync, None, invisible, CurrentTime); + } + if (kbgrab != GrabSuccess) { + kbgrab = XGrabKeyboard(dpy, lock->root, True, + GrabModeAsync, GrabModeAsync, CurrentTime); + } - if (XGrabKeyboard(dpy, lock->root, True, GrabModeAsync, GrabModeAsync, - CurrentTime) != GrabSuccess) { - fprintf(stderr, "slock: unable to grab keyboard for screen %d\n", screen); - running = 0; - unlockscreen(dpy, lock); - return NULL; - } + /* input is grabbed: we can lock the screen */ + if (ptgrab == GrabSuccess && kbgrab == GrabSuccess) { + XMapRaised(dpy, lock->win); + if (rr) + XRRSelectInput(dpy, lock->win, RRScreenChangeNotifyMask); + + XSelectInput(dpy, lock->root, SubstructureNotifyMask); + return lock; + } - XMapRaised(dpy, lock->win); - if (rr) - XRRSelectInput(dpy, lock->win, RRScreenChangeNotifyMask); + /* retry on AlreadyGrabbed but fail on other errors */ + if ((ptgrab != AlreadyGrabbed && ptgrab != GrabSuccess) || + (kbgrab != AlreadyGrabbed && kbgrab != GrabSuccess)) + break; + + usleep(100000); + } - XSelectInput(dpy, lock->root, SubstructureNotifyMask); - return lock; + /* we couldn't grab all input: fail out */ + if (ptgrab != GrabSuccess) + fprintf(stderr, "slock: unable to grab mouse pointer for screen %d\n", screen); + if (kbgrab != GrabSuccess) + fprintf(stderr, "slock: unable to grab keyboard for screen %d\n", screen); + return NULL; } static void @@ -343,19 +361,20 @@ main(int argc, char **argv) { /* get number of screens in display "dpy" and blank them */ nscreens = ScreenCount(dpy); - if (!(locks = malloc(sizeof(Lock *) * nscreens))) { + if (!(locks = calloc(nscreens, sizeof(Lock *)))) { XCloseDisplay(dpy); die("slock: out of memory\n"); } for (nlocks = 0, s = 0; s < nscreens; s++) { if ((locks[s] = lockscreen(dpy, s)) != NULL) nlocks++; + else + break; } XSync(dpy, 0); - /* did we actually manage to lock anything? */ - if (nlocks == 0) { - /* nothing to protect */ + /* did we manage to lock everything? */ + if (nlocks != nscreens) { cleanup(dpy); return 1; } @@ -384,9 +403,6 @@ main(int argc, char **argv) { #endif /* password ok, unlock everything and quit */ - for (s = 0; s < nscreens; s++) - unlockscreen(dpy, locks[s]); - cleanup(dpy); return 0;