From 040c13e2b9b59895368930cd74d0943d43418383 Mon Sep 17 00:00:00 2001 From: Simeon Simeonov Date: Fri, 12 Apr 2024 11:22:31 +0200 Subject: Sync with upstream 2.15 and update the documentation --- CHANGELOG | 6 ++++ LICENSE | 2 +- README.md | 2 +- i3lock-extended.1 | 6 +++- i3lock.c | 32 ++++++++++++------- meson.build | 2 +- unlock_indicator.c | 94 ++++++++++++++++++++++++++++++++++++------------------ 7 files changed, 98 insertions(+), 46 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 126cf58..258177d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,9 @@ +2024-04-12 i3lock-extended 2.2.15 + + • Fetch and sync with i3lock 2.15 + • Update README.md + + 2023-03-18 i3lock-extended 2.2.14 • Fetch and sync with i3lock 2.14.1 diff --git a/LICENSE b/LICENSE index 8b98561..7f9e06e 100644 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,5 @@ i3lock-extended -Copyright (C) 2020-2023 Simeon Simeonov +Copyright (C) 2020-2024 Simeon Simeonov This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/README.md b/README.md index 9ea58fe..e8a35d0 100644 --- a/README.md +++ b/README.md @@ -120,7 +120,7 @@ Simeon Simeonov - sgs @ LiberaChat ## [License](https://github.com/blackm0re/i3lock-extended/blob/master/LICENSE) -Copyright 2020-2023 Simeon Simeonov +Copyright 2020-2024 Simeon Simeonov Licensed under the GPLv3: http://www.gnu.org/licenses/gpl-3.0.html diff --git a/i3lock-extended.1 b/i3lock-extended.1 index dbac52a..5a15f42 100644 --- a/i3lock-extended.1 +++ b/i3lock-extended.1 @@ -8,7 +8,7 @@ .fi .. -.TH i3lock\-extended 1 "MARCH 2023" Linux "User Manuals" +.TH i3lock\-extended 1 "APRIL 2024" Linux "User Manuals" .SH NAME i3lock\-extended \- improved screen locker @@ -165,6 +165,10 @@ Display the given PNG image instead of a blank screen. .BI \-J\ text \fR,\ \fB\-\-display\-text= text Display text instead of elapsed time, using the same color and alignment. +.TP +.B \-k, \-\-show-keyboard-layout +Show the current keyboard layout. + .TP .B \-L, \-\-led\-clock Display LED-clock. diff --git a/i3lock.c b/i3lock.c index aee9b2a..3f8eb77 100644 --- a/i3lock.c +++ b/i3lock.c @@ -1,6 +1,6 @@ /* * This file is part of i3lock-extended - * Copyright (C) 2020-2023 Simeon Simeonov + * Copyright (C) 2020-2024 Simeon Simeonov * i3lock-extended is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -130,6 +130,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; @@ -162,6 +163,9 @@ static void u8_dec(char *s, int *i) { * Necessary so that we can properly let xkbcommon track the keyboard state and * translate keypresses to utf-8. * + * This function can be called when the user changes the XKB configuration, + * so it must not leave unusable global state behind + * */ static bool load_keymap(void) { if (xkb_context == NULL) { @@ -171,25 +175,26 @@ static bool load_keymap(void) { } } - xkb_keymap_unref(xkb_keymap); - int32_t device_id = xkb_x11_get_core_keyboard_device_id(conn); DEBUG("device = %d\n", device_id); - if ((xkb_keymap = xkb_x11_keymap_new_from_device(xkb_context, conn, device_id, 0)) == NULL) { + struct xkb_keymap *new_keymap = xkb_x11_keymap_new_from_device(xkb_context, conn, device_id, 0); + if (new_keymap == NULL) { fprintf(stderr, "[i3lock] xkb_x11_keymap_new_from_device failed\n"); return false; } struct xkb_state *new_state = - xkb_x11_state_new_from_device(xkb_keymap, conn, device_id); + xkb_x11_state_new_from_device(new_keymap, conn, device_id); if (new_state == NULL) { fprintf(stderr, "[i3lock] xkb_x11_state_new_from_device failed\n"); return false; } + /* Only update global state on success */ xkb_state_unref(xkb_state); + xkb_keymap_unref(xkb_keymap); xkb_state = new_state; - + xkb_keymap = new_keymap; return true; } @@ -954,6 +959,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) { @@ -1079,6 +1085,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) @@ -1089,14 +1096,14 @@ int main(int argc, char *argv[]) { errx(EXIT_FAILURE, "i3lock is a program for X11 and does not work on Wayland. Try https://github.com/swaywm/swaylock instead"); #ifdef EXTRAS - char *optstring = "hvnbDdELC:c:B:G:F:J:O:R:r:S:T:W:X:x:Y:y:Z:p:ui:teI:f"; + char *optstring = "hvnbDdELC:c:B:G:F:J:O:R:r:S:T:W:X:x:Y:y:Z:p:ui:teI:fk"; #else - char *optstring = "hvnbdc:p:ui:teI:f"; + char *optstring = "hvnbdc:p:ui:teI:fk"; #endif while ((o = getopt_long(argc, argv, optstring, longopts, &longoptind)) != -1) { switch (o) { case 'v': - errx(EXIT_SUCCESS, "version " I3LOCK_VERSION " © 2010 Michael Stapelberg, 2020-2023 Simeon Simeonov"); + errx(EXIT_SUCCESS, "version " I3LOCK_VERSION " © 2010 Michael Stapelberg, 2020-2024 Simeon Simeonov"); case 'n': dont_fork = true; break; @@ -1333,12 +1340,15 @@ int main(int argc, char *argv[]) { case 'f': show_failed_attempts = true; break; + case 'k': + show_keyboard_layout = true; + break; default: #ifdef EXTRAS errx( EXIT_FAILURE, "Syntax: i3lock-extended [-B color] [-b] [-C seconds] " - "[-c color] [-D] [-d] [-E] [-e] [-F color] [-f] " + "[-c color] [-D] [-d] [-E] [-e] [-F color] [-f] [-k]" "[-G color] [-h] [-I timeout] [-i image.png] [-J text] " "[-L] [-n] [-O color] [-p win|default] [-R color] " "[-r refresh rate] [-S size] [-T template] [-t] [-u] [-v] " @@ -1347,7 +1357,7 @@ int main(int argc, char *argv[]) { "[-y vertical-alignment] [-Z vertical-alignment]"); #else 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]"); #endif } } diff --git a/meson.build b/meson.build index c3b4dc8..6960930 100644 --- a/meson.build +++ b/meson.build @@ -6,7 +6,7 @@ project( 'i3lock-extended', 'c', - version: '2.2.14', + version: '2.2.15', default_options: [ 'c_std=c11', 'warning_level=1', # enable all warnings (-Wall) diff --git a/unlock_indicator.c b/unlock_indicator.c index 6f6fbf7..7d620fd 100644 --- a/unlock_indicator.c +++ b/unlock_indicator.c @@ -1,6 +1,6 @@ /* * This file is part of i3lock-extended - * Copyright (C) 2020-2023 Simeon Simeonov + * Copyright (C) 2020-2024 Simeon Simeonov * i3lock-extended is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -90,6 +90,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; @@ -101,6 +103,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; @@ -126,6 +130,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) { @@ -152,15 +203,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); } } @@ -249,6 +292,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: @@ -265,6 +310,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); @@ -321,31 +367,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 @@ -480,6 +511,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]); -- cgit v1.3