|
|
@ -84,7 +84,7 @@ bool ignore_empty_password = false; |
|
|
|
bool skip_repeated_empty_password = false; |
|
|
|
|
|
|
|
/* isutf, u8_dec © 2005 Jeff Bezanson, public domain */ |
|
|
|
#define isutf(c) (((c) & 0xC0) != 0x80) |
|
|
|
#define isutf(c) (((c)&0xC0) != 0x80) |
|
|
|
|
|
|
|
/*
|
|
|
|
* Decrements i to point to the previous unicode glyph |
|
|
@ -181,7 +181,7 @@ static void clear_password_memory(void) { |
|
|
|
vpassword[c] = c + (int)beep; |
|
|
|
} |
|
|
|
|
|
|
|
ev_timer* start_timer(ev_timer *timer_obj, ev_tstamp timeout, ev_callback_t callback) { |
|
|
|
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.); |
|
|
@ -198,7 +198,7 @@ ev_timer* start_timer(ev_timer *timer_obj, ev_tstamp timeout, ev_callback_t call |
|
|
|
return timer_obj; |
|
|
|
} |
|
|
|
|
|
|
|
ev_timer* stop_timer(ev_timer *timer_obj) { |
|
|
|
ev_timer *stop_timer(ev_timer *timer_obj) { |
|
|
|
if (timer_obj) { |
|
|
|
ev_timer_stop(main_loop, timer_obj); |
|
|
|
free(timer_obj); |
|
|
@ -326,20 +326,20 @@ static void handle_key_press(xcb_key_press_event_t *event) { |
|
|
|
|
|
|
|
if (xkb_compose_state && xkb_compose_state_feed(xkb_compose_state, ksym) == XKB_COMPOSE_FEED_ACCEPTED) { |
|
|
|
switch (xkb_compose_state_get_status(xkb_compose_state)) { |
|
|
|
case XKB_COMPOSE_NOTHING: |
|
|
|
break; |
|
|
|
case XKB_COMPOSE_COMPOSING: |
|
|
|
return; |
|
|
|
case XKB_COMPOSE_COMPOSED: |
|
|
|
/* xkb_compose_state_get_utf8 doesn't include the terminating byte in the return value
|
|
|
|
case XKB_COMPOSE_NOTHING: |
|
|
|
break; |
|
|
|
case XKB_COMPOSE_COMPOSING: |
|
|
|
return; |
|
|
|
case XKB_COMPOSE_COMPOSED: |
|
|
|
/* xkb_compose_state_get_utf8 doesn't include the terminating byte in the return value
|
|
|
|
* as xkb_keysym_to_utf8 does. Adding one makes the variable n consistent. */ |
|
|
|
n = xkb_compose_state_get_utf8(xkb_compose_state, buffer, sizeof(buffer)) + 1; |
|
|
|
ksym = xkb_compose_state_get_one_sym(xkb_compose_state); |
|
|
|
composed = true; |
|
|
|
break; |
|
|
|
case XKB_COMPOSE_CANCELLED: |
|
|
|
xkb_compose_state_reset(xkb_compose_state); |
|
|
|
return; |
|
|
|
n = xkb_compose_state_get_utf8(xkb_compose_state, buffer, sizeof(buffer)) + 1; |
|
|
|
ksym = xkb_compose_state_get_one_sym(xkb_compose_state); |
|
|
|
composed = true; |
|
|
|
break; |
|
|
|
case XKB_COMPOSE_CANCELLED: |
|
|
|
xkb_compose_state_reset(xkb_compose_state); |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@ -348,54 +348,54 @@ static void handle_key_press(xcb_key_press_event_t *event) { |
|
|
|
} |
|
|
|
|
|
|
|
switch (ksym) { |
|
|
|
case XKB_KEY_Return: |
|
|
|
case XKB_KEY_KP_Enter: |
|
|
|
case XKB_KEY_XF86ScreenSaver: |
|
|
|
if (pam_state == STATE_PAM_WRONG) |
|
|
|
return; |
|
|
|
|
|
|
|
if (skip_without_validation()) { |
|
|
|
clear_input(); |
|
|
|
case XKB_KEY_Return: |
|
|
|
case XKB_KEY_KP_Enter: |
|
|
|
case XKB_KEY_XF86ScreenSaver: |
|
|
|
if (pam_state == STATE_PAM_WRONG) |
|
|
|
return; |
|
|
|
|
|
|
|
if (skip_without_validation()) { |
|
|
|
clear_input(); |
|
|
|
return; |
|
|
|
} |
|
|
|
password[input_position] = '\0'; |
|
|
|
unlock_state = STATE_KEY_PRESSED; |
|
|
|
redraw_screen(); |
|
|
|
input_done(); |
|
|
|
skip_repeated_empty_password = true; |
|
|
|
return; |
|
|
|
} |
|
|
|
password[input_position] = '\0'; |
|
|
|
unlock_state = STATE_KEY_PRESSED; |
|
|
|
redraw_screen(); |
|
|
|
input_done(); |
|
|
|
skip_repeated_empty_password = true; |
|
|
|
return; |
|
|
|
default: |
|
|
|
skip_repeated_empty_password = false; |
|
|
|
default: |
|
|
|
skip_repeated_empty_password = false; |
|
|
|
} |
|
|
|
|
|
|
|
switch (ksym) { |
|
|
|
case XKB_KEY_u: |
|
|
|
if (ctrl) { |
|
|
|
DEBUG("C-u pressed\n"); |
|
|
|
case XKB_KEY_u: |
|
|
|
if (ctrl) { |
|
|
|
DEBUG("C-u pressed\n"); |
|
|
|
clear_input(); |
|
|
|
return; |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
case XKB_KEY_Escape: |
|
|
|
clear_input(); |
|
|
|
return; |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
case XKB_KEY_Escape: |
|
|
|
clear_input(); |
|
|
|
return; |
|
|
|
|
|
|
|
case XKB_KEY_BackSpace: |
|
|
|
if (input_position == 0) |
|
|
|
return; |
|
|
|
case XKB_KEY_BackSpace: |
|
|
|
if (input_position == 0) |
|
|
|
return; |
|
|
|
|
|
|
|
/* decrement input_position to point to the previous glyph */ |
|
|
|
u8_dec(password, &input_position); |
|
|
|
password[input_position] = '\0'; |
|
|
|
/* decrement input_position to point to the previous glyph */ |
|
|
|
u8_dec(password, &input_position); |
|
|
|
password[input_position] = '\0'; |
|
|
|
|
|
|
|
/* Hide the unlock indicator after a bit if the password buffer is
|
|
|
|
/* 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; |
|
|
|
return; |
|
|
|
START_TIMER(clear_indicator_timeout, 1.0, clear_indicator_cb); |
|
|
|
unlock_state = STATE_BACKSPACE_ACTIVE; |
|
|
|
redraw_screen(); |
|
|
|
unlock_state = STATE_KEY_PRESSED; |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if ((input_position + 8) >= sizeof(password)) |
|
|
@ -416,8 +416,8 @@ static void handle_key_press(xcb_key_press_event_t *event) { |
|
|
|
return; |
|
|
|
|
|
|
|
/* store it in the password array as UTF-8 */ |
|
|
|
memcpy(password+input_position, buffer, n-1); |
|
|
|
input_position += n-1; |
|
|
|
memcpy(password + input_position, buffer, n - 1); |
|
|
|
input_position += n - 1; |
|
|
|
DEBUG("current password = %.*s\n", input_position, password); |
|
|
|
|
|
|
|
unlock_state = STATE_KEY_ACTIVE; |
|
|
@ -440,9 +440,9 @@ static void handle_key_press(xcb_key_press_event_t *event) { |
|
|
|
* |
|
|
|
*/ |
|
|
|
static void handle_visibility_notify(xcb_connection_t *conn, |
|
|
|
xcb_visibility_notify_event_t *event) { |
|
|
|
xcb_visibility_notify_event_t *event) { |
|
|
|
if (event->state != XCB_VISIBILITY_UNOBSCURED) { |
|
|
|
uint32_t values[] = { XCB_STACK_MODE_ABOVE }; |
|
|
|
uint32_t values[] = {XCB_STACK_MODE_ABOVE}; |
|
|
|
xcb_configure_window(conn, event->window, XCB_CONFIG_WINDOW_STACK_MODE, values); |
|
|
|
xcb_flush(conn); |
|
|
|
} |
|
|
@ -467,7 +467,7 @@ static void process_xkb_event(xcb_generic_event_t *gevent) { |
|
|
|
xcb_xkb_new_keyboard_notify_event_t new_keyboard_notify; |
|
|
|
xcb_xkb_map_notify_event_t map_notify; |
|
|
|
xcb_xkb_state_notify_event_t state_notify; |
|
|
|
} *event = (union xkb_event*)gevent; |
|
|
|
} *event = (union xkb_event *)gevent; |
|
|
|
|
|
|
|
DEBUG("process_xkb_event for device %d\n", event->any.deviceID); |
|
|
|
|
|
|
@ -540,8 +540,7 @@ void handle_screen_resize(void) { |
|
|
|
* |
|
|
|
*/ |
|
|
|
static int conv_callback(int num_msg, const struct pam_message **msg, |
|
|
|
struct pam_response **resp, void *appdata_ptr) |
|
|
|
{ |
|
|
|
struct pam_response **resp, void *appdata_ptr) { |
|
|
|
if (num_msg == 0) |
|
|
|
return 1; |
|
|
|
|
|
|
@ -597,7 +596,7 @@ static void xcb_check_cb(EV_P_ ev_check *w, int revents) { |
|
|
|
|
|
|
|
while ((event = xcb_poll_for_event(conn)) != NULL) { |
|
|
|
if (event->response_type == 0) { |
|
|
|
xcb_generic_error_t *error = (xcb_generic_error_t*)event; |
|
|
|
xcb_generic_error_t *error = (xcb_generic_error_t *)event; |
|
|
|
if (debug_mode) |
|
|
|
fprintf(stderr, "X11 Error received! sequence 0x%x, error_code = %d\n", |
|
|
|
error->sequence, error->error_code); |
|
|
@ -610,7 +609,7 @@ static void xcb_check_cb(EV_P_ ev_check *w, int revents) { |
|
|
|
|
|
|
|
switch (type) { |
|
|
|
case XCB_KEY_PRESS: |
|
|
|
handle_key_press((xcb_key_press_event_t*)event); |
|
|
|
handle_key_press((xcb_key_press_event_t *)event); |
|
|
|
break; |
|
|
|
|
|
|
|
case XCB_KEY_RELEASE: |
|
|
@ -623,7 +622,7 @@ static void xcb_check_cb(EV_P_ ev_check *w, int revents) { |
|
|
|
break; |
|
|
|
|
|
|
|
case XCB_VISIBILITY_NOTIFY: |
|
|
|
handle_visibility_notify(conn, (xcb_visibility_notify_event_t*)event); |
|
|
|
handle_visibility_notify(conn, (xcb_visibility_notify_event_t *)event); |
|
|
|
break; |
|
|
|
|
|
|
|
case XCB_MAP_NOTIFY: |
|
|
@ -670,18 +669,17 @@ static void raise_loop(xcb_window_t window) { |
|
|
|
|
|
|
|
/* We need to know about the window being obscured or getting destroyed. */ |
|
|
|
xcb_change_window_attributes(conn, window, XCB_CW_EVENT_MASK, |
|
|
|
(uint32_t[]){ |
|
|
|
XCB_EVENT_MASK_VISIBILITY_CHANGE | |
|
|
|
XCB_EVENT_MASK_STRUCTURE_NOTIFY |
|
|
|
}); |
|
|
|
(uint32_t[]){ |
|
|
|
XCB_EVENT_MASK_VISIBILITY_CHANGE | |
|
|
|
XCB_EVENT_MASK_STRUCTURE_NOTIFY}); |
|
|
|
xcb_flush(conn); |
|
|
|
|
|
|
|
DEBUG("Watching window 0x%08x\n", window); |
|
|
|
while ((event = xcb_wait_for_event(conn)) != NULL) { |
|
|
|
if (event->response_type == 0) { |
|
|
|
xcb_generic_error_t *error = (xcb_generic_error_t*)event; |
|
|
|
xcb_generic_error_t *error = (xcb_generic_error_t *)event; |
|
|
|
DEBUG("X11 Error received! sequence 0x%x, error_code = %d\n", |
|
|
|
error->sequence, error->error_code); |
|
|
|
error->sequence, error->error_code); |
|
|
|
free(event); |
|
|
|
continue; |
|
|
|
} |
|
|
@ -690,16 +688,16 @@ static void raise_loop(xcb_window_t window) { |
|
|
|
DEBUG("Read event of type %d\n", type); |
|
|
|
switch (type) { |
|
|
|
case XCB_VISIBILITY_NOTIFY: |
|
|
|
handle_visibility_notify(conn, (xcb_visibility_notify_event_t*)event); |
|
|
|
handle_visibility_notify(conn, (xcb_visibility_notify_event_t *)event); |
|
|
|
break; |
|
|
|
case XCB_UNMAP_NOTIFY: |
|
|
|
DEBUG("UnmapNotify for 0x%08x\n", (((xcb_unmap_notify_event_t*)event)->window)); |
|
|
|
if (((xcb_unmap_notify_event_t*)event)->window == window) |
|
|
|
DEBUG("UnmapNotify for 0x%08x\n", (((xcb_unmap_notify_event_t *)event)->window)); |
|
|
|
if (((xcb_unmap_notify_event_t *)event)->window == window) |
|
|
|
exit(EXIT_SUCCESS); |
|
|
|
break; |
|
|
|
case XCB_DESTROY_NOTIFY: |
|
|
|
DEBUG("DestroyNotify for 0x%08x\n", (((xcb_destroy_notify_event_t*)event)->window)); |
|
|
|
if (((xcb_destroy_notify_event_t*)event)->window == window) |
|
|
|
DEBUG("DestroyNotify for 0x%08x\n", (((xcb_destroy_notify_event_t *)event)->window)); |
|
|
|
if (((xcb_destroy_notify_event_t *)event)->window == window) |
|
|
|
exit(EXIT_SUCCESS); |
|
|
|
break; |
|
|
|
default: |
|
|
@ -725,7 +723,7 @@ int main(int argc, char *argv[]) { |
|
|
|
{"beep", no_argument, NULL, 'b'}, |
|
|
|
{"dpms", no_argument, NULL, 'd'}, |
|
|
|
{"color", required_argument, NULL, 'c'}, |
|
|
|
{"pointer", required_argument, NULL , 'p'}, |
|
|
|
{"pointer", required_argument, NULL, 'p'}, |
|
|
|
{"debug", no_argument, NULL, 0}, |
|
|
|
{"help", no_argument, NULL, 'h'}, |
|
|
|
{"no-unlock-indicator", no_argument, NULL, 'u'}, |
|
|
@ -734,8 +732,7 @@ int main(int argc, char *argv[]) { |
|
|
|
{"ignore-empty-password", no_argument, NULL, 'e'}, |
|
|
|
{"inactivity-timeout", required_argument, NULL, 'I'}, |
|
|
|
{"show-failed-attempts", no_argument, NULL, 'f'}, |
|
|
|
{NULL, no_argument, NULL, 0} |
|
|
|
}; |
|
|
|
{NULL, no_argument, NULL, 0}}; |
|
|
|
|
|
|
|
if ((pw = getpwuid(getuid())) == NULL) |
|
|
|
err(EXIT_FAILURE, "getpwuid() failed"); |
|
|
@ -745,68 +742,67 @@ int main(int argc, char *argv[]) { |
|
|
|
char *optstring = "hvnbdc:p:ui:teI:f"; |
|
|
|
while ((o = getopt_long(argc, argv, optstring, longopts, &optind)) != -1) { |
|
|
|
switch (o) { |
|
|
|
case 'v': |
|
|
|
errx(EXIT_SUCCESS, "version " VERSION " © 2010-2012 Michael Stapelberg"); |
|
|
|
case 'n': |
|
|
|
dont_fork = true; |
|
|
|
break; |
|
|
|
case 'b': |
|
|
|
beep = true; |
|
|
|
break; |
|
|
|
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; |
|
|
|
case 'v': |
|
|
|
errx(EXIT_SUCCESS, "version " VERSION " © 2010-2012 Michael Stapelberg"); |
|
|
|
case 'n': |
|
|
|
dont_fork = true; |
|
|
|
break; |
|
|
|
case 'b': |
|
|
|
beep = true; |
|
|
|
break; |
|
|
|
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; |
|
|
|
|
|
|
|
/* Skip # if present */ |
|
|
|
if (arg[0] == '#') |
|
|
|
arg++; |
|
|
|
/* Skip # if present */ |
|
|
|
if (arg[0] == '#') |
|
|
|
arg++; |
|
|
|
|
|
|
|
if (strlen(arg) != 6 || sscanf(arg, "%06[0-9a-fA-F]", color) != 1) |
|
|
|
errx(EXIT_FAILURE, "color is invalid, it must be given in 3-byte hexadecimal format: rrggbb\n"); |
|
|
|
if (strlen(arg) != 6 || sscanf(arg, "%06[0-9a-fA-F]", color) != 1) |
|
|
|
errx(EXIT_FAILURE, "color is invalid, it must be given in 3-byte hexadecimal format: rrggbb\n"); |
|
|
|
|
|
|
|
break; |
|
|
|
} |
|
|
|
case 'u': |
|
|
|
unlock_indicator = false; |
|
|
|
break; |
|
|
|
case 'i': |
|
|
|
image_path = strdup(optarg); |
|
|
|
break; |
|
|
|
case 't': |
|
|
|
tile = true; |
|
|
|
break; |
|
|
|
case 'p': |
|
|
|
if (!strcmp(optarg, "win")) { |
|
|
|
curs_choice = CURS_WIN; |
|
|
|
} else if (!strcmp(optarg, "default")) { |
|
|
|
curs_choice = CURS_DEFAULT; |
|
|
|
} else { |
|
|
|
errx(EXIT_FAILURE, "i3lock: Invalid pointer type given. Expected one of \"win\" or \"default\".\n"); |
|
|
|
break; |
|
|
|
} |
|
|
|
break; |
|
|
|
case 'e': |
|
|
|
ignore_empty_password = true; |
|
|
|
break; |
|
|
|
case 0: |
|
|
|
if (strcmp(longopts[optind].name, "debug") == 0) |
|
|
|
debug_mode = true; |
|
|
|
break; |
|
|
|
case 'f': |
|
|
|
show_failed_attempts = true; |
|
|
|
break; |
|
|
|
default: |
|
|
|
errx(EXIT_FAILURE, "Syntax: i3lock [-v] [-n] [-b] [-d] [-c color] [-u] [-p win|default]" |
|
|
|
" [-i image.png] [-t] [-e] [-I] [-f]" |
|
|
|
); |
|
|
|
case 'u': |
|
|
|
unlock_indicator = false; |
|
|
|
break; |
|
|
|
case 'i': |
|
|
|
image_path = strdup(optarg); |
|
|
|
break; |
|
|
|
case 't': |
|
|
|
tile = true; |
|
|
|
break; |
|
|
|
case 'p': |
|
|
|
if (!strcmp(optarg, "win")) { |
|
|
|
curs_choice = CURS_WIN; |
|
|
|
} else if (!strcmp(optarg, "default")) { |
|
|
|
curs_choice = CURS_DEFAULT; |
|
|
|
} else { |
|
|
|
errx(EXIT_FAILURE, "i3lock: Invalid pointer type given. Expected one of \"win\" or \"default\".\n"); |
|
|
|
} |
|
|
|
break; |
|
|
|
case 'e': |
|
|
|
ignore_empty_password = true; |
|
|
|
break; |
|
|
|
case 0: |
|
|
|
if (strcmp(longopts[optind].name, "debug") == 0) |
|
|
|
debug_mode = true; |
|
|
|
break; |
|
|
|
case 'f': |
|
|
|
show_failed_attempts = true; |
|
|
|
break; |
|
|
|
default: |
|
|
|
errx(EXIT_FAILURE, "Syntax: i3lock [-v] [-n] [-b] [-d] [-c color] [-u] [-p win|default]" |
|
|
|
" [-i image.png] [-t] [-e] [-I] [-f]"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@ -837,13 +833,13 @@ int main(int argc, char *argv[]) { |
|
|
|
errx(EXIT_FAILURE, "Could not connect to X11, maybe you need to set DISPLAY?"); |
|
|
|
|
|
|
|
if (xkb_x11_setup_xkb_extension(conn, |
|
|
|
XKB_X11_MIN_MAJOR_XKB_VERSION, |
|
|
|
XKB_X11_MIN_MINOR_XKB_VERSION, |
|
|
|
0, |
|
|
|
NULL, |
|
|
|
NULL, |
|
|
|
&xkb_base_event, |
|
|
|
&xkb_base_error) != 1) |
|
|
|
XKB_X11_MIN_MAJOR_XKB_VERSION, |
|
|
|
XKB_X11_MIN_MINOR_XKB_VERSION, |
|
|
|
0, |
|
|
|
NULL, |
|
|
|
NULL, |
|
|
|
&xkb_base_event, |
|
|
|
&xkb_base_error) != 1) |
|
|
|
errx(EXIT_FAILURE, "Could not setup XKB extension."); |
|
|
|
|
|
|
|
static const xcb_xkb_map_part_t required_map_parts = |
|
|
@ -910,7 +906,7 @@ int main(int argc, char *argv[]) { |
|
|
|
last_resolution[1] = screen->height_in_pixels; |
|
|
|
|
|
|
|
xcb_change_window_attributes(conn, screen->root, XCB_CW_EVENT_MASK, |
|
|
|
(uint32_t[]){ XCB_EVENT_MASK_STRUCTURE_NOTIFY }); |
|
|
|
(uint32_t[]){XCB_EVENT_MASK_STRUCTURE_NOTIFY}); |
|
|
|
|
|
|
|
if (image_path) { |
|
|
|
/* Create a pixmap to render on, fill it with the background color */ |
|
|
|