diff --git a/i3lock.1 b/i3lock.1 index 0b6a186..f7c90ef 100644 --- a/i3lock.1 +++ b/i3lock.1 @@ -146,6 +146,10 @@ your computer with the enter key. .B \-f, \-\-show-failed-attempts Show the number of failed attempts, if any. +.TP +.B \-k, \-\-show-keyboard-layout +Show the current keyboard layout. + .TP .B \-\-debug Enables debug logging. diff --git a/i3lock.c b/i3lock.c index 159ea9f..bcd6976 100644 --- a/i3lock.c +++ b/i3lock.c @@ -81,6 +81,7 @@ extern unlock_state_t unlock_state; extern auth_state_t auth_state; int failed_attempts = 0; bool show_failed_attempts = false; +bool show_keyboard_layout = false; bool retry_verification = false; struct xkb_state *xkb_state; @@ -902,6 +903,7 @@ static void xcb_check_cb(EV_P_ ev_check *w, int revents) { default: if (type == xkb_base_event) { process_xkb_event(event); + redraw_screen(); } if (randr_base > -1 && type == randr_base + XCB_RANDR_SCREEN_CHANGE_NOTIFY) { @@ -997,6 +999,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'}, + {"show-keyboard-layout", no_argument, NULL, 'k'}, {NULL, no_argument, NULL, 0}}; if ((pw = getpwuid(getuid())) == NULL) @@ -1006,7 +1009,7 @@ int main(int argc, char *argv[]) { if (getenv("WAYLAND_DISPLAY") != NULL) errx(EXIT_FAILURE, "i3lock is a program for X11 and does not work on Wayland. Try https://github.com/swaywm/swaylock instead"); - char *optstring = "hvnbdc:p:ui:teI:f"; + char *optstring = "hvnbdc:p:ui:teI:fk"; while ((o = getopt_long(argc, argv, optstring, longopts, &longoptind)) != -1) { switch (o) { case 'v': @@ -1066,9 +1069,12 @@ int main(int argc, char *argv[]) { case 'f': show_failed_attempts = true; break; + case 'k': + show_keyboard_layout = true; + break; default: errx(EXIT_FAILURE, "Syntax: i3lock [-v] [-n] [-b] [-d] [-c color] [-u] [-p win|default]" - " [-i image.png] [-t] [-e] [-I timeout] [-f]"); + " [-i image.png] [-t] [-e] [-I timeout] [-f] [-k]"); } } diff --git a/unlock_indicator.c b/unlock_indicator.c index 4ec07b8..a50b52f 100644 --- a/unlock_indicator.c +++ b/unlock_indicator.c @@ -49,6 +49,8 @@ extern bool unlock_indicator; /* List of pressed modifiers, or NULL if none are pressed. */ extern char *modifier_string; +/* Name of the current keyboard layout or NULL if not initialized. */ +char *layout_string = NULL; /* A Cairo surface containing the specified image (-i), if any. */ extern cairo_surface_t *img; @@ -60,6 +62,8 @@ extern char color[7]; /* Whether the failed attempts should be displayed. */ extern bool show_failed_attempts; +/* Whether keyboard layout should be displayed. */ +extern bool show_keyboard_layout; /* Number of failed unlock attempts. */ extern int failed_attempts; @@ -85,6 +89,53 @@ static xcb_visualtype_t *vistype; unlock_state_t unlock_state; auth_state_t auth_state; +static void string_append(char **string_ptr, const char *appended) { + char *tmp = NULL; + if (*string_ptr == NULL) { + if (asprintf(&tmp, "%s", appended) != -1) { + *string_ptr = tmp; + } + } else if (asprintf(&tmp, "%s, %s", *string_ptr, appended) != -1) { + free(*string_ptr); + *string_ptr = tmp; + } +} + +static void display_button_text( + cairo_t *ctx, const char *text, double y_offset, bool use_dark_text) { + cairo_text_extents_t extents; + double x, y; + + cairo_text_extents(ctx, text, &extents); + x = BUTTON_CENTER - ((extents.width / 2) + extents.x_bearing); + y = BUTTON_CENTER - ((extents.height / 2) + extents.y_bearing) + y_offset; + + cairo_move_to(ctx, x, y); + if (use_dark_text) { + cairo_set_source_rgb(ctx, 0., 0., 0.); + } else { + cairo_set_source_rgb(ctx, 1., 1., 1.); + } + cairo_show_text(ctx, text); + cairo_close_path(ctx); +} + +static void update_layout_string() { + if (layout_string) { + free(layout_string); + layout_string = NULL; + } + xkb_layout_index_t num_layouts = xkb_keymap_num_layouts(xkb_keymap); + for (xkb_layout_index_t i = 0; i < num_layouts; ++i) { + if (xkb_state_layout_index_is_active(xkb_state, i, XKB_STATE_LAYOUT_EFFECTIVE)) { + const char *name = xkb_keymap_layout_get_name(xkb_keymap, i); + if (name) { + string_append(&layout_string, name); + } + } + } +} + /* check_modifier_keys describes the currently active modifiers (Caps Lock, Alt, Num Lock or Super) in the modifier_string variable. */ static void check_modifier_keys(void) { @@ -111,15 +162,7 @@ static void check_modifier_keys(void) { * leak state about the password. */ continue; } - - char *tmp; - if (modifier_string == NULL) { - if (asprintf(&tmp, "%s", mod_name) != -1) - modifier_string = tmp; - } else if (asprintf(&tmp, "%s, %s", modifier_string, mod_name) != -1) { - free(modifier_string); - modifier_string = tmp; - } + string_append(&modifier_string, mod_name); } } @@ -208,6 +251,8 @@ void draw_image(xcb_pixmap_t bg_pixmap, uint32_t *resolution) { } cairo_fill_preserve(ctx); + bool use_dark_text = true; + switch (auth_state) { case STATE_AUTH_VERIFY: case STATE_AUTH_LOCK: @@ -224,6 +269,7 @@ void draw_image(xcb_pixmap_t bg_pixmap, uint32_t *resolution) { } cairo_set_source_rgb(ctx, 51.0 / 255, 125.0 / 255, 0); + use_dark_text = false; break; } cairo_stroke(ctx); @@ -280,31 +326,16 @@ void draw_image(xcb_pixmap_t bg_pixmap, uint32_t *resolution) { } if (text) { - cairo_text_extents_t extents; - double x, y; - - cairo_text_extents(ctx, text, &extents); - x = BUTTON_CENTER - ((extents.width / 2) + extents.x_bearing); - y = BUTTON_CENTER - ((extents.height / 2) + extents.y_bearing); - - cairo_move_to(ctx, x, y); - cairo_show_text(ctx, text); - cairo_close_path(ctx); + display_button_text(ctx, text, 0., use_dark_text); } if (modifier_string != NULL) { - cairo_text_extents_t extents; - double x, y; - cairo_set_font_size(ctx, 14.0); - - cairo_text_extents(ctx, modifier_string, &extents); - x = BUTTON_CENTER - ((extents.width / 2) + extents.x_bearing); - y = BUTTON_CENTER - ((extents.height / 2) + extents.y_bearing) + 28.0; - - cairo_move_to(ctx, x, y); - cairo_show_text(ctx, modifier_string); - cairo_close_path(ctx); + display_button_text(ctx, modifier_string, 28., use_dark_text); + } + if (show_keyboard_layout && layout_string != NULL) { + cairo_set_font_size(ctx, 14.0); + display_button_text(ctx, layout_string, -28., use_dark_text); } /* After the user pressed any valid key or the backspace key, we @@ -399,6 +430,7 @@ void redraw_screen(void) { modifier_string = NULL; } check_modifier_keys(); + update_layout_string(); if (bg_pixmap == XCB_NONE) { DEBUG("allocating pixmap for %d x %d px\n", last_resolution[0], last_resolution[1]);