[PATCH weston 31/31] Add support for wl_keyboard::keymap events

Daniel Stone daniel at fooishbar.org
Wed May 30 08:32:09 PDT 2012


These keymap events communicate the keymap from the compositor to the
clients via fd passing, rather than having the clients separately
compile a map.

Signed-off-by: Daniel Stone <daniel at fooishbar.org>
---
 clients/window.c         |  106 +++++++++++++++++++++++++++-------------------
 src/compositor-wayland.c |   42 ++++++++++++++++++
 src/compositor.c         |   74 +++++++++++++++++++++++++++++---
 src/compositor.h         |    3 ++
 tests/test-client.c      |    8 ++++
 5 files changed, 184 insertions(+), 49 deletions(-)

diff --git a/clients/window.c b/clients/window.c
index 6179196..47cbaa1 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -200,7 +200,6 @@ struct input {
 	struct data_offer *selection_offer;
 
 	struct {
-		struct xkb_rule_names names;
 		struct xkb_keymap *keymap;
 		struct xkb_state *state;
 		xkb_mod_mask_t control_mask;
@@ -1829,7 +1828,7 @@ keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
 
 	input->display->serial = serial;
 	code = key + 8;
-	if (!window || window->keyboard_device != input)
+	if (!window || window->keyboard_device != input || !input->xkb.state)
 		return;
 
 	num_syms = xkb_key_get_syms(input->xkb.state, code, &syms);
@@ -1869,13 +1868,8 @@ keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard,
 {
 	struct input *input = data;
 
-	xkb_state_update_mask(input->xkb.state,
-			      mods_depressed,
-			      mods_latched,
-			      mods_locked,
-			      0,
-			      0,
-			      group);
+	xkb_state_update_mask(input->xkb.state, mods_depressed, mods_latched,
+			      mods_locked, 0, 0, group);
 }
 
 static void
@@ -1982,6 +1976,57 @@ keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
 	input_remove_keyboard_focus(input);
 }
 
+static void
+keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
+		       uint32_t format, int fd, uint32_t size)
+{
+	struct input *input = data;
+	char *map_str;
+
+	if (!data) {
+		close(fd);
+		return;
+	}
+
+	if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
+		close(fd);
+		return;
+	}
+
+	map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
+	if (map_str == MAP_FAILED) {
+		close(fd);
+		return;
+	}
+
+	input->xkb.keymap = xkb_map_new_from_string(input->display->xkb_context,
+						    map_str,
+						    XKB_KEYMAP_FORMAT_TEXT_V1,
+						    0);
+	munmap(map_str, size);
+	close(fd);
+
+	if (!input->xkb.keymap) {
+		fprintf(stderr, "failed to compile keymap\n");
+		return;
+	}
+
+	input->xkb.state = xkb_state_new(input->xkb.keymap);
+	if (!input->xkb.state) {
+		fprintf(stderr, "failed to create XKB state\n");
+		xkb_map_unref(input->xkb.keymap);
+		input->xkb.keymap = NULL;
+		return;
+	}
+
+	input->xkb.control_mask =
+		1 << xkb_map_mod_get_index(input->xkb.keymap, "Control");
+	input->xkb.alt_mask =
+		1 << xkb_map_mod_get_index(input->xkb.keymap, "Mod1");
+	input->xkb.shift_mask =
+		1 << xkb_map_mod_get_index(input->xkb.keymap, "Shift");
+}
+
 static const struct wl_pointer_listener pointer_listener = {
 	pointer_handle_enter,
 	pointer_handle_leave,
@@ -1991,6 +2036,7 @@ static const struct wl_pointer_listener pointer_listener = {
 };
 
 static const struct wl_keyboard_listener keyboard_listener = {
+	keyboard_handle_keymap,
 	keyboard_handle_enter,
 	keyboard_handle_leave,
 	keyboard_handle_key,
@@ -3060,37 +3106,6 @@ output_get_wl_output(struct output *output)
 }
 
 static void
-init_xkb(struct input *input)
-{
-	input->xkb.names.rules = "evdev";
-	input->xkb.names.model = "pc105";
-	input->xkb.names.layout = (char *) option_xkb_layout;
-	input->xkb.names.variant = (char *) option_xkb_variant;
-	input->xkb.names.options = (char *) option_xkb_options;
-
-	input->xkb.keymap = xkb_map_new_from_names(input->display->xkb_context,
-						   &input->xkb.names, 0);
-	if (!input->xkb.keymap) {
-		fprintf(stderr, "Failed to compile keymap\n");
-		exit(1);
-	}
-
-	input->xkb.state = xkb_state_new(input->xkb.keymap);
-	if (!input->xkb.state) {
-		fprintf(stderr, "Failed to create XKB state\n");
-		exit(1);
-	}
-
-	input->xkb.control_mask =
-		1 << xkb_map_mod_get_index(input->xkb.keymap, "Control");
-	input->xkb.alt_mask =
-		1 << xkb_map_mod_get_index(input->xkb.keymap, "Mod1");
-	input->xkb.shift_mask =
-		1 << xkb_map_mod_get_index(input->xkb.keymap, "Shift");
-
-}
-
-static void
 fini_xkb(struct input *input)
 {
 	xkb_state_unref(input->xkb.state);
@@ -3113,8 +3128,6 @@ display_add_input(struct display *d, uint32_t id)
 	input->keyboard_focus = NULL;
 	wl_list_insert(d->input_list.prev, &input->link);
 
-	init_xkb(input);
-
 	wl_seat_add_listener(input->seat, &seat_listener, input);
 	wl_seat_set_user_data(input->seat, input);
 
@@ -3131,6 +3144,11 @@ input_destroy(struct input *input)
 	input_remove_keyboard_focus(input);
 	input_remove_pointer_focus(input);
 
+	if (input->xkb.state)
+		xkb_state_unref(input->xkb.state);
+	if (input->xkb.keymap)
+		xkb_map_unref(input->xkb.keymap);
+
 	if (input->drag_offer)
 		data_offer_destroy(input->drag_offer);
 
@@ -3308,8 +3326,8 @@ display_create(int argc, char *argv[])
 	wl_list_init(&d->output_list);
 
 	d->xkb_context = xkb_context_new(0);
-	if (!d->xkb_context) {
-		fprintf(stderr, "failed to initialize XKB context\n");
+	if (d->xkb_context == NULL) {
+		fprintf(stderr, "Failed to create XKB context\n");
 		return NULL;
 	}
 
diff --git a/src/compositor-wayland.c b/src/compositor-wayland.c
index 4b4f1eb..66d20a2 100644
--- a/src/compositor-wayland.c
+++ b/src/compositor-wayland.c
@@ -31,6 +31,7 @@
 #include <string.h>
 #include <fcntl.h>
 #include <unistd.h>
+#include <sys/mman.h>
 
 #include <wayland-client.h>
 #include <wayland-egl.h>
@@ -576,6 +577,46 @@ static const struct wl_pointer_listener pointer_listener = {
 };
 
 static void
+input_handle_keymap(void *data, struct wl_keyboard *keyboard, uint32_t format,
+		    int fd, uint32_t size)
+{
+	struct wayland_input *input = data;
+	struct xkb_keymap *keymap;
+        char *map_str;
+
+        if (!data) {
+                close(fd);
+                return;
+        }
+
+        if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
+                close(fd);
+                return;
+        }
+
+        map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
+        if (map_str == MAP_FAILED) {
+                close(fd);
+                return;
+        }
+
+        keymap = xkb_map_new_from_string(input->compositor->base.xkb_context,
+                                         map_str,
+                                         XKB_KEYMAP_FORMAT_TEXT_V1,
+                                         0);
+        munmap(map_str, size);
+        close(fd);
+
+        if (!keymap) {
+                fprintf(stderr, "failed to compile keymap\n");
+                return;
+        }
+
+	weston_seat_init_keyboard(input->compositor->base.seat, keymap);
+	xkb_map_unref(keymap);
+}
+
+static void
 input_handle_keyboard_enter(void *data,
 			    struct wl_keyboard *keyboard,
 			    uint32_t serial,
@@ -622,6 +663,7 @@ input_handle_modifiers(void *data, struct wl_keyboard *keyboard,
 }
 
 static const struct wl_keyboard_listener keyboard_listener = {
+	input_handle_keymap,
 	input_handle_keyboard_enter,
 	input_handle_keyboard_leave,
 	input_handle_key,
diff --git a/src/compositor.c b/src/compositor.c
index 70db411..d140a50 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -34,6 +34,7 @@
 #include <stdarg.h>
 #include <assert.h>
 #include <sys/ioctl.h>
+#include <sys/mman.h>
 #include <sys/wait.h>
 #include <sys/types.h>
 #include <sys/socket.h>
@@ -2165,6 +2166,10 @@ seat_get_keyboard(struct wl_client *client, struct wl_resource *resource,
 	wl_list_insert(&seat->seat.keyboard->resource_list, &cr->link);
 	cr->destroy = unbind_resource;
 
+	wl_keyboard_send_keymap(cr, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
+				seat->xkb_info.keymap_fd,
+				seat->xkb_info.keymap_size);
+
 	if (seat->seat.keyboard->focus &&
 	    seat->seat.keyboard->focus->resource.client == client) {
 		wl_keyboard_set_focus(seat->seat.keyboard,
@@ -2247,8 +2252,13 @@ static void weston_compositor_xkb_init(struct weston_compositor *ec,
 
 static void xkb_info_destroy(struct weston_xkb_info *xkb_info)
 {
-        if (xkb_info->keymap)
-                xkb_map_unref(xkb_info->keymap);
+	if (xkb_info->keymap)
+		xkb_map_unref(xkb_info->keymap);
+
+	if (xkb_info->keymap_area)
+		munmap(xkb_info->keymap_area, xkb_info->keymap_size);
+	if (xkb_info->keymap_fd >= 0)
+		close(xkb_info->keymap_fd);
 }
 
 static void weston_compositor_xkb_destroy(struct weston_compositor *ec)
@@ -2264,8 +2274,11 @@ static void weston_compositor_xkb_destroy(struct weston_compositor *ec)
 }
 
 static void
-weston_xkb_info_get_mods(struct weston_xkb_info *xkb_info)
+weston_xkb_info_new_keymap(struct weston_xkb_info *xkb_info)
 {
+	char *keymap_str;
+	char *path;
+
 	xkb_info->ctrl_mod = xkb_map_mod_get_index(xkb_info->keymap,
 						   XKB_MOD_NAME_CTRL);
 	xkb_info->alt_mod = xkb_map_mod_get_index(xkb_info->keymap,
@@ -2279,6 +2292,57 @@ weston_xkb_info_get_mods(struct weston_xkb_info *xkb_info)
 						   XKB_LED_NAME_CAPS);
 	xkb_info->scroll_led = xkb_map_led_get_index(xkb_info->keymap,
 						     XKB_LED_NAME_SCROLL);
+
+	keymap_str = xkb_map_get_as_string(xkb_info->keymap);
+	if (keymap_str == NULL) {
+		fprintf(stderr, "failed to get string version of keymap\n");
+		exit(EXIT_FAILURE);
+	}
+	xkb_info->keymap_size = strlen(keymap_str) + 1;
+
+	/* Create a temporary file in /dev/shm to use for mapping the keymap,
+	 * and then unlink it as soon as we can. */
+	path = strdup("/dev/shm/weston-keymap-XXXXXX");
+	if (path == NULL) {
+		fprintf(stderr, "failed to allocate keymap path\n");
+		goto err_keymap_str;
+	}
+
+	xkb_info->keymap_fd = mkostemp(path, O_CLOEXEC);
+	if (xkb_info->keymap_fd < 0) {
+		fprintf(stderr, "failed to create temporary keymap file\n");
+		goto err_path;
+	}
+	unlink(path);
+
+	if (ftruncate(xkb_info->keymap_fd, xkb_info->keymap_size) != 0) {
+		fprintf(stderr, "failed to enlarage temporary keymap file\n");
+		goto err_path;
+	}
+
+	xkb_info->keymap_area = mmap(NULL, xkb_info->keymap_size,
+				     PROT_READ | PROT_WRITE,
+				     MAP_SHARED, xkb_info->keymap_fd, 0);
+	if (xkb_info->keymap_area == MAP_FAILED) {
+		fprintf(stderr, "failed to mmap() %lu bytes on %s\n",
+			(unsigned long) xkb_info->keymap_size,
+			path);
+		goto err_dev_zero;
+	}
+	strcpy(xkb_info->keymap_area, keymap_str);
+	free(keymap_str);
+	free(path);
+
+	return;
+
+err_dev_zero:
+	close(xkb_info->keymap_fd);
+	xkb_info->keymap_fd = -1;
+err_path:
+	free(path);
+err_keymap_str:
+	free(keymap_str);
+	exit(EXIT_FAILURE);
 }
 
 static void
@@ -2301,7 +2365,7 @@ weston_compositor_build_global_keymap(struct weston_compositor *ec)
 		exit(1);
 	}
 
-	weston_xkb_info_get_mods(&ec->xkb_info);
+	weston_xkb_info_new_keymap(&ec->xkb_info);
 }
 
 WL_EXPORT void
@@ -2312,7 +2376,7 @@ weston_seat_init_keyboard(struct weston_seat *seat, struct xkb_keymap *keymap)
 
 	if (keymap != NULL) {
 		seat->xkb_info.keymap = xkb_map_ref(keymap);
-		weston_xkb_info_get_mods(&seat->xkb_info);
+		weston_xkb_info_new_keymap(&seat->xkb_info);
 	}
 	else {
 		weston_compositor_build_global_keymap(seat->compositor);
diff --git a/src/compositor.h b/src/compositor.h
index 8809f9d..a398ddf 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -159,6 +159,9 @@ struct weston_output {
 
 struct weston_xkb_info {
 	struct xkb_keymap *keymap;
+	int keymap_fd;
+	size_t keymap_size;
+	char *keymap_area;
 	xkb_mod_index_t ctrl_mod;
 	xkb_mod_index_t alt_mod;
 	xkb_mod_index_t super_mod;
diff --git a/tests/test-client.c b/tests/test-client.c
index 60ba051..4ec0f4a 100644
--- a/tests/test-client.c
+++ b/tests/test-client.c
@@ -112,6 +112,13 @@ pointer_handle_axis(void *data, struct wl_pointer *pointer,
 }
 
 static void
+keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
+		       uint32_t format, int fd, uint32_t size)
+{
+	close(fd);
+}
+
+static void
 keyboard_handle_enter(void *data, struct wl_keyboard *keyboard,
 		      uint32_t serial, struct wl_surface *surface,
 		      struct wl_array *keys)
@@ -146,6 +153,7 @@ static const struct wl_pointer_listener pointer_listener = {
 };
 
 static const struct wl_keyboard_listener keyboard_listener = {
+	keyboard_handle_keymap,
 	keyboard_handle_enter,
 	keyboard_handle_leave,
 	keyboard_handle_key,
-- 
1.7.10



More information about the wayland-devel mailing list