aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Drew DeVault <sir@cmpwn.com>2018-04-03 14:31:30 -0400
committerLibravatar Drew DeVault <sir@cmpwn.com>2018-04-04 18:47:48 -0400
commit066143adef7adc6e76e43e1990db2f75fe984b42 (patch)
treef9509c14f04399bf02d2cc31ff62869a07691543
parentLink swaylock to xkbcommon (diff)
downloadsway-066143adef7adc6e76e43e1990db2f75fe984b42.tar.gz
sway-066143adef7adc6e76e43e1990db2f75fe984b42.tar.zst
sway-066143adef7adc6e76e43e1990db2f75fe984b42.zip
Add password buffer, refactor rendering/surfaces
-rw-r--r--common/meson.build1
-rw-r--r--common/unicode.c101
-rw-r--r--include/swaylock/swaylock.h15
-rw-r--r--include/unicode.h33
-rw-r--r--swaylock/main.c79
-rw-r--r--swaylock/meson.build2
-rw-r--r--swaylock/password.c57
-rw-r--r--swaylock/render.c21
-rw-r--r--swaylock/seat.c4
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
5size_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
16static const uint8_t masks[] = {
17 0x7F,
18 0x1F,
19 0x0F,
20 0x07,
21 0x03,
22 0x01
23};
24
25uint32_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
51size_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
79static 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
93int 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
18struct swaylock_password {
19 size_t size;
20 size_t len;
21 char *buffer;
22};
23
18struct swaylock_state { 24struct 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
29struct swaylock_context { 36struct 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
48void swaylock_handle_key(struct swaylock_state *state,
49 xkb_keysym_t keysym, uint32_t codepoint);
50void 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 */
15uint32_t utf8_decode(const char **str);
16
17/**
18 * Encodes a character as UTF-8 and returns the length of that character.
19 */
20size_t utf8_encode(char *str, uint32_t ch);
21
22/**
23 * Returns the size of the next UTF-8 character
24 */
25int utf8_size(const char *str);
26
27/**
28 * Returns the size of a UTF-8 character
29 */
30size_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
35static 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
52static void layer_surface_configure(void *data, 35static 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
62static void layer_surface_closed(void *data, 45static 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
70static const struct zwlr_layer_surface_v1_listener layer_surface_listener = { 53static 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 @@
1executable( 1executable(
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
10static void backspace(struct swaylock_password *pw) {
11 if (pw->len != 0) {
12 pw->buffer[--pw->len] = 0;
13 }
14}
15
16static 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
41void 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
6void 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
79static void keyboard_modifiers(void *data, struct wl_keyboard *wl_keyboard, 81static void keyboard_modifiers(void *data, struct wl_keyboard *wl_keyboard,