#include "unlock_indicator.h"
#include "xinerama.h"
+#define TSTAMP_N_SECS(n) (n * 1.0)
+#define TSTAMP_N_MINS(n) (60 * TSTAMP_N_SECS(n))
+#define START_TIMER(timer_obj, timeout, callback) \
+ timer_obj = start_timer(timer_obj, timeout, callback)
+#define STOP_TIMER(timer_obj) \
+ timer_obj = stop_timer(timer_obj)
+
+typedef void (*ev_callback_t)(EV_P_ ev_timer *w, int revents);
+
/* We need this for libxkbfile */
static Display *display;
char color[7] = "ffffff";
+int inactivity_timeout = 30;
uint32_t last_resolution[2];
xcb_window_t win;
static xcb_cursor_t cursor;
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
vpassword[c] = c + (int)beep;
}
+ev_timer* start_timer(ev_timer *timer_obj, ev_tstamp timeout, ev_callback_t callback) {
+ if (timer_obj) {
+ ev_timer_stop(main_loop, timer_obj);
+ ev_timer_set(timer_obj, timeout, 0.);
+ ev_timer_start(main_loop, timer_obj);
+ } else {
+ /* When there is no memory, we just don’t have a timeout. We cannot
+ * exit() here, since that would effectively unlock the screen. */
+ timer_obj = calloc(sizeof(struct ev_timer), 1);
+ if (timer_obj) {
+ ev_timer_init(timer_obj, callback, timeout, 0.);
+ ev_timer_start(main_loop, timer_obj);
+ }
+ }
+ return timer_obj;
+}
+
+ev_timer* stop_timer(ev_timer *timer_obj) {
+ if (timer_obj) {
+ ev_timer_stop(main_loop, timer_obj);
+ free(timer_obj);
+ }
+ return NULL;
+}
/*
- * Resets pam_state to STATE_PAM_IDLE 2 seconds after an unsuccesful
+ * Resets pam_state to STATE_PAM_IDLE 2 seconds after an unsuccessful
* authentication event.
*
*/
clear_pam_wrong_timeout = NULL;
}
+static void clear_indicator_cb(EV_P_ ev_timer *w, int revents) {
+ clear_indicator();
+ STOP_TIMER(clear_indicator_timeout);
+}
+
static void clear_input(void) {
input_position = 0;
clear_password_memory();
/* Hide the unlock indicator after a bit if the password buffer is
* empty. */
- start_clear_indicator_timeout();
+ 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) {
if (clear_pam_wrong_timeout) {
ev_timer_stop(main_loop, clear_pam_wrong_timeout);
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();
exit(0);
}
/* Cancel the clear_indicator_timeout, it would hide the unlock indicator
* too early. */
- stop_clear_indicator_timeout();
+ STOP_TIMER(clear_indicator_timeout);
/* beep on authentication failure, if enabled */
if (beep) {
/* Hide the unlock indicator after a bit if the password buffer is
* empty. */
- start_clear_indicator_timeout();
+ START_TIMER(clear_indicator_timeout, 1.0, clear_indicator_cb);
unlock_state = STATE_BACKSPACE_ACTIVE;
redraw_screen();
unlock_state = STATE_KEY_PRESSED;
ev_timer_start(main_loop, timeout);
}
- stop_clear_indicator_timeout();
+ STOP_TIMER(clear_indicator_timeout);
+ START_TIMER(discard_passwd_timeout, TSTAMP_N_MINS(3), discard_passwd_cb);
}
/*
handle_key_release((xcb_key_release_event_t*)event);
/* If this was the backspace or escape key we are back at an
- * empty input, so turn off the screen if DPMS is enabled */
- if (dpms && input_position == 0)
- dpms_turn_off_screen(conn);
-
+ * 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:
{"image", required_argument, NULL, 'i'},
{"tiling", no_argument, NULL, 't'},
{"ignore-empty-password", no_argument, NULL, 'e'},
+ {"inactivity-timeout", required_argument, NULL, 'I'},
{NULL, no_argument, NULL, 0}
};
if ((username = getenv("USER")) == NULL)
- errx(1, "USER environment variable not set, please set it.\n");
+ errx(EXIT_FAILURE, "USER environment variable not set, please set it.\n");
- while ((o = getopt_long(argc, argv, "hvnbdc:p:ui:te", longopts, &optind)) != -1) {
+ char *optstring = "hvnbdc:p:ui:teI:";
+ while ((o = getopt_long(argc, argv, optstring, longopts, &optind)) != -1) {
switch (o) {
case 'v':
errx(EXIT_SUCCESS, "version " VERSION " © 2010-2012 Michael Stapelberg");
case 'd':
dpms = true;
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;
+ break;
+ }
case 'c': {
char *arg = optarg;
arg++;
if (strlen(arg) != 6 || sscanf(arg, "%06[0-9a-fA-F]", color) != 1)
- errx(1, "color is invalid, it must be given in 3-byte hexadecimal format: rrggbb\n");
+ errx(EXIT_FAILURE, "color is invalid, it must be given in 3-byte hexadecimal format: rrggbb\n");
break;
}
} else if (!strcmp(optarg, "default")) {
curs_choice = CURS_DEFAULT;
} else {
- errx(1, "i3lock: Invalid pointer type given. Expected one of \"win\" or \"default\".\n");
+ errx(EXIT_FAILURE, "i3lock: Invalid pointer type given. Expected one of \"win\" or \"default\".\n");
}
break;
case 'e':
debug_mode = true;
break;
default:
- errx(1, "Syntax: i3lock [-v] [-n] [-b] [-d] [-c color] [-u] [-p win|default]"
- " [-i image.png] [-t] [-e]"
+ errx(EXIT_FAILURE, "Syntax: i3lock [-v] [-n] [-b] [-d] [-c color] [-u] [-p win|default]"
+ " [-i image.png] [-t] [-e] [-I]"
);
}
}
* keyboard. */
(void)load_keymap();
- if (dpms)
- dpms_turn_off_screen(conn);
+ turn_monitors_off();
/* Initialize the libev event loop. */
main_loop = EV_DEFAULT;