#include <stdint.h>
#include <xcb/xcb.h>
#include <xcb/xkb.h>
-#include <xcb/dpms.h>
#include <err.h>
#include <assert.h>
#include <security/pam_appl.h>
typedef void (*ev_callback_t)(EV_P_ ev_timer *w, int revents);
-/* We need this for libxkbfile */
char color[7] = "ffffff";
int inactivity_timeout = 30;
uint32_t last_resolution[2];
static char password[512];
static bool beep = false;
bool debug_mode = false;
-static bool dpms = false;
bool unlock_indicator = true;
char *modifier_string = NULL;
static bool dont_fork = false;
struct ev_loop *main_loop;
static struct ev_timer *clear_pam_wrong_timeout;
static struct ev_timer *clear_indicator_timeout;
-static struct ev_timer *dpms_timeout;
static struct ev_timer *discard_passwd_timeout;
extern unlock_state_t unlock_state;
extern pam_state_t pam_state;
(void)(isutf(s[--(*i)]) || isutf(s[--(*i)]) || isutf(s[--(*i)]) || --(*i));
}
-static void turn_monitors_on(void) {
- if (dpms)
- dpms_set_mode(conn, XCB_DPMS_DPMS_MODE_ON);
-}
-
-static void turn_monitors_off(void) {
- if (dpms)
- dpms_set_mode(conn, XCB_DPMS_DPMS_MODE_OFF);
-}
-
/*
* Loads the XKB keymap from the X11 server and feeds it to xkbcommon.
* Necessary so that we can properly let xkbcommon track the keyboard state and
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. */
input_position = 0;
clear_password_memory();
password[input_position] = '\0';
-
- /* Hide the unlock indicator after a bit if the password buffer is
- * empty. */
- START_TIMER(clear_indicator_timeout, 1.0, clear_indicator_cb);
- unlock_state = STATE_BACKSPACE_ACTIVE;
- redraw_screen();
- unlock_state = STATE_KEY_PRESSED;
-}
-
-static void turn_off_monitors_cb(EV_P_ ev_timer *w, int revents) {
- if (input_position == 0)
- turn_monitors_off();
-
- STOP_TIMER(dpms_timeout);
}
static void discard_passwd_cb(EV_P_ ev_timer *w, int revents) {
clear_input();
- turn_monitors_off();
STOP_TIMER(discard_passwd_timeout);
}
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) {
DEBUG("successfully authenticated\n");
clear_password_memory();
- /* Turn the screen on, as it may have been turned off
- * on release of the 'enter' key. */
- turn_monitors_on();
/* PAM credentials should be refreshed, this will for example update any kerberos tickets.
* Related to credentials pam_end() needs to be called to cleanup any temporary
pam_state = STATE_PAM_WRONG;
failed_attempts += 1;
clear_input();
- redraw_screen();
+ if (unlock_indicator)
+ redraw_screen();
/* Clear this state after 2 seconds (unless the user enters another
* password during that time). */
}
switch (ksym) {
+ case XKB_KEY_j:
case XKB_KEY_Return:
case XKB_KEY_KP_Enter:
case XKB_KEY_XF86ScreenSaver:
+ if (ksym == XKB_KEY_j && !ctrl)
+ break;
+
if (pam_state == STATE_PAM_WRONG)
return;
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();
+ case XKB_KEY_Delete:
+ case XKB_KEY_KP_Delete:
+ /* Deleting forward doesn’t make sense, as i3lock doesn’t allow you
+ * to move the cursor when entering a password. We need to eat this
+ * key press so that it won’t be treated as part of the password,
+ * see issue #50. */
return;
+ case XKB_KEY_h:
case XKB_KEY_BackSpace:
+ if (ksym == XKB_KEY_h && !ctrl)
+ break;
+
if (input_position == 0)
return;
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();
input_position += n - 1;
DEBUG("current password = %.*s\n", input_position, password);
- unlock_state = STATE_KEY_ACTIVE;
- redraw_screen();
- unlock_state = STATE_KEY_PRESSED;
+ if (unlock_indicator) {
+ unlock_state = STATE_KEY_ACTIVE;
+ redraw_screen();
+ unlock_state = STATE_KEY_PRESSED;
+
+ struct ev_timer *timeout = NULL;
+ START_TIMER(timeout, TSTAMP_N_SECS(0.25), redraw_timeout);
+ STOP_TIMER(clear_indicator_timeout);
+ }
- struct ev_timer *timeout = NULL;
- START_TIMER(timeout, TSTAMP_N_SECS(0.25), redraw_timeout);
- STOP_TIMER(clear_indicator_timeout);
START_TIMER(discard_passwd_timeout, TSTAMP_N_MINS(3), discard_passwd_cb);
}
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.
handle_key_press((xcb_key_press_event_t *)event);
break;
- case XCB_KEY_RELEASE:
- /* If this was the backspace or escape key we are back at an
- * empty input, so turn off the screen if DPMS is enabled, but
- * only do that after some timeout: maybe user mistyped and
- * will type again right away */
- START_TIMER(dpms_timeout, TSTAMP_N_SECS(inactivity_timeout),
- turn_off_monitors_cb);
- break;
-
case XCB_VISIBILITY_NOTIFY:
handle_visibility_notify(conn, (xcb_visibility_notify_event_t *)event);
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… */
beep = true;
break;
case 'd':
- dpms = true;
+ fprintf(stderr, "DPMS support has been removed from i3lock. Please see the manpage i3lock(1).\n");
break;
case 'I': {
int time = 0;
break;
default:
errx(EXIT_FAILURE, "Syntax: i3lock [-v] [-n] [-b] [-d] [-c color] [-u] [-p win|default]"
- " [-i image.png] [-t] [-e] [-I] [-f]");
+ " [-i image.png] [-t] [-e] [-I timeout] [-f]");
}
}
srand(time(NULL));
/* Initialize PAM */
- ret = pam_start("i3lock", username, &conv, &pam_handle);
- if (ret != PAM_SUCCESS)
+ if ((ret = pam_start("i3lock", username, &conv, &pam_handle)) != PAM_SUCCESS)
+ errx(EXIT_FAILURE, "PAM: %s", pam_strerror(pam_handle, ret));
+
+ if ((ret = pam_set_item(pam_handle, PAM_TTY, getenv("DISPLAY"))) != PAM_SUCCESS)
errx(EXIT_FAILURE, "PAM: %s", pam_strerror(pam_handle, ret));
/* Using mlock() as non-super-user seems only possible in Linux. Users of other
xinerama_init();
xinerama_query_screens();
- /* if DPMS is enabled, check if the X server really supports it */
- if (dpms) {
- xcb_dpms_capable_cookie_t dpmsc = xcb_dpms_capable(conn);
- xcb_dpms_capable_reply_t *dpmsr;
- if ((dpmsr = xcb_dpms_capable_reply(conn, dpmsc, NULL))) {
- if (!dpmsr->capable) {
- if (debug_mode)
- fprintf(stderr, "Disabling DPMS, X server not DPMS capable\n");
- dpms = false;
- }
- free(dpmsr);
- }
- }
-
screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data;
last_resolution[0] = screen->width_in_pixels;
if (pid == 0) {
/* Child */
close(xcb_get_file_descriptor(conn));
+ maybe_close_sleep_lock_fd();
raise_loop(win);
exit(EXIT_SUCCESS);
}
* keyboard. */
(void)load_keymap();
- turn_monitors_off();
-
/* Initialize the libev event loop. */
main_loop = EV_DEFAULT;
if (main_loop == NULL)