diff options
-rw-r--r-- | clients/window.c | 106 | ||||
-rw-r--r-- | src/compositor-wayland.c | 43 | ||||
-rw-r--r-- | src/compositor.c | 75 | ||||
-rw-r--r-- | src/compositor.h | 3 | ||||
-rw-r--r-- | tests/test-client.c | 8 |
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, |