summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG6
-rw-r--r--LICENSE2
-rw-r--r--README.md2
-rw-r--r--i3lock-extended.16
-rw-r--r--i3lock.c32
-rw-r--r--meson.build2
-rw-r--r--unlock_indicator.c94
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 @@
12024-04-12 i3lock-extended 2.2.15
2
3 • Fetch and sync with i3lock 2.15
4 • Update README.md
5
6
12023-03-18 i3lock-extended 2.2.14 72023-03-18 i3lock-extended 2.2.14
2 8
3 • Fetch and sync with i3lock 2.14.1 9 • 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 @@
1i3lock-extended 1i3lock-extended
2Copyright (C) 2020-2023 Simeon Simeonov 2Copyright (C) 2020-2024 Simeon Simeonov
3 3
4This program is free software: you can redistribute it and/or modify 4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by 5it 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
120 120
121## [License](https://github.com/blackm0re/i3lock-extended/blob/master/LICENSE) 121## [License](https://github.com/blackm0re/i3lock-extended/blob/master/LICENSE)
122 122
123Copyright 2020-2023 Simeon Simeonov 123Copyright 2020-2024 Simeon Simeonov
124 124
125Licensed under the GPLv3: http://www.gnu.org/licenses/gpl-3.0.html 125Licensed under the GPLv3: http://www.gnu.org/licenses/gpl-3.0.html
126 126
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 @@
8.fi 8.fi
9.. 9..
10 10
11.TH i3lock\-extended 1 "MARCH 2023" Linux "User Manuals" 11.TH i3lock\-extended 1 "APRIL 2024" Linux "User Manuals"
12 12
13.SH NAME 13.SH NAME
14i3lock\-extended \- improved screen locker 14i3lock\-extended \- improved screen locker
@@ -166,6 +166,10 @@ Display the given PNG image instead of a blank screen.
166Display text instead of elapsed time, using the same color and alignment. 166Display text instead of elapsed time, using the same color and alignment.
167 167
168.TP 168.TP
169.B \-k, \-\-show-keyboard-layout
170Show the current keyboard layout.
171
172.TP
169.B \-L, \-\-led\-clock 173.B \-L, \-\-led\-clock
170Display LED-clock. 174Display LED-clock.
171 175
diff --git a/i3lock.c b/i3lock.c
index aee9b2a..3f8eb77 100644
--- a/i3lock.c
+++ b/i3lock.c
@@ -1,6 +1,6 @@
1/* 1/*
2 * This file is part of i3lock-extended 2 * This file is part of i3lock-extended
3 * Copyright (C) 2020-2023 Simeon Simeonov 3 * Copyright (C) 2020-2024 Simeon Simeonov
4 4
5 * i3lock-extended is free software: you can redistribute it and/or modify 5 * i3lock-extended is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by 6 * it under the terms of the GNU General Public License as published by
@@ -130,6 +130,7 @@ extern unlock_state_t unlock_state;
130extern auth_state_t auth_state; 130extern auth_state_t auth_state;
131int failed_attempts = 0; 131int failed_attempts = 0;
132bool show_failed_attempts = false; 132bool show_failed_attempts = false;
133bool show_keyboard_layout = false;
133bool retry_verification = false; 134bool retry_verification = false;
134 135
135struct xkb_state *xkb_state; 136struct xkb_state *xkb_state;
@@ -162,6 +163,9 @@ static void u8_dec(char *s, int *i) {
162 * Necessary so that we can properly let xkbcommon track the keyboard state and 163 * Necessary so that we can properly let xkbcommon track the keyboard state and
163 * translate keypresses to utf-8. 164 * translate keypresses to utf-8.
164 * 165 *
166 * This function can be called when the user changes the XKB configuration,
167 * so it must not leave unusable global state behind
168 *
165 */ 169 */
166static bool load_keymap(void) { 170static bool load_keymap(void) {
167 if (xkb_context == NULL) { 171 if (xkb_context == NULL) {
@@ -171,25 +175,26 @@ static bool load_keymap(void) {
171 } 175 }
172 } 176 }
173 177
174 xkb_keymap_unref(xkb_keymap);
175
176 int32_t device_id = xkb_x11_get_core_keyboard_device_id(conn); 178 int32_t device_id = xkb_x11_get_core_keyboard_device_id(conn);
177 DEBUG("device = %d\n", device_id); 179 DEBUG("device = %d\n", device_id);
178 if ((xkb_keymap = xkb_x11_keymap_new_from_device(xkb_context, conn, device_id, 0)) == NULL) { 180 struct xkb_keymap *new_keymap = xkb_x11_keymap_new_from_device(xkb_context, conn, device_id, 0);
181 if (new_keymap == NULL) {
179 fprintf(stderr, "[i3lock] xkb_x11_keymap_new_from_device failed\n"); 182 fprintf(stderr, "[i3lock] xkb_x11_keymap_new_from_device failed\n");
180 return false; 183 return false;
181 } 184 }
182 185
183 struct xkb_state *new_state = 186 struct xkb_state *new_state =
184 xkb_x11_state_new_from_device(xkb_keymap, conn, device_id); 187 xkb_x11_state_new_from_device(new_keymap, conn, device_id);
185 if (new_state == NULL) { 188 if (new_state == NULL) {
186 fprintf(stderr, "[i3lock] xkb_x11_state_new_from_device failed\n"); 189 fprintf(stderr, "[i3lock] xkb_x11_state_new_from_device failed\n");
187 return false; 190 return false;
188 } 191 }
189 192
193 /* Only update global state on success */
190 xkb_state_unref(xkb_state); 194 xkb_state_unref(xkb_state);
195 xkb_keymap_unref(xkb_keymap);
191 xkb_state = new_state; 196 xkb_state = new_state;
192 197 xkb_keymap = new_keymap;
193 return true; 198 return true;
194} 199}
195 200
@@ -954,6 +959,7 @@ static void xcb_check_cb(EV_P_ ev_check *w, int revents) {
954 default: 959 default:
955 if (type == xkb_base_event) { 960 if (type == xkb_base_event) {
956 process_xkb_event(event); 961 process_xkb_event(event);
962 redraw_screen();
957 } 963 }
958 if (randr_base > -1 && 964 if (randr_base > -1 &&
959 type == randr_base + XCB_RANDR_SCREEN_CHANGE_NOTIFY) { 965 type == randr_base + XCB_RANDR_SCREEN_CHANGE_NOTIFY) {
@@ -1079,6 +1085,7 @@ int main(int argc, char *argv[]) {
1079 {"ignore-empty-password", no_argument, NULL, 'e'}, 1085 {"ignore-empty-password", no_argument, NULL, 'e'},
1080 {"inactivity-timeout", required_argument, NULL, 'I'}, 1086 {"inactivity-timeout", required_argument, NULL, 'I'},
1081 {"show-failed-attempts", no_argument, NULL, 'f'}, 1087 {"show-failed-attempts", no_argument, NULL, 'f'},
1088 {"show-keyboard-layout", no_argument, NULL, 'k'},
1082 {NULL, no_argument, NULL, 0}}; 1089 {NULL, no_argument, NULL, 0}};
1083 1090
1084 if ((pw = getpwuid(getuid())) == NULL) 1091 if ((pw = getpwuid(getuid())) == NULL)
@@ -1089,14 +1096,14 @@ int main(int argc, char *argv[]) {
1089 errx(EXIT_FAILURE, "i3lock is a program for X11 and does not work on Wayland. Try https://github.com/swaywm/swaylock instead"); 1096 errx(EXIT_FAILURE, "i3lock is a program for X11 and does not work on Wayland. Try https://github.com/swaywm/swaylock instead");
1090 1097
1091#ifdef EXTRAS 1098#ifdef EXTRAS
1092 char *optstring = "hvnbDdELC:c:B:G:F:J:O:R:r:S:T:W:X:x:Y:y:Z:p:ui:teI:f"; 1099 char *optstring = "hvnbDdELC:c:B:G:F:J:O:R:r:S:T:W:X:x:Y:y:Z:p:ui:teI:fk";
1093#else 1100#else
1094 char *optstring = "hvnbdc:p:ui:teI:f"; 1101 char *optstring = "hvnbdc:p:ui:teI:fk";
1095#endif 1102#endif
1096 while ((o = getopt_long(argc, argv, optstring, longopts, &longoptind)) != -1) { 1103 while ((o = getopt_long(argc, argv, optstring, longopts, &longoptind)) != -1) {
1097 switch (o) { 1104 switch (o) {
1098 case 'v': 1105 case 'v':
1099 errx(EXIT_SUCCESS, "version " I3LOCK_VERSION " © 2010 Michael Stapelberg, 2020-2023 Simeon Simeonov"); 1106 errx(EXIT_SUCCESS, "version " I3LOCK_VERSION " © 2010 Michael Stapelberg, 2020-2024 Simeon Simeonov");
1100 case 'n': 1107 case 'n':
1101 dont_fork = true; 1108 dont_fork = true;
1102 break; 1109 break;
@@ -1333,12 +1340,15 @@ int main(int argc, char *argv[]) {
1333 case 'f': 1340 case 'f':
1334 show_failed_attempts = true; 1341 show_failed_attempts = true;
1335 break; 1342 break;
1343 case 'k':
1344 show_keyboard_layout = true;
1345 break;
1336 default: 1346 default:
1337#ifdef EXTRAS 1347#ifdef EXTRAS
1338 errx( 1348 errx(
1339 EXIT_FAILURE, 1349 EXIT_FAILURE,
1340 "Syntax: i3lock-extended [-B color] [-b] [-C seconds] " 1350 "Syntax: i3lock-extended [-B color] [-b] [-C seconds] "
1341 "[-c color] [-D] [-d] [-E] [-e] [-F color] [-f] " 1351 "[-c color] [-D] [-d] [-E] [-e] [-F color] [-f] [-k]"
1342 "[-G color] [-h] [-I timeout] [-i image.png] [-J text] " 1352 "[-G color] [-h] [-I timeout] [-i image.png] [-J text] "
1343 "[-L] [-n] [-O color] [-p win|default] [-R color] " 1353 "[-L] [-n] [-O color] [-p win|default] [-R color] "
1344 "[-r refresh rate] [-S size] [-T template] [-t] [-u] [-v] " 1354 "[-r refresh rate] [-S size] [-T template] [-t] [-u] [-v] "
@@ -1347,7 +1357,7 @@ int main(int argc, char *argv[]) {
1347 "[-y vertical-alignment] [-Z vertical-alignment]"); 1357 "[-y vertical-alignment] [-Z vertical-alignment]");
1348#else 1358#else
1349 errx(EXIT_FAILURE, "Syntax: i3lock [-v] [-n] [-b] [-d] [-c color] [-u] [-p win|default]" 1359 errx(EXIT_FAILURE, "Syntax: i3lock [-v] [-n] [-b] [-d] [-c color] [-u] [-p win|default]"
1350 " [-i image.png] [-t] [-e] [-I timeout] [-f]"); 1360 " [-i image.png] [-t] [-e] [-I timeout] [-f] [-k]");
1351#endif 1361#endif
1352 } 1362 }
1353 } 1363 }
diff --git a/meson.build b/meson.build
index c3b4dc8..6960930 100644
--- a/meson.build
+++ b/meson.build
@@ -6,7 +6,7 @@
6project( 6project(
7 'i3lock-extended', 7 'i3lock-extended',
8 'c', 8 'c',
9 version: '2.2.14', 9 version: '2.2.15',
10 default_options: [ 10 default_options: [
11 'c_std=c11', 11 'c_std=c11',
12 'warning_level=1', # enable all warnings (-Wall) 12 '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 @@
1/* 1/*
2 * This file is part of i3lock-extended 2 * This file is part of i3lock-extended
3 * Copyright (C) 2020-2023 Simeon Simeonov 3 * Copyright (C) 2020-2024 Simeon Simeonov
4 4
5 * i3lock-extended is free software: you can redistribute it and/or modify 5 * i3lock-extended is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by 6 * it under the terms of the GNU General Public License as published by
@@ -90,6 +90,8 @@ extern bool unlock_indicator;
90 90
91/* List of pressed modifiers, or NULL if none are pressed. */ 91/* List of pressed modifiers, or NULL if none are pressed. */
92extern char *modifier_string; 92extern char *modifier_string;
93/* Name of the current keyboard layout or NULL if not initialized. */
94char *layout_string = NULL;
93 95
94/* A Cairo surface containing the specified image (-i), if any. */ 96/* A Cairo surface containing the specified image (-i), if any. */
95extern cairo_surface_t *img; 97extern cairo_surface_t *img;
@@ -101,6 +103,8 @@ extern char color[7];
101 103
102/* Whether the failed attempts should be displayed. */ 104/* Whether the failed attempts should be displayed. */
103extern bool show_failed_attempts; 105extern bool show_failed_attempts;
106/* Whether keyboard layout should be displayed. */
107extern bool show_keyboard_layout;
104/* Number of failed unlock attempts. */ 108/* Number of failed unlock attempts. */
105extern int failed_attempts; 109extern int failed_attempts;
106 110
@@ -126,6 +130,53 @@ static xcb_visualtype_t *vistype;
126unlock_state_t unlock_state; 130unlock_state_t unlock_state;
127auth_state_t auth_state; 131auth_state_t auth_state;
128 132
133static void string_append(char **string_ptr, const char *appended) {
134 char *tmp = NULL;
135 if (*string_ptr == NULL) {
136 if (asprintf(&tmp, "%s", appended) != -1) {
137 *string_ptr = tmp;
138 }
139 } else if (asprintf(&tmp, "%s, %s", *string_ptr, appended) != -1) {
140 free(*string_ptr);
141 *string_ptr = tmp;
142 }
143}
144
145static void display_button_text(
146 cairo_t *ctx, const char *text, double y_offset, bool use_dark_text) {
147 cairo_text_extents_t extents;
148 double x, y;
149
150 cairo_text_extents(ctx, text, &extents);
151 x = BUTTON_CENTER - ((extents.width / 2) + extents.x_bearing);
152 y = BUTTON_CENTER - ((extents.height / 2) + extents.y_bearing) + y_offset;
153
154 cairo_move_to(ctx, x, y);
155 if (use_dark_text) {
156 cairo_set_source_rgb(ctx, 0., 0., 0.);
157 } else {
158 cairo_set_source_rgb(ctx, 1., 1., 1.);
159 }
160 cairo_show_text(ctx, text);
161 cairo_close_path(ctx);
162}
163
164static void update_layout_string() {
165 if (layout_string) {
166 free(layout_string);
167 layout_string = NULL;
168 }
169 xkb_layout_index_t num_layouts = xkb_keymap_num_layouts(xkb_keymap);
170 for (xkb_layout_index_t i = 0; i < num_layouts; ++i) {
171 if (xkb_state_layout_index_is_active(xkb_state, i, XKB_STATE_LAYOUT_EFFECTIVE)) {
172 const char *name = xkb_keymap_layout_get_name(xkb_keymap, i);
173 if (name) {
174 string_append(&layout_string, name);
175 }
176 }
177 }
178}
179
129/* check_modifier_keys describes the currently active modifiers (Caps Lock, Alt, 180/* check_modifier_keys describes the currently active modifiers (Caps Lock, Alt,
130 Num Lock or Super) in the modifier_string variable. */ 181 Num Lock or Super) in the modifier_string variable. */
131static void check_modifier_keys(void) { 182static void check_modifier_keys(void) {
@@ -152,15 +203,7 @@ static void check_modifier_keys(void) {
152 * leak state about the password. */ 203 * leak state about the password. */
153 continue; 204 continue;
154 } 205 }
155 206 string_append(&modifier_string, mod_name);
156 char *tmp;
157 if (modifier_string == NULL) {
158 if (asprintf(&tmp, "%s", mod_name) != -1)
159 modifier_string = tmp;
160 } else if (asprintf(&tmp, "%s, %s", modifier_string, mod_name) != -1) {
161 free(modifier_string);
162 modifier_string = tmp;
163 }
164 } 207 }
165} 208}
166 209
@@ -249,6 +292,8 @@ void draw_image(xcb_pixmap_t bg_pixmap, uint32_t *resolution) {
249 } 292 }
250 cairo_fill_preserve(ctx); 293 cairo_fill_preserve(ctx);
251 294
295 bool use_dark_text = true;
296
252 switch (auth_state) { 297 switch (auth_state) {
253 case STATE_AUTH_VERIFY: 298 case STATE_AUTH_VERIFY:
254 case STATE_AUTH_LOCK: 299 case STATE_AUTH_LOCK:
@@ -265,6 +310,7 @@ void draw_image(xcb_pixmap_t bg_pixmap, uint32_t *resolution) {
265 } 310 }
266 311
267 cairo_set_source_rgb(ctx, 51.0 / 255, 125.0 / 255, 0); 312 cairo_set_source_rgb(ctx, 51.0 / 255, 125.0 / 255, 0);
313 use_dark_text = false;
268 break; 314 break;
269 } 315 }
270 cairo_stroke(ctx); 316 cairo_stroke(ctx);
@@ -321,31 +367,16 @@ void draw_image(xcb_pixmap_t bg_pixmap, uint32_t *resolution) {
321 } 367 }
322 368
323 if (text) { 369 if (text) {
324 cairo_text_extents_t extents; 370 display_button_text(ctx, text, 0., use_dark_text);
325 double x, y;
326
327 cairo_text_extents(ctx, text, &extents);
328 x = BUTTON_CENTER - ((extents.width / 2) + extents.x_bearing);
329 y = BUTTON_CENTER - ((extents.height / 2) + extents.y_bearing);
330
331 cairo_move_to(ctx, x, y);
332 cairo_show_text(ctx, text);
333 cairo_close_path(ctx);
334 } 371 }
335 372
336 if (modifier_string != NULL) { 373 if (modifier_string != NULL) {
337 cairo_text_extents_t extents;
338 double x, y;
339
340 cairo_set_font_size(ctx, 14.0); 374 cairo_set_font_size(ctx, 14.0);
341 375 display_button_text(ctx, modifier_string, 28., use_dark_text);
342 cairo_text_extents(ctx, modifier_string, &extents); 376 }
343 x = BUTTON_CENTER - ((extents.width / 2) + extents.x_bearing); 377 if (show_keyboard_layout && layout_string != NULL) {
344 y = BUTTON_CENTER - ((extents.height / 2) + extents.y_bearing) + 28.0; 378 cairo_set_font_size(ctx, 14.0);
345 379 display_button_text(ctx, layout_string, -28., use_dark_text);
346 cairo_move_to(ctx, x, y);
347 cairo_show_text(ctx, modifier_string);
348 cairo_close_path(ctx);
349 } 380 }
350 381
351 /* After the user pressed any valid key or the backspace key, we 382 /* After the user pressed any valid key or the backspace key, we
@@ -480,6 +511,7 @@ void redraw_screen(void) {
480 modifier_string = NULL; 511 modifier_string = NULL;
481 } 512 }
482 check_modifier_keys(); 513 check_modifier_keys();
514 update_layout_string();
483 515
484 if (bg_pixmap == XCB_NONE) { 516 if (bg_pixmap == XCB_NONE) {
485 DEBUG("allocating pixmap for %d x %d px\n", last_resolution[0], last_resolution[1]); 517 DEBUG("allocating pixmap for %d x %d px\n", last_resolution[0], last_resolution[1]);