aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDrew DeVault <sir@cmpwn.com>2018-04-03 14:31:30 -0400
committerDrew DeVault <sir@cmpwn.com>2018-04-04 18:47:48 -0400
commit066143adef7adc6e76e43e1990db2f75fe984b42 (patch)
treef9509c14f04399bf02d2cc31ff62869a07691543
parent1fe3cb8965e70f8f05f28512e66d76c49453a196 (diff)
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(
'pango.c',
'readline.c',
'stringop.c',
+ 'unicode.c',
'util.c'
),
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 @@
+#include <stdint.h>
+#include <stddef.h>
+#include "unicode.h"
+
+size_t utf8_chsize(uint32_t ch) {
+ if (ch < 0x80) {
+ return 1;
+ } else if (ch < 0x800) {
+ return 2;
+ } else if (ch < 0x10000) {
+ return 3;
+ }
+ return 4;
+}
+
+static const uint8_t masks[] = {
+ 0x7F,
+ 0x1F,
+ 0x0F,
+ 0x07,
+ 0x03,
+ 0x01
+};
+
+uint32_t utf8_decode(const char **char_str) {
+ uint8_t **s = (uint8_t **)char_str;
+
+ uint32_t cp = 0;
+ if (**s < 128) {
+ // shortcut
+ cp = **s;
+ ++*s;
+ return cp;
+ }
+ int size = utf8_size((char *)*s);
+ if (size == -1) {
+ ++*s;
+ return UTF8_INVALID;
+ }
+ uint8_t mask = masks[size - 1];
+ cp = **s & mask;
+ ++*s;
+ while (--size) {
+ cp <<= 6;
+ cp |= **s & 0x3f;
+ ++*s;
+ }
+ return cp;
+}
+
+size_t utf8_encode(char *str, uint32_t ch) {
+ size_t len = 0;
+ uint8_t first;
+
+ if (ch < 0x80) {
+ first = 0;
+ len = 1;
+ } else if (ch < 0x800) {
+ first = 0xc0;
+ len = 2;
+ } else if (ch < 0x10000) {
+ first = 0xe0;
+ len = 3;
+ } else {
+ first = 0xf0;
+ len = 4;
+ }
+
+ for (size_t i = len - 1; i > 0; --i) {
+ str[i] = (ch & 0x3f) | 0x80;
+ ch >>= 6;
+ }
+
+ str[0] = ch | first;
+ return len;
+}
+
+
+static const struct {
+ uint8_t mask;
+ uint8_t result;
+ int octets;
+} sizes[] = {
+ { 0x80, 0x00, 1 },
+ { 0xE0, 0xC0, 2 },
+ { 0xF0, 0xE0, 3 },
+ { 0xF8, 0xF0, 4 },
+ { 0xFC, 0xF8, 5 },
+ { 0xFE, 0xF8, 6 },
+ { 0x80, 0x80, -1 },
+};
+
+int utf8_size(const char *s) {
+ uint8_t c = (uint8_t)*s;
+ for (size_t i = 0; i < sizeof(sizes) / 2; ++i) {
+ if ((c & sizes[i].mask) == sizes[i].result) {
+ return sizes[i].octets;
+ }
+ }
+ return -1;
+}
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 {
bool show_indicator;
};
+struct swaylock_password {
+ size_t size;
+ size_t len;
+ char *buffer;
+};
+
struct swaylock_state {
struct wl_display *display;
struct wl_compositor *compositor;
struct zwlr_layer_shell_v1 *layer_shell;
struct wl_shm *shm;
- struct wl_list contexts;
+ struct wl_list surfaces;
struct swaylock_args args;
+ struct swaylock_password password;
struct swaylock_xkb xkb;
bool run_display;
};
-struct swaylock_context {
+struct swaylock_surface {
cairo_surface_t *image;
struct swaylock_state *state;
struct wl_output *output;
@@ -38,4 +45,8 @@ struct swaylock_context {
struct wl_list link;
};
+void swaylock_handle_key(struct swaylock_state *state,
+ xkb_keysym_t keysym, uint32_t codepoint);
+void render_frame(struct swaylock_surface *surface);
+
#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 @@
+#ifndef _SWAY_UNICODE_H
+#define _SWAY_UNICODE_H
+#include <stddef.h>
+#include <stdint.h>
+
+// Technically UTF-8 supports up to 6 byte codepoints, but Unicode itself
+// doesn't really bother with more than 4.
+#define UTF8_MAX_SIZE 4
+
+#define UTF8_INVALID 0x80
+
+/**
+ * Grabs the next UTF-8 character and advances the string pointer
+ */
+uint32_t utf8_decode(const char **str);
+
+/**
+ * Encodes a character as UTF-8 and returns the length of that character.
+ */
+size_t utf8_encode(char *str, uint32_t ch);
+
+/**
+ * Returns the size of the next UTF-8 character
+ */
+int utf8_size(const char *str);
+
+/**
+ * Returns the size of a UTF-8 character
+ */
+size_t utf8_chsize(uint32_t ch);
+
+#endif
+
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() {
}
}
-static void render_frame(struct swaylock_context *context) {
- struct swaylock_state *state = context->state;
- context->current_buffer = get_next_buffer(state->shm,
- context->buffers, context->width, context->height);
- cairo_t *cairo = context->current_buffer->cairo;
- if (state->args.mode == BACKGROUND_MODE_SOLID_COLOR) {
- cairo_set_source_u32(cairo, state->args.color);
- cairo_paint(cairo);
- } else {
- render_background_image(cairo, context->image,
- state->args.mode, context->width, context->height);
- }
- wl_surface_attach(context->surface, context->current_buffer->buffer, 0, 0);
- wl_surface_damage(context->surface, 0, 0, context->width, context->height);
- wl_surface_commit(context->surface);
-}
-
static void layer_surface_configure(void *data,
- struct zwlr_layer_surface_v1 *surface,
+ struct zwlr_layer_surface_v1 *layer_surface,
uint32_t serial, uint32_t width, uint32_t height) {
- struct swaylock_context *context = data;
- context->width = width;
- context->height = height;
- zwlr_layer_surface_v1_ack_configure(surface, serial);
- render_frame(context);
+ struct swaylock_surface *surface = data;
+ surface->width = width;
+ surface->height = height;
+ zwlr_layer_surface_v1_ack_configure(layer_surface, serial);
+ render_frame(surface);
}
static void layer_surface_closed(void *data,
- struct zwlr_layer_surface_v1 *surface) {
- struct swaylock_context *context = data;
- zwlr_layer_surface_v1_destroy(context->layer_surface);
- wl_surface_destroy(context->surface);
- context->state->run_display = false;
+ struct zwlr_layer_surface_v1 *layer_surface) {
+ struct swaylock_surface *surface = data;
+ zwlr_layer_surface_v1_destroy(surface->layer_surface);
+ wl_surface_destroy(surface->surface);
+ surface->state->run_display = false;
}
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,
state->layer_shell = wl_registry_bind(
registry, name, &zwlr_layer_shell_v1_interface, 1);
} else if (strcmp(interface, wl_output_interface.name) == 0) {
- struct swaylock_context *context =
- calloc(1, sizeof(struct swaylock_context));
- context->state = state;
- context->output = wl_registry_bind(registry, name,
+ struct swaylock_surface *surface =
+ calloc(1, sizeof(struct swaylock_surface));
+ surface->state = state;
+ surface->output = wl_registry_bind(registry, name,
&wl_output_interface, 1);
- wl_list_insert(&state->contexts, &context->link);
+ wl_list_insert(&state->surfaces, &surface->link);
}
}
@@ -198,7 +181,7 @@ int main(int argc, char **argv) {
}
}
- wl_list_init(&state.contexts);
+ wl_list_init(&state.surfaces);
state.xkb.context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
assert(state.display = wl_display_connect(NULL));
@@ -207,33 +190,33 @@ int main(int argc, char **argv) {
wl_display_roundtrip(state.display);
assert(state.compositor && state.layer_shell && state.shm);
- if (wl_list_empty(&state.contexts)) {
+ if (wl_list_empty(&state.surfaces)) {
wlr_log(L_DEBUG, "Exiting - no outputs to show on.");
return 0;
}
- struct swaylock_context *context;
- wl_list_for_each(context, &state.contexts, link) {
- assert(context->surface =
+ struct swaylock_surface *surface;
+ wl_list_for_each(surface, &state.surfaces, link) {
+ assert(surface->surface =
wl_compositor_create_surface(state.compositor));
- context->layer_surface = zwlr_layer_shell_v1_get_layer_surface(
- state.layer_shell, context->surface, context->output,
+ surface->layer_surface = zwlr_layer_shell_v1_get_layer_surface(
+ state.layer_shell, surface->surface, surface->output,
ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, "lockscreen");
- assert(context->layer_surface);
+ assert(surface->layer_surface);
- zwlr_layer_surface_v1_set_size(context->layer_surface, 0, 0);
- zwlr_layer_surface_v1_set_anchor(context->layer_surface,
+ zwlr_layer_surface_v1_set_size(surface->layer_surface, 0, 0);
+ zwlr_layer_surface_v1_set_anchor(surface->layer_surface,
ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |
ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT |
ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM |
ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT);
- zwlr_layer_surface_v1_set_exclusive_zone(context->layer_surface, -1);
+ zwlr_layer_surface_v1_set_exclusive_zone(surface->layer_surface, -1);
zwlr_layer_surface_v1_set_keyboard_interactivity(
- context->layer_surface, true);
- zwlr_layer_surface_v1_add_listener(context->layer_surface,
- &layer_surface_listener, context);
- wl_surface_commit(context->surface);
+ surface->layer_surface, true);
+ zwlr_layer_surface_v1_add_listener(surface->layer_surface,
+ &layer_surface_listener, surface);
+ wl_surface_commit(surface->surface);
wl_display_roundtrip(state.display);
}
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 @@
executable(
'swaylock', [
'main.c',
+ 'password.c',
+ 'render.c',
'seat.c'
],
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 @@
+#include <assert.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <wlr/util/log.h>
+#include <xkbcommon/xkbcommon.h>
+#include "swaylock/swaylock.h"
+#include "swaylock/seat.h"
+#include "unicode.h"
+
+static void backspace(struct swaylock_password *pw) {
+ if (pw->len != 0) {
+ pw->buffer[--pw->len] = 0;
+ }
+}
+
+static void append_ch(struct swaylock_password *pw, uint32_t codepoint) {
+ if (!pw->buffer) {
+ pw->size = 8;
+ if (!(pw->buffer = malloc(pw->size))) {
+ // TODO: Display error
+ return;
+ }
+ pw->buffer[0] = 0;
+ }
+ size_t utf8_size = utf8_chsize(codepoint);
+ if (pw->len + utf8_size + 1 >= pw->size) {
+ size_t size = pw->size * 2;
+ char *buffer = realloc(pw->buffer, size);
+ if (!buffer) {
+ // TODO: Display error
+ return;
+ }
+ pw->size = size;
+ pw->buffer = buffer;
+ }
+ utf8_encode(&pw->buffer[pw->len], codepoint);
+ pw->buffer[pw->len + utf8_size] = 0;
+ pw->len += utf8_size;
+}
+
+void swaylock_handle_key(struct swaylock_state *state,
+ xkb_keysym_t keysym, uint32_t codepoint) {
+ switch (keysym) {
+ case XKB_KEY_KP_Enter: /* fallthrough */
+ case XKB_KEY_Return:
+ // TODO: Attempt password
+ break;
+ case XKB_KEY_BackSpace:
+ backspace(&state->password);
+ break;
+ default:
+ if (codepoint) {
+ append_ch(&state->password, codepoint);
+ }
+ break;
+ }
+}
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 @@
+#include <wayland-client.h>
+#include "cairo.h"
+#include "background-image.h"
+#include "swaylock/swaylock.h"
+
+void render_frame(struct swaylock_surface *surface) {
+ struct swaylock_state *state = surface->state;
+ surface->current_buffer = get_next_buffer(state->shm,
+ surface->buffers, surface->width, surface->height);
+ cairo_t *cairo = surface->current_buffer->cairo;
+ if (state->args.mode == BACKGROUND_MODE_SOLID_COLOR) {
+ cairo_set_source_u32(cairo, state->args.color);
+ cairo_paint(cairo);
+ } else {
+ render_background_image(cairo, surface->image,
+ state->args.mode, surface->width, surface->height);
+ }
+ wl_surface_attach(surface->surface, surface->current_buffer->buffer, 0, 0);
+ wl_surface_damage(surface->surface, 0, 0, surface->width, surface->height);
+ wl_surface_commit(surface->surface);
+}
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,
uint32_t keycode = key_state == WL_KEYBOARD_KEY_STATE_PRESSED ?
key + 8 : 0;
uint32_t codepoint = xkb_state_key_get_utf32(state->xkb.state, keycode);
- wlr_log(L_DEBUG, "%c %d", codepoint, sym);
+ if (key_state == WL_KEYBOARD_KEY_STATE_PRESSED) {
+ swaylock_handle_key(state, sym, codepoint);
+ }
}
static void keyboard_modifiers(void *data, struct wl_keyboard *wl_keyboard,