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 | 1fe3cb8965e70f8f05f28512e66d76c49453a196 (diff) | |
| download | sway-066143adef7adc6e76e43e1990db2f75fe984b42.tar.xz | |
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(  		'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,  | 
