]> git.sur5r.net Git - i3/i3lock/blobdiff - xcb.c
Measure wall-clock time instead of CPU time for “locking” indicator. (#153)
[i3/i3lock] / xcb.c
diff --git a/xcb.c b/xcb.c
index 3e8cd071c455954b1189fed6e4392ce3338f7140..c38440414766b4f8b6b9d19166329ffae2bc0dc5 100644 (file)
--- a/xcb.c
+++ b/xcb.c
 #include <unistd.h>
 #include <assert.h>
 #include <err.h>
+#include <time.h>
+#include <sys/time.h>
 
 #include "cursors.h"
+#include "unlock_indicator.h"
+
+extern auth_state_t auth_state;
 
 xcb_connection_t *conn;
 xcb_screen_t *screen;
@@ -158,7 +163,7 @@ xcb_window_t open_fullscreen_window(xcb_connection_t *conn, xcb_screen_t *scr, c
 }
 
 /*
- * Repeatedly tries to grab pointer and keyboard (up to 1000 times).
+ * Repeatedly tries to grab pointer and keyboard (up to 10000 times).
  *
  */
 void grab_pointer_and_keyboard(xcb_connection_t *conn, xcb_screen_t *screen, xcb_cursor_t cursor) {
@@ -168,8 +173,16 @@ void grab_pointer_and_keyboard(xcb_connection_t *conn, xcb_screen_t *screen, xcb
     xcb_grab_keyboard_cookie_t kcookie;
     xcb_grab_keyboard_reply_t *kreply;
 
+    const suseconds_t screen_redraw_timeout = 100000; /* 100ms */
     int tries = 10000;
 
+    /* Using few variables to trigger a redraw_screen() if too many tries */
+    bool redrawn = false;
+    struct timeval start;
+    if (gettimeofday(&start, NULL) == -1) {
+        err(EXIT_FAILURE, "gettimeofday");
+    }
+
     while (tries-- > 0) {
         pcookie = xcb_grab_pointer(
             conn,
@@ -190,6 +203,21 @@ void grab_pointer_and_keyboard(xcb_connection_t *conn, xcb_screen_t *screen, xcb
 
         /* Make this quite a bit slower */
         usleep(50);
+
+        struct timeval now;
+        if (gettimeofday(&now, NULL) == -1) {
+            err(EXIT_FAILURE, "gettimeofday");
+        }
+
+        struct timeval elapsed;
+        timersub(&now, &start, &elapsed);
+
+        if (!redrawn &&
+            (tries % 100) == 0 &&
+            elapsed.tv_usec >= screen_redraw_timeout) {
+            redraw_screen();
+            redrawn = true;
+        }
     }
 
     while (tries-- > 0) {
@@ -209,10 +237,32 @@ void grab_pointer_and_keyboard(xcb_connection_t *conn, xcb_screen_t *screen, xcb
 
         /* Make this quite a bit slower */
         usleep(50);
+
+        struct timeval now;
+        if (gettimeofday(&now, NULL) == -1) {
+            err(EXIT_FAILURE, "gettimeofday");
+        }
+
+        struct timeval elapsed;
+        timersub(&now, &start, &elapsed);
+
+        /* Trigger a screen redraw if 100ms elapsed */
+        if (!redrawn &&
+            (tries % 100) == 0 &&
+            elapsed.tv_usec >= screen_redraw_timeout) {
+            redraw_screen();
+            redrawn = true;
+        }
     }
 
-    if (tries <= 0)
+    /* After trying for 10000 times, i3lock will display an error message
+     * for 2 sec prior to terminate. */
+    if (tries <= 0) {
+        auth_state = STATE_I3LOCK_LOCK_FAILED;
+        redraw_screen();
+        sleep(1);
         errx(EXIT_FAILURE, "Cannot grab pointer/keyboard");
+    }
 }
 
 xcb_cursor_t create_cursor(xcb_connection_t *conn, xcb_screen_t *screen, xcb_window_t win, int choice) {