Re-introduce the waiting loop for input grabbing
authorQuentin Rameau <quinq@fifth.space>
Thu, 1 Sep 2016 11:46:51 +0000 (13:46 +0200)
committerMarkus Teich <markus.teich@stusta.mhn.de>
Fri, 2 Sep 2016 08:50:32 +0000 (10:50 +0200)
We actually “need” to wait a little for input to be released before
locking for cases where slock is spawned from other graphical
applications using keybindings.
This undoes the misbehaviour I introduced in c2f9757, sorry for the mess.

slock.c

diff --git a/slock.c b/slock.c
index 4980325..97c7489 100644 (file)
--- a/slock.c
+++ b/slock.c
@@ -223,6 +223,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);
@@ -241,7 +242,7 @@ 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;
@@ -268,30 +269,45 @@ 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 = 6, ptgrab = kbgrab = -1; i; --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;
 
-       XSelectInput(dpy, lock->root, SubstructureNotifyMask);
-       return lock;
+               usleep(100000);
+       }
+
+       /* 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);
+       running = 0;
+       unlockscreen(dpy, lock);
+       return NULL;
 }
 
 static void