diff options
author | Drew DeVault <sir@cmpwn.com> | 2018-04-03 14:31:30 -0400 |
---|---|---|
committer | Drew DeVault <sir@cmpwn.com> | 2018-04-04 18:47:48 -0400 |
commit | 066143adef7adc6e76e43e1990db2f75fe984b42 (patch) | |
tree | f9509c14f04399bf02d2cc31ff62869a07691543 | |
parent | Link swaylock to xkbcommon (diff) | |
download | sway-066143adef7adc6e76e43e1990db2f75fe984b42.tar.gz sway-066143adef7adc6e76e43e1990db2f75fe984b42.tar.zst sway-066143adef7adc6e76e43e1990db2f75fe984b42.zip |
Add password buffer, refactor rendering/surfaces
-rw-r--r-- | common/meson.build | 1 | ||||
-rw-r--r-- | common/unicode.c | 101 | ||||
-rw-r--r-- | include/swaylock/swaylock.h | 15 | ||||
-rw-r--r-- | include/unicode.h | 33 | ||||
-rw-r--r-- | swaylock/main.c | 79 | ||||
-rw-r--r-- | swaylock/meson.build | 2 | ||||
-rw-r--r-- | swaylock/password.c | 57 | ||||
-rw-r--r-- | swaylock/render.c | 21 | ||||
-rw-r--r-- | swaylock/seat.c | 4 |
9 files changed, 262 insertions, 51 deletions
diff --git a/common/meson.build b/common/meson.build index 851e7bbf..44a29508 100644 --- a/common/meson.build +++ b/common/meson.build | |||
@@ -9,6 +9,7 @@ lib_sway_common = static_library( | |||
9 | 'pango.c', | 9 | 'pango.c', |
10 | 'readline.c', | 10 | 'readline.c', |
11 | 'stringop.c', | 11 | 'stringop.c', |
12 | 'unicode.c', | ||
12 | 'util.c' | 13 | 'util.c' |
13 | ), | 14 | ), |
14 | dependencies: [ | 15 | dependencies: [ |
diff --git a/common/unicode.c b/common/unicode.c new file mode 100644 index 00000000..38a9b48e --- /dev/null +++ b/common/unicode.c | |||
@@ -0,0 +1,101 @@ | |||
1 | #include <stdint.h> | ||
2 | #include <stddef.h> | ||
3 | #include "unicode.h" | ||
4 | |||
5 | size_t utf8_chsize(uint32_t ch) { | ||
6 | if (ch < 0x80) { | ||
7 | return 1; | ||
8 | } else if (ch < 0x800) { | ||
9 | return 2; | ||
10 | } else if (ch < 0x10000) { | ||
11 | return 3; | ||
12 | } | ||
13 | return 4; | ||
14 | } | ||
15 | |||
16 | static const uint8_t masks[] = { | ||
17 | 0x7F, | ||
18 | 0x1F, | ||
19 | 0x0F, | ||
20 | 0x07, | ||
21 | 0x03, | ||
22 | 0x01 | ||
23 | }; | ||
24 | |||
25 | uint32_t utf8_decode(const char **char_str) { | ||
26 | uint8_t **s = (uint8_t **)char_str; | ||
27 | |||
28 | uint32_t cp = 0; | ||
29 | if (**s < 128) { | ||
30 | // shortcut | ||
31 | cp = **s; | ||
32 | ++*s; | ||
33 | return cp; | ||
34 | } | ||
35 | int size = utf8_size((char *)*s); | ||
36 | if (size == -1) { | ||
37 | ++*s; | ||
38 | return UTF8_INVALID; | ||
39 | } | ||
40 | uint8_t mask = masks[size - 1]; | ||
41 | cp = **s & mask; | ||
42 | ++*s; | ||
43 | while (--size) { | ||
44 | cp <<= 6; | ||
45 | cp |= **s & 0x3f; | ||
46 | ++*s; | ||
47 | } | ||
48 | return cp; | ||
49 | } | ||
50 | |||
51 | size_t utf8_encode(char *str, uint32_t ch) { | ||
52 | size_t len = 0; | ||
53 | uint8_t first; | ||
54 | |||
55 | if (ch < 0x80) { | ||
56 | first = 0; | ||
57 | len = 1; | ||
58 | } else if (ch < 0x800) { | ||
59 | first = 0xc0; | ||
60 | len = 2; | ||
61 | } else if (ch < 0x10000) { | ||
62 | first = 0xe0; | ||
63 | len = 3; | ||
64 | } else { | ||
65 | first = 0xf0; | ||
66 | len = 4; | ||
67 | } | ||
68 | |||
69 | for (size_t i = len - 1; i > 0; --i) { | ||
70 | str[i] = (ch & 0x3f) | 0x80; | ||
71 | ch >>= 6; | ||
72 | } | ||
73 | |||
74 | str[0] = ch | first; | ||
75 | return len; | ||
76 | } | ||
77 | |||
78 | |||
79 | static const struct { | ||
80 | uint8_t mask; | ||
81 | uint8_t result; | ||
82 | int octets; | ||
83 | } sizes[] = { | ||
84 | { 0x80, 0x00, 1 }, | ||
85 | { 0xE0, 0xC0, 2 }, | ||
86 | { 0xF0, 0xE0, 3 }, | ||
87 | { 0xF8, 0xF0, 4 }, | ||
88 | { 0xFC, 0xF8, 5 }, | ||
89 | { 0xFE, 0xF8, 6 }, | ||
90 | { 0x80, 0x80, -1 }, | ||
91 | }; | ||
92 | |||
93 | int utf8_size(const char *s) { | ||
94 | uint8_t c = (uint8_t)*s; | ||
95 | for (size_t i = 0; i < sizeof(sizes) / 2; ++i) { | ||
96 | if ((c & sizes[i].mask) == sizes[i].result) { | ||
97 | return sizes[i].octets; | ||
98 | } | ||
99 | } | ||
100 | return -1; | ||
101 | } | ||
diff --git a/include/swaylock/swaylock.h b/include/swaylock/swaylock.h index e2673aae..f3b0b58b 100644 --- a/include/swaylock/swaylock.h +++ b/include/swaylock/swaylock.h | |||
@@ -15,18 +15,25 @@ struct swaylock_args { | |||
15 | bool show_indicator; | 15 | bool show_indicator; |
16 | }; | 16 | }; |
17 | 17 | ||
18 | struct swaylock_password { | ||
19 | size_t size; | ||
20 | size_t len; | ||
21 | char *buffer; | ||
22 | }; | ||
23 | |||
18 | struct swaylock_state { | 24 | struct swaylock_state { |
19 | struct wl_display *display; | 25 | struct wl_display *display; |
20 | struct wl_compositor *compositor; | 26 | struct wl_compositor *compositor; |
21 | struct zwlr_layer_shell_v1 *layer_shell; | 27 | struct zwlr_layer_shell_v1 *layer_shell; |
22 | struct wl_shm *shm; | 28 | struct wl_shm *shm; |
23 | struct wl_list contexts; | 29 | struct wl_list surfaces; |
24 | struct swaylock_args args; | 30 | struct swaylock_args args; |
31 | struct swaylock_password password; | ||
25 | struct swaylock_xkb xkb; | 32 | struct swaylock_xkb xkb; |
26 | bool run_display; | 33 | bool run_display; |
27 | }; | 34 | }; |
28 | 35 | ||
29 | struct swaylock_context { | 36 | struct swaylock_surface { |
30 | cairo_surface_t *image; | 37 | cairo_surface_t *image; |
31 | struct swaylock_state *state; | 38 | struct swaylock_state *state; |
32 | struct wl_output *output; | 39 | struct wl_output *output; |
@@ -38,4 +45,8 @@ struct swaylock_context { | |||
38 | struct wl_list link; | 45 | struct wl_list link; |
39 | }; | 46 | }; |
40 | 47 | ||
48 | void swaylock_handle_key(struct swaylock_state *state, | ||
49 | xkb_keysym_t keysym, uint32_t codepoint); | ||
50 | void render_frame(struct swaylock_surface *surface); | ||
51 | |||
41 | #endif | 52 | #endif |
diff --git a/include/unicode.h b/include/unicode.h new file mode 100644 index 00000000..e2ee9588 --- /dev/null +++ b/include/unicode.h | |||
@@ -0,0 +1,33 @@ | |||
1 | #ifndef _SWAY_UNICODE_H | ||
2 | #define _SWAY_UNICODE_H | ||
3 | #include <stddef.h> | ||
4 | #include <stdint.h> | ||
5 | |||
6 | // Technically UTF-8 supports up to 6 byte codepoints, but Unicode itself | ||
7 | // doesn't really bother with more than 4. | ||
8 | #define UTF8_MAX_SIZE 4 | ||
9 | |||
10 | #define UTF8_INVALID 0x80 | ||
11 | |||
12 | /** | ||
13 | * Grabs the next UTF-8 character and advances the string pointer | ||
14 | */ | ||
15 | uint32_t utf8_decode(const char **str); | ||
16 | |||
17 | /** | ||
18 | * Encodes a character as UTF-8 and returns the length of that character. | ||
19 | */ | ||
20 | size_t utf8_encode(char *str, uint32_t ch); | ||
21 | |||
22 | /** | ||
23 | * Returns the size of the next UTF-8 character | ||
24 | */ | ||
25 | int utf8_size(const char *str); | ||
26 | |||
27 | /** | ||
28 | * Returns the size of a UTF-8 character | ||
29 | */ | ||
30 | size_t utf8_chsize(uint32_t ch); | ||
31 | |||
32 | #endif | ||
33 | |||
diff --git a/swaylock/main.c b/swaylock/main.c index 7602e47e..c8fdc2f4 100644 --- a/swaylock/main.c +++ b/swaylock/main.c | |||
@@ -32,39 +32,22 @@ static void daemonize() { | |||
32 | } | 32 | } |
33 | } | 33 | } |
34 | 34 | ||
35 | static void render_frame(struct swaylock_context *context) { | ||
36 | struct swaylock_state *state = context->state; | ||
37 | context->current_buffer = get_next_buffer(state->shm, | ||
38 | context->buffers, context->width, context->height); | ||
39 | cairo_t *cairo = context->current_buffer->cairo; | ||
40 | if (state->args.mode == BACKGROUND_MODE_SOLID_COLOR) { | ||
41 | cairo_set_source_u32(cairo, state->args.color); | ||
42 | cairo_paint(cairo); | ||
43 | } else { | ||
44 | render_background_image(cairo, context->image, | ||
45 | state->args.mode, context->width, context->height); | ||
46 | } | ||
47 | wl_surface_attach(context->surface, context->current_buffer->buffer, 0, 0); | ||
48 | wl_surface_damage(context->surface, 0, 0, context->width, context->height); | ||
49 | wl_surface_commit(context->surface); | ||
50 | } | ||
51 | |||
52 | static void layer_surface_configure(void *data, | 35 | static void layer_surface_configure(void *data, |
53 | struct zwlr_layer_surface_v1 *surface, | 36 | struct zwlr_layer_surface_v1 *layer_surface, |
54 | uint32_t serial, uint32_t width, uint32_t height) { | 37 | uint32_t serial, uint32_t width, uint32_t height) { |
55 | struct swaylock_context *context = data; | 38 | struct swaylock_surface *surface = data; |
56 | context->width = width; | 39 | surface->width = width; |
57 | context->height = height; | 40 | surface->height = height; |
58 | zwlr_layer_surface_v1_ack_configure(surface, serial); | 41 | zwlr_layer_surface_v1_ack_configure(layer_surface, serial); |
59 | render_frame(context); | 42 | render_frame(surface); |
60 | } | 43 | } |
61 | 44 | ||
62 | static void layer_surface_closed(void *data, | 45 | static void layer_surface_closed(void *data, |
63 | struct zwlr_layer_surface_v1 *surface) { | 46 | struct zwlr_layer_surface_v1 *layer_surface) { |
64 | struct swaylock_context *context = data; | 47 | struct swaylock_surface *surface = data; |
65 | zwlr_layer_surface_v1_destroy(context->layer_surface); | 48 | zwlr_layer_surface_v1_destroy(surface->layer_surface); |
66 | wl_surface_destroy(context->surface); | 49 | wl_surface_destroy(surface->surface); |
67 | context->state->run_display = false; | 50 | surface->state->run_display = false; |
68 | } | 51 | } |
69 | 52 | ||
70 | static const struct zwlr_layer_surface_v1_listener layer_surface_listener = { | 53 | static const struct zwlr_layer_surface_v1_listener layer_surface_listener = { |
@@ -89,12 +72,12 @@ static void handle_global(void *data, struct wl_registry *registry, | |||
89 | state->layer_shell = wl_registry_bind( | 72 | state->layer_shell = wl_registry_bind( |
90 | registry, name, &zwlr_layer_shell_v1_interface, 1); | 73 | registry, name, &zwlr_layer_shell_v1_interface, 1); |
91 | } else if (strcmp(interface, wl_output_interface.name) == 0) { | 74 | } else if (strcmp(interface, wl_output_interface.name) == 0) { |
92 | struct swaylock_context *context = | 75 | struct swaylock_surface *surface = |
93 | calloc(1, sizeof(struct swaylock_context)); | 76 | calloc(1, sizeof(struct swaylock_surface)); |
94 | context->state = state; | 77 | surface->state = state; |
95 | context->output = wl_registry_bind(registry, name, | 78 | surface->output = wl_registry_bind(registry, name, |
96 | &wl_output_interface, 1); | 79 | &wl_output_interface, 1); |
97 | wl_list_insert(&state->contexts, &context->link); | 80 | wl_list_insert(&state->surfaces, &surface->link); |
98 | } | 81 | } |
99 | } | 82 | } |
100 | 83 | ||
@@ -198,7 +181,7 @@ int main(int argc, char **argv) { | |||
198 | } | 181 | } |
199 | } | 182 | } |
200 | 183 | ||
201 | wl_list_init(&state.contexts); | 184 | wl_list_init(&state.surfaces); |
202 | state.xkb.context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); | 185 | state.xkb.context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); |
203 | assert(state.display = wl_display_connect(NULL)); | 186 | assert(state.display = wl_display_connect(NULL)); |
204 | 187 | ||
@@ -207,33 +190,33 @@ int main(int argc, char **argv) { | |||
207 | wl_display_roundtrip(state.display); | 190 | wl_display_roundtrip(state.display); |
208 | assert(state.compositor && state.layer_shell && state.shm); | 191 | assert(state.compositor && state.layer_shell && state.shm); |
209 | 192 | ||
210 | if (wl_list_empty(&state.contexts)) { | 193 | if (wl_list_empty(&state.surfaces)) { |
211 | wlr_log(L_DEBUG, "Exiting - no outputs to show on."); | 194 | wlr_log(L_DEBUG, "Exiting - no outputs to show on."); |
212 | return 0; | 195 | return 0; |
213 | } | 196 | } |
214 | 197 | ||
215 | struct swaylock_context *context; | 198 | struct swaylock_surface *surface; |
216 | wl_list_for_each(context, &state.contexts, link) { | 199 | wl_list_for_each(surface, &state.surfaces, link) { |
217 | assert(context->surface = | 200 | assert(surface->surface = |
218 | wl_compositor_create_surface(state.compositor)); | 201 | wl_compositor_create_surface(state.compositor)); |
219 | 202 | ||
220 | context->layer_surface = zwlr_layer_shell_v1_get_layer_surface( | 203 | surface->layer_surface = zwlr_layer_shell_v1_get_layer_surface( |
221 | state.layer_shell, context->surface, context->output, | 204 | state.layer_shell, surface->surface, surface->output, |
222 | ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, "lockscreen"); | 205 | ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, "lockscreen"); |
223 | assert(context->layer_surface); | 206 | assert(surface->layer_surface); |
224 | 207 | ||
225 | zwlr_layer_surface_v1_set_size(context->layer_surface, 0, 0); | 208 | zwlr_layer_surface_v1_set_size(surface->layer_surface, 0, 0); |
226 | zwlr_layer_surface_v1_set_anchor(context->layer_surface, | 209 | zwlr_layer_surface_v1_set_anchor(surface->layer_surface, |
227 | ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | | 210 | ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | |
228 | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | | 211 | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | |
229 | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM | | 212 | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM | |
230 | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT); | 213 | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT); |
231 | zwlr_layer_surface_v1_set_exclusive_zone(context->layer_surface, -1); | 214 | zwlr_layer_surface_v1_set_exclusive_zone(surface->layer_surface, -1); |
232 | zwlr_layer_surface_v1_set_keyboard_interactivity( | 215 | zwlr_layer_surface_v1_set_keyboard_interactivity( |
233 | context->layer_surface, true); | 216 | surface->layer_surface, true); |
234 | zwlr_layer_surface_v1_add_listener(context->layer_surface, | 217 | zwlr_layer_surface_v1_add_listener(surface->layer_surface, |
235 | &layer_surface_listener, context); | 218 | &layer_surface_listener, surface); |
236 | wl_surface_commit(context->surface); | 219 | wl_surface_commit(surface->surface); |
237 | wl_display_roundtrip(state.display); | 220 | wl_display_roundtrip(state.display); |
238 | } | 221 | } |
239 | 222 | ||
diff --git a/swaylock/meson.build b/swaylock/meson.build index 2a1f029a..3cde47a4 100644 --- a/swaylock/meson.build +++ b/swaylock/meson.build | |||
@@ -1,6 +1,8 @@ | |||
1 | executable( | 1 | executable( |
2 | 'swaylock', [ | 2 | 'swaylock', [ |
3 | 'main.c', | 3 | 'main.c', |
4 | 'password.c', | ||
5 | 'render.c', | ||
4 | 'seat.c' | 6 | 'seat.c' |
5 | ], | 7 | ], |
6 | include_directories: [sway_inc], | 8 | include_directories: [sway_inc], |
diff --git a/swaylock/password.c b/swaylock/password.c new file mode 100644 index 00000000..da67205d --- /dev/null +++ b/swaylock/password.c | |||
@@ -0,0 +1,57 @@ | |||
1 | #include <assert.h> | ||
2 | #include <stdlib.h> | ||
3 | #include <unistd.h> | ||
4 | #include <wlr/util/log.h> | ||
5 | #include <xkbcommon/xkbcommon.h> | ||
6 | #include "swaylock/swaylock.h" | ||
7 | #include "swaylock/seat.h" | ||
8 | #include "unicode.h" | ||
9 | |||
10 | static void backspace(struct swaylock_password *pw) { | ||
11 | if (pw->len != 0) { | ||
12 | pw->buffer[--pw->len] = 0; | ||
13 | } | ||
14 | } | ||
15 | |||
16 | static void append_ch(struct swaylock_password *pw, uint32_t codepoint) { | ||
17 | if (!pw->buffer) { | ||
18 | pw->size = 8; | ||
19 | if (!(pw->buffer = malloc(pw->size))) { | ||
20 | // TODO: Display error | ||
21 | return; | ||
22 | } | ||
23 | pw->buffer[0] = 0; | ||
24 | } | ||
25 | size_t utf8_size = utf8_chsize(codepoint); | ||
26 | if (pw->len + utf8_size + 1 >= pw->size) { | ||
27 | size_t size = pw->size * 2; | ||
28 | char *buffer = realloc(pw->buffer, size); | ||
29 | if (!buffer) { | ||
30 | // TODO: Display error | ||
31 | return; | ||
32 | } | ||
33 | pw->size = size; | ||
34 | pw->buffer = buffer; | ||
35 | } | ||
36 | utf8_encode(&pw->buffer[pw->len], codepoint); | ||
37 | pw->buffer[pw->len + utf8_size] = 0; | ||
38 | pw->len += utf8_size; | ||
39 | } | ||
40 | |||
41 | void swaylock_handle_key(struct swaylock_state *state, | ||
42 | xkb_keysym_t keysym, uint32_t codepoint) { | ||
43 | switch (keysym) { | ||
44 | case XKB_KEY_KP_Enter: /* fallthrough */ | ||
45 | case XKB_KEY_Return: | ||
46 | // TODO: Attempt password | ||
47 | break; | ||
48 | case XKB_KEY_BackSpace: | ||
49 | backspace(&state->password); | ||
50 | break; | ||
51 | default: | ||
52 | if (codepoint) { | ||
53 | append_ch(&state->password, codepoint); | ||
54 | } | ||
55 | break; | ||
56 | } | ||
57 | } | ||
diff --git a/swaylock/render.c b/swaylock/render.c new file mode 100644 index 00000000..8fc47281 --- /dev/null +++ b/swaylock/render.c | |||
@@ -0,0 +1,21 @@ | |||
1 | #include <wayland-client.h> | ||
2 | #include "cairo.h" | ||
3 | #include "background-image.h" | ||
4 | #include "swaylock/swaylock.h" | ||
5 | |||
6 | void render_frame(struct swaylock_surface *surface) { | ||
7 | struct swaylock_state *state = surface->state; | ||
8 | surface->current_buffer = get_next_buffer(state->shm, | ||
9 | surface->buffers, surface->width, surface->height); | ||
10 | cairo_t *cairo = surface->current_buffer->cairo; | ||
11 | if (state->args.mode == BACKGROUND_MODE_SOLID_COLOR) { | ||
12 | cairo_set_source_u32(cairo, state->args.color); | ||
13 | cairo_paint(cairo); | ||
14 | } else { | ||
15 | render_background_image(cairo, surface->image, | ||
16 | state->args.mode, surface->width, surface->height); | ||
17 | } | ||
18 | wl_surface_attach(surface->surface, surface->current_buffer->buffer, 0, 0); | ||
19 | wl_surface_damage(surface->surface, 0, 0, surface->width, surface->height); | ||
20 | wl_surface_commit(surface->surface); | ||
21 | } | ||
diff --git a/swaylock/seat.c b/swaylock/seat.c index 522200f2..6c46bb41 100644 --- a/swaylock/seat.c +++ b/swaylock/seat.c | |||
@@ -73,7 +73,9 @@ static void keyboard_key(void *data, struct wl_keyboard *wl_keyboard, | |||
73 | uint32_t keycode = key_state == WL_KEYBOARD_KEY_STATE_PRESSED ? | 73 | uint32_t keycode = key_state == WL_KEYBOARD_KEY_STATE_PRESSED ? |
74 | key + 8 : 0; | 74 | key + 8 : 0; |
75 | uint32_t codepoint = xkb_state_key_get_utf32(state->xkb.state, keycode); | 75 | uint32_t codepoint = xkb_state_key_get_utf32(state->xkb.state, keycode); |
76 | wlr_log(L_DEBUG, "%c %d", codepoint, sym); | 76 | if (key_state == WL_KEYBOARD_KEY_STATE_PRESSED) { |
77 | swaylock_handle_key(state, sym, codepoint); | ||
78 | } | ||
77 | } | 79 | } |
78 | 80 | ||
79 | static void keyboard_modifiers(void *data, struct wl_keyboard *wl_keyboard, | 81 | static void keyboard_modifiers(void *data, struct wl_keyboard *wl_keyboard, |