X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=i3lock.c;h=1bb7b0c8b40c91f1a25e4b3fa4520d323bd08a12;hb=5b4d45a8aff1dacaad364ae6df70c3a6a5067701;hp=01f0436a1de6569689df2db980d3fbe588284d34;hpb=0bed914e8eccb5d62cb12de4b26541b7441c94dc;p=i3%2Fi3lock diff --git a/i3lock.c b/i3lock.c index 01f0436..1bb7b0c 100644 --- a/i3lock.c +++ b/i3lock.c @@ -35,6 +35,7 @@ #ifdef __OpenBSD__ #include /* explicit_bzero(3) */ #endif +#include #include "i3lock.h" #include "xcb.h" @@ -278,7 +279,8 @@ static void input_done(void) { DEBUG("successfully authenticated\n"); clear_password_memory(); - exit(0); + ev_break(EV_DEFAULT, EVBREAK_ALL); + return; } #else if (pam_authenticate(pam_handle, 0) == PAM_SUCCESS) { @@ -292,7 +294,8 @@ static void input_done(void) { pam_setcred(pam_handle, PAM_REFRESH_CRED); pam_end(pam_handle, PAM_SUCCESS); - exit(0); + ev_break(EV_DEFAULT, EVBREAK_ALL); + return; } #endif @@ -445,14 +448,9 @@ static void handle_key_press(xcb_key_press_event_t *event) { 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; - } + /* Also hide the unlock indicator */ + if (unlock_indicator) + clear_indicator(); return; } break; @@ -819,7 +817,7 @@ int main(int argc, char *argv[]) { #endif int curs_choice = CURS_NONE; int o; - int optind = 0; + int longoptind = 0; struct option longopts[] = { {"version", no_argument, NULL, 'v'}, {"nofork", no_argument, NULL, 'n'}, @@ -843,7 +841,7 @@ int main(int argc, char *argv[]) { errx(EXIT_FAILURE, "pw->pw_name is NULL.\n"); char *optstring = "hvnbdc:p:ui:teI:f"; - while ((o = getopt_long(argc, argv, optstring, longopts, &optind)) != -1) { + while ((o = getopt_long(argc, argv, optstring, longopts, &longoptind)) != -1) { switch (o) { case 'v': errx(EXIT_SUCCESS, "version " VERSION " © 2010 Michael Stapelberg"); @@ -894,7 +892,7 @@ int main(int argc, char *argv[]) { ignore_empty_password = true; break; case 0: - if (strcmp(longopts[optind].name, "debug") == 0) + if (strcmp(longopts[longoptind].name, "debug") == 0) debug_mode = true; break; case 'f': @@ -919,12 +917,12 @@ int main(int argc, char *argv[]) { errx(EXIT_FAILURE, "PAM: %s", pam_strerror(pam_handle, ret)); #endif -/* Using mlock() as non-super-user seems only possible in Linux and OpenBSD. +/* Using mlock() as non-super-user seems only possible in Linux. * Users of other operating systems should use encrypted swap/no swap * (or remove the ifdef and run i3lock as super-user). - * NB: Alas, swap is encrypted by default on OpenBSD so swapping out + * Alas, swap is encrypted by default on OpenBSD so swapping out * is not necessarily an issue. */ -#if defined(__linux__) || defined(__OpenBSD__) +#if defined(__linux__) /* Lock the area where we store the password in memory, we don’t want it to * be swapped to disk. Since Linux 2.6.9, this does not require any * privileges, just enough bytes in the RLIMIT_MEMLOCK limit. */ @@ -977,11 +975,11 @@ int main(int argc, char *argv[]) { errx(EXIT_FAILURE, "Could not load keymap"); const char *locale = getenv("LC_ALL"); - if (!locale) + if (!locale || !*locale) locale = getenv("LC_CTYPE"); - if (!locale) + if (!locale || !*locale) locale = getenv("LANG"); - if (!locale) { + if (!locale || !*locale) { if (debug_mode) fprintf(stderr, "Can't detect your locale, fallback to C\n"); locale = "C"; @@ -1015,6 +1013,8 @@ int main(int argc, char *argv[]) { /* Pixmap on which the image is rendered to (if any) */ xcb_pixmap_t bg_pixmap = draw_image(last_resolution); + xcb_window_t stolen_focus = find_focused_window(conn, screen->root); + /* 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); @@ -1023,7 +1023,23 @@ int main(int argc, char *argv[]) { /* Display the "locking…" message while trying to grab the pointer/keyboard. */ auth_state = STATE_AUTH_LOCK; - grab_pointer_and_keyboard(conn, screen, cursor); + if (!grab_pointer_and_keyboard(conn, screen, cursor, 1000)) { + DEBUG("stole focus from X11 window 0x%08x\n", stolen_focus); + + /* Set the focus to i3lock, possibly closing context menus which would + * otherwise prevent us from grabbing keyboard/pointer. + * + * We cannot use set_focused_window because _NET_ACTIVE_WINDOW only + * works for managed windows, but i3lock uses an unmanaged window + * (override_redirect=1). */ + xcb_set_input_focus(conn, XCB_INPUT_FOCUS_PARENT /* revert_to */, win, XCB_CURRENT_TIME); + if (!grab_pointer_and_keyboard(conn, screen, cursor, 9000)) { + auth_state = STATE_I3LOCK_LOCK_FAILED; + redraw_screen(); + sleep(1); + errx(EXIT_FAILURE, "Cannot grab pointer/keyboard"); + } + } pid_t pid = fork(); /* The pid == -1 case is intentionally ignored here: @@ -1070,4 +1086,17 @@ int main(int argc, char *argv[]) { * file descriptor becomes readable). */ ev_invoke(main_loop, xcb_check, 0); ev_loop(main_loop, 0); + + if (stolen_focus == XCB_NONE) { + return 0; + } + + DEBUG("restoring focus to X11 window 0x%08x\n", stolen_focus); + xcb_ungrab_pointer(conn, XCB_CURRENT_TIME); + xcb_ungrab_keyboard(conn, XCB_CURRENT_TIME); + xcb_destroy_window(conn, win); + set_focused_window(conn, screen->root, stolen_focus); + xcb_aux_sync(conn); + + return 0; }