]> git.sur5r.net Git - i3/i3lock/blobdiff - i3lock.c
Displaying locking message when grabbing the pointer/keyboard. (#88)
[i3/i3lock] / i3lock.c
index 3989e993242b29e2f90ba971f57442e39ad44a72..06531e61e0485489f9699fffab213b603b71dc31 100644 (file)
--- a/i3lock.c
+++ b/i3lock.c
@@ -43,9 +43,9 @@
     timer_obj = stop_timer(timer_obj)
 
 typedef void (*ev_callback_t)(EV_P_ ev_timer *w, int revents);
+static void input_done(void);
 
 char color[7] = "ffffff";
-int inactivity_timeout = 30;
 uint32_t last_resolution[2];
 xcb_window_t win;
 static xcb_cursor_t cursor;
@@ -66,6 +66,7 @@ extern unlock_state_t unlock_state;
 extern pam_state_t pam_state;
 int failed_attempts = 0;
 bool show_failed_attempts = false;
+bool retry_verification = false;
 
 static struct xkb_state *xkb_state;
 static struct xkb_context *xkb_context;
@@ -193,6 +194,17 @@ ev_timer *stop_timer(ev_timer *timer_obj) {
     return NULL;
 }
 
+/*
+ * Neccessary calls after ending input via enter or others
+ *
+ */
+static void finish_input(void) {
+    password[input_position] = '\0';
+    unlock_state = STATE_KEY_PRESSED;
+    redraw_screen();
+    input_done();
+}
+
 /*
  * Resets pam_state to STATE_PAM_IDLE 2 seconds after an unsuccessful
  * authentication event.
@@ -201,7 +213,6 @@ ev_timer *stop_timer(ev_timer *timer_obj) {
 static void clear_pam_wrong(EV_P_ ev_timer *w, int revents) {
     DEBUG("clearing pam wrong\n");
     pam_state = STATE_PAM_IDLE;
-    unlock_state = STATE_STARTED;
     redraw_screen();
 
     /* Clear modifier string. */
@@ -212,6 +223,12 @@ static void clear_pam_wrong(EV_P_ ev_timer *w, int revents) {
 
     /* Now free this timeout. */
     STOP_TIMER(clear_pam_wrong_timeout);
+
+    /* retry with input done during pam verification */
+    if (retry_verification) {
+        retry_verification = false;
+        finish_input();
+    }
 }
 
 static void clear_indicator_cb(EV_P_ ev_timer *w, int revents) {
@@ -223,15 +240,6 @@ static void clear_input(void) {
     input_position = 0;
     clear_password_memory();
     password[input_position] = '\0';
-
-    /* Hide the unlock indicator after a bit if the password buffer is
-     * empty. */
-    if (unlock_indicator) {
-        START_TIMER(clear_indicator_timeout, 1.0, clear_indicator_cb);
-        unlock_state = STATE_BACKSPACE_ACTIVE;
-        redraw_screen();
-        unlock_state = STATE_KEY_PRESSED;
-    }
 }
 
 static void discard_passwd_cb(EV_P_ ev_timer *w, int revents) {
@@ -242,6 +250,7 @@ static void discard_passwd_cb(EV_P_ ev_timer *w, int revents) {
 static void input_done(void) {
     STOP_TIMER(clear_pam_wrong_timeout);
     pam_state = STATE_PAM_VERIFY;
+    unlock_state = STATE_STARTED;
     redraw_screen();
 
     if (pam_authenticate(pam_handle, 0) == PAM_SUCCESS) {
@@ -376,20 +385,23 @@ static void handle_key_press(xcb_key_press_event_t *event) {
     }
 
     switch (ksym) {
+        case XKB_KEY_j:
         case XKB_KEY_Return:
         case XKB_KEY_KP_Enter:
         case XKB_KEY_XF86ScreenSaver:
-            if (pam_state == STATE_PAM_WRONG)
+            if (ksym == XKB_KEY_j && !ctrl)
+                break;
+
+            if (pam_state == STATE_PAM_WRONG) {
+                retry_verification = true;
                 return;
+            }
 
             if (skip_without_validation()) {
                 clear_input();
                 return;
             }
-            password[input_position] = '\0';
-            unlock_state = STATE_KEY_PRESSED;
-            redraw_screen();
-            input_done();
+            finish_input();
             skip_repeated_empty_password = true;
             return;
         default:
@@ -398,17 +410,23 @@ static void handle_key_press(xcb_key_press_event_t *event) {
 
     switch (ksym) {
         case XKB_KEY_u:
-            if (ctrl) {
+        case XKB_KEY_Escape:
+            if ((ksym == XKB_KEY_u && ctrl) ||
+                ksym == XKB_KEY_Escape) {
                 DEBUG("C-u pressed\n");
                 clear_input();
+                /* Hide the unlock indicator after a bit if the password buffer is
+                 * empty. */
+                if (unlock_indicator) {
+                    START_TIMER(clear_indicator_timeout, 1.0, clear_indicator_cb);
+                    unlock_state = STATE_BACKSPACE_ACTIVE;
+                    redraw_screen();
+                    unlock_state = STATE_KEY_PRESSED;
+                }
                 return;
             }
             break;
 
-        case XKB_KEY_Escape:
-            clear_input();
-            return;
-
         case XKB_KEY_Delete:
         case XKB_KEY_KP_Delete:
             /* Deleting forward doesn’t make sense, as i3lock doesn’t allow you
@@ -417,7 +435,11 @@ static void handle_key_press(xcb_key_press_event_t *event) {
              * see issue #50. */
             return;
 
+        case XKB_KEY_h:
         case XKB_KEY_BackSpace:
+            if (ksym == XKB_KEY_h && !ctrl)
+                break;
+
             if (input_position == 0)
                 return;
 
@@ -426,7 +448,7 @@ static void handle_key_press(xcb_key_press_event_t *event) {
             password[input_position] = '\0';
 
             /* Hide the unlock indicator after a bit if the password buffer is
-         * empty. */
+             * empty. */
             START_TIMER(clear_indicator_timeout, 1.0, clear_indicator_cb);
             unlock_state = STATE_BACKSPACE_ACTIVE;
             redraw_screen();
@@ -622,6 +644,22 @@ static void xcb_prepare_cb(EV_P_ ev_prepare *w, int revents) {
     xcb_flush(conn);
 }
 
+/*
+ * Try closing logind sleep lock fd passed over from xss-lock, in case we're
+ * being run from there.
+ *
+ */
+static void maybe_close_sleep_lock_fd(void) {
+    const char *sleep_lock_fd = getenv("XSS_SLEEP_LOCK_FD");
+    char *endptr;
+    if (sleep_lock_fd && *sleep_lock_fd != 0) {
+        long int fd = strtol(sleep_lock_fd, &endptr, 10);
+        if (*endptr == 0) {
+            close(fd);
+        }
+    }
+}
+
 /*
  * Instead of polling the X connection socket we leave this to
  * xcb_poll_for_event() which knows better than we can ever know.
@@ -656,6 +694,7 @@ static void xcb_check_cb(EV_P_ ev_check *w, int revents) {
                 break;
 
             case XCB_MAP_NOTIFY:
+                maybe_close_sleep_lock_fd();
                 if (!dont_fork) {
                     /* After the first MapNotify, we never fork again. We don’t
                      * expect to get another MapNotify, but better be sure… */
@@ -784,10 +823,7 @@ int main(int argc, char *argv[]) {
                 fprintf(stderr, "DPMS support has been removed from i3lock. Please see the manpage i3lock(1).\n");
                 break;
             case 'I': {
-                int time = 0;
-                if (sscanf(optarg, "%d", &time) != 1 || time < 0)
-                    errx(EXIT_FAILURE, "invalid timeout, it must be a positive integer\n");
-                inactivity_timeout = time;
+                fprintf(stderr, "Inactivity timeout only makes sense with DPMS, which was removed. Please see the manpage i3lock(1).\n");
                 break;
             }
             case 'c': {
@@ -935,15 +971,22 @@ int main(int argc, char *argv[]) {
                     image_path, cairo_status_to_string(cairo_surface_status(img)));
             img = NULL;
         }
+        free(image_path);
     }
 
     /* Pixmap on which the image is rendered to (if any) */
     xcb_pixmap_t bg_pixmap = draw_image(last_resolution);
 
-    /* open the fullscreen window, already with the correct pixmap in place */
+    /* Open the fullscreen window, already with the correct pixmap in place */
     win = open_fullscreen_window(conn, screen, color, bg_pixmap);
     xcb_free_pixmap(conn, bg_pixmap);
 
+    cursor = create_cursor(conn, screen, win, curs_choice);
+
+    /* Display the "locking…" message while trying to grab the pointer/keyboard. */
+    pam_state = STATE_PAM_LOCK;
+    grab_pointer_and_keyboard(conn, screen, cursor);
+
     pid_t pid = fork();
     /* The pid == -1 case is intentionally ignored here:
      * While the child process is useful for preventing other windows from
@@ -951,13 +994,11 @@ int main(int argc, char *argv[]) {
     if (pid == 0) {
         /* Child */
         close(xcb_get_file_descriptor(conn));
+        maybe_close_sleep_lock_fd();
         raise_loop(win);
         exit(EXIT_SUCCESS);
     }
 
-    cursor = create_cursor(conn, screen, win, curs_choice);
-
-    grab_pointer_and_keyboard(conn, screen, cursor);
     /* Load the keymap again to sync the current modifier state. Since we first
      * loaded the keymap, there might have been changes, but starting from now,
      * we should get all key presses/releases due to having grabbed the
@@ -969,6 +1010,10 @@ int main(int argc, char *argv[]) {
     if (main_loop == NULL)
         errx(EXIT_FAILURE, "Could not initialize libev. Bad LIBEV_FLAGS?\n");
 
+    /* Explicitly call the screen redraw in case "locking…" message was displayed */
+    pam_state = STATE_PAM_IDLE;
+    redraw_screen();
+
     struct ev_io *xcb_watcher = calloc(sizeof(struct ev_io), 1);
     struct ev_check *xcb_check = calloc(sizeof(struct ev_check), 1);
     struct ev_prepare *xcb_prepare = calloc(sizeof(struct ev_prepare), 1);