summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--clients/window.c106
-rw-r--r--src/compositor-wayland.c43
-rw-r--r--src/compositor.c75
-rw-r--r--src/compositor.h3
-rw-r--r--tests/test-client.c8
5 files changed, 185 insertions, 50 deletions
diff --git a/clients/window.c b/clients/window.c
index e78864c..69bcb15 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -204,7 +204,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;
@@ -1833,7 +1832,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;
if (state)
@@ -1876,13 +1875,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
@@ -1989,6 +1983,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,
@@ -1998,6 +2043,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,
@@ -3087,37 +3133,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);
@@ -3140,8 +3155,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);
@@ -3158,6 +3171,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);
@@ -3339,8 +3357,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 870c208..9e1f8a3 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,
@@ -650,7 +692,6 @@ input_handle_capabilities(void *data, struct wl_seat *seat,
wl_keyboard_set_user_data(input->keyboard, input);
wl_keyboard_add_listener(input->keyboard, &keyboard_listener,
input);
- weston_seat_init_keyboard(input->compositor->base.seat, NULL);
} else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && input->keyboard) {
wl_keyboard_destroy(input->keyboard);
input->keyboard = NULL;
diff --git a/src/compositor.c b/src/compositor.c
index 676eebb..b299e03 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -26,6 +26,7 @@
#include "config.h"
+#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
@@ -34,6 +35,7 @@
#include <stdarg.h>
#include <assert.h>
#include <sys/ioctl.h>
+#include <sys/mman.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <unistd.h>
@@ -2163,6 +2165,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 +2253,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 +2275,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 +2293,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 +2366,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 +2377,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 23beb5f..d070471 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -164,6 +164,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,