From 92c85858a9dfc11b83f374f53a7e70b6e08899cd Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Tue, 30 Jun 2020 13:10:11 +0200 Subject: [PATCH 1/9] layer-shell: remove unused surface list This was rendered useless in 5cde359. --- include/wlr/types/wlr_layer_shell_v1.h | 2 -- types/wlr_layer_shell_v1.c | 4 ---- 2 files changed, 6 deletions(-) diff --git a/include/wlr/types/wlr_layer_shell_v1.h b/include/wlr/types/wlr_layer_shell_v1.h index 7c6a5cd26..b6a0a1352 100644 --- a/include/wlr/types/wlr_layer_shell_v1.h +++ b/include/wlr/types/wlr_layer_shell_v1.h @@ -29,7 +29,6 @@ */ struct wlr_layer_shell_v1 { struct wl_global *global; - struct wl_list surfaces; // wl_layer_surface struct wl_listener display_destroy; @@ -63,7 +62,6 @@ struct wlr_layer_surface_v1_configure { }; struct wlr_layer_surface_v1 { - struct wl_list link; // wlr_layer_shell_v1::surfaces struct wlr_surface *surface; struct wlr_output *output; struct wl_resource *resource; diff --git a/types/wlr_layer_shell_v1.c b/types/wlr_layer_shell_v1.c index 6746f2166..0002f4cbf 100644 --- a/types/wlr_layer_shell_v1.c +++ b/types/wlr_layer_shell_v1.c @@ -232,7 +232,6 @@ static void layer_surface_destroy(struct wlr_layer_surface_v1 *surface) { wl_resource_set_user_data(surface->resource, NULL); surface->surface->role_data = NULL; wl_list_remove(&surface->surface_destroy.link); - wl_list_remove(&surface->link); free(surface->namespace); free(surface); } @@ -440,7 +439,6 @@ static void layer_shell_handle_get_layer_surface(struct wl_client *wl_client, surface, surface->resource); wl_resource_set_implementation(surface->resource, &layer_surface_implementation, surface, layer_surface_resource_destroy); - wl_list_insert(&shell->surfaces, &surface->link); } static const struct zwlr_layer_shell_v1_interface layer_shell_implementation = { @@ -479,8 +477,6 @@ struct wlr_layer_shell_v1 *wlr_layer_shell_v1_create(struct wl_display *display) return NULL; } - wl_list_init(&layer_shell->surfaces); - struct wl_global *global = wl_global_create(display, &zwlr_layer_shell_v1_interface, 2, layer_shell, layer_shell_bind); if (!global) { From cccca368c595946235cdfb80a9d796ef5cb750fa Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 7 Jul 2020 17:36:51 +0200 Subject: [PATCH 2/9] backend/drm: fix typo in drm_surface_make_current arg --- backend/drm/renderer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/drm/renderer.c b/backend/drm/renderer.c index 2f9769f54..4b6e9bf18 100644 --- a/backend/drm/renderer.c +++ b/backend/drm/renderer.c @@ -126,8 +126,8 @@ static void finish_drm_surface(struct wlr_drm_surface *surf) { } bool drm_surface_make_current(struct wlr_drm_surface *surf, - int *buffer_damage) { - return wlr_egl_make_current(&surf->renderer->egl, surf->egl, buffer_damage); + int *buffer_age) { + return wlr_egl_make_current(&surf->renderer->egl, surf->egl, buffer_age); } bool export_drm_bo(struct gbm_bo *bo, struct wlr_dmabuf_attributes *attribs) { From b6377b59ff70342e4e33b67c9733fe80d7e87cac Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 7 Jul 2020 16:28:20 +0200 Subject: [PATCH 3/9] backend/drm: check drm_surface_make_current return value drm_connector_set_cursor wasn't checking the return value of the drm_surface_make_current call. On failure, this results in a failed assertion in wlr_renderer_begin (because no rendering context is current). --- backend/drm/drm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 7153761ad..6978c22c1 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -928,7 +928,9 @@ static bool drm_connector_set_cursor(struct wlr_output *output, return false; } - drm_surface_make_current(&plane->surf, NULL); + if (!drm_surface_make_current(&plane->surf, NULL)) { + return false; + } struct wlr_renderer *rend = plane->surf.renderer->wlr_rend; From 61e2ebac908c33cfaf06a53a09e829ac97eca400 Mon Sep 17 00:00:00 2001 From: xdavidwu Date: Wed, 8 Jul 2020 10:46:28 +0200 Subject: [PATCH 4/9] virtual-keyboard: add wlr_input_device_get_virtual_keyboard --- include/wlr/types/wlr_virtual_keyboard_v1.h | 5 ++++- types/wlr_virtual_keyboard_v1.c | 8 ++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/include/wlr/types/wlr_virtual_keyboard_v1.h b/include/wlr/types/wlr_virtual_keyboard_v1.h index 78f80fbb7..a3f4e4521 100644 --- a/include/wlr/types/wlr_virtual_keyboard_v1.h +++ b/include/wlr/types/wlr_virtual_keyboard_v1.h @@ -26,8 +26,8 @@ struct wlr_virtual_keyboard_manager_v1 { }; struct wlr_virtual_keyboard_v1 { - struct wl_resource *resource; struct wlr_input_device input_device; + struct wl_resource *resource; struct wlr_seat *seat; bool has_keymap; @@ -41,4 +41,7 @@ struct wlr_virtual_keyboard_v1 { struct wlr_virtual_keyboard_manager_v1* wlr_virtual_keyboard_manager_v1_create( struct wl_display *display); +struct wlr_virtual_keyboard_v1 *wlr_input_device_get_virtual_keyboard( + struct wlr_input_device *wlr_dev); + #endif diff --git a/types/wlr_virtual_keyboard_v1.c b/types/wlr_virtual_keyboard_v1.c index 258a08cb8..7ae030eec 100644 --- a/types/wlr_virtual_keyboard_v1.c +++ b/types/wlr_virtual_keyboard_v1.c @@ -40,6 +40,14 @@ static struct wlr_virtual_keyboard_v1 *virtual_keyboard_from_resource( return wl_resource_get_user_data(resource); } +struct wlr_virtual_keyboard_v1 *wlr_input_device_get_virtual_keyboard( + struct wlr_input_device *wlr_dev) { + if (wlr_dev->impl != &input_device_impl) { + return NULL; + } + return (struct wlr_virtual_keyboard_v1 *)wlr_dev; +} + static void virtual_keyboard_keymap(struct wl_client *client, struct wl_resource *resource, uint32_t format, int32_t fd, uint32_t size) { From 595f324f8b74eebed59176e3889ebccb875c574c Mon Sep 17 00:00:00 2001 From: xdavidwu Date: Wed, 8 Jul 2020 10:48:05 +0200 Subject: [PATCH 5/9] input-method: implement keyboard grabs --- include/wlr/types/wlr_input_method_v2.h | 32 +++- types/wlr_input_method_v2.c | 213 ++++++++++++++++++++++-- 2 files changed, 234 insertions(+), 11 deletions(-) diff --git a/include/wlr/types/wlr_input_method_v2.h b/include/wlr/types/wlr_input_method_v2.h index 2ea4a6e54..99361d0cd 100644 --- a/include/wlr/types/wlr_input_method_v2.h +++ b/include/wlr/types/wlr_input_method_v2.h @@ -34,6 +34,7 @@ struct wlr_input_method_v2 { struct wl_resource *resource; struct wlr_seat *seat; + struct wlr_seat_client *seat_client; struct wlr_input_method_v2_state pending; struct wlr_input_method_v2_state current; @@ -41,16 +42,33 @@ struct wlr_input_method_v2 { bool client_active; // state known to the client uint32_t current_serial; // received in last commit call + struct wlr_input_method_keyboard_grab_v2 *keyboard_grab; + struct wl_list link; - struct wl_listener seat_destroy; + struct wl_listener seat_client_destroy; struct { struct wl_signal commit; // (struct wlr_input_method_v2*) + struct wl_signal grab_keyboard; // (struct wlr_input_method_keyboard_grab_v2*) struct wl_signal destroy; // (struct wlr_input_method_v2*) } events; }; +struct wlr_input_method_keyboard_grab_v2 { + struct wl_resource *resource; + struct wlr_input_method_v2 *input_method; + struct wlr_keyboard *keyboard; + + struct wl_listener keyboard_keymap; + struct wl_listener keyboard_repeat_info; + struct wl_listener keyboard_destroy; + + struct { + struct wl_signal destroy; // (struct wlr_input_method_keyboard_grab_v2*) + } events; +}; + struct wlr_input_method_manager_v2 { struct wl_global *global; struct wl_list input_methods; // struct wlr_input_method_v2*::link @@ -82,4 +100,16 @@ void wlr_input_method_v2_send_done(struct wlr_input_method_v2 *input_method); void wlr_input_method_v2_send_unavailable( struct wlr_input_method_v2 *input_method); +void wlr_input_method_keyboard_grab_v2_send_key( + struct wlr_input_method_keyboard_grab_v2 *keyboard_grab, + uint32_t time, uint32_t key, uint32_t state); +void wlr_input_method_keyboard_grab_v2_send_modifiers( + struct wlr_input_method_keyboard_grab_v2 *keyboard_grab, + struct wlr_keyboard_modifiers *modifiers); +void wlr_input_method_keyboard_grab_v2_set_keyboard( + struct wlr_input_method_keyboard_grab_v2 *keyboard_grab, + struct wlr_keyboard *keyboard); +void wlr_input_method_keyboard_grab_v2_destroy( + struct wlr_input_method_keyboard_grab_v2 *keyboard_grab); + #endif diff --git a/types/wlr_input_method_v2.c b/types/wlr_input_method_v2.c index 525b3616c..cb2482888 100644 --- a/types/wlr_input_method_v2.c +++ b/types/wlr_input_method_v2.c @@ -3,15 +3,19 @@ #endif #include #include +#include +#include #include #include #include #include #include #include "input-method-unstable-v2-protocol.h" +#include "util/shm.h" #include "util/signal.h" static const struct zwp_input_method_v2_interface input_method_impl; +static const struct zwp_input_method_keyboard_grab_v2_interface keyboard_grab_impl; static struct wlr_input_method_v2 *input_method_from_resource( struct wl_resource *resource) { @@ -20,10 +24,19 @@ static struct wlr_input_method_v2 *input_method_from_resource( return wl_resource_get_user_data(resource); } +static struct wlr_input_method_keyboard_grab_v2 *keyboard_grab_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, + &zwp_input_method_keyboard_grab_v2_interface, + &keyboard_grab_impl)); + return wl_resource_get_user_data(resource); +} + static void input_method_destroy(struct wlr_input_method_v2 *input_method) { wlr_signal_emit_safe(&input_method->events.destroy, input_method); wl_list_remove(wl_resource_get_link(input_method->resource)); - wl_list_remove(&input_method->seat_destroy.link); + wl_list_remove(&input_method->seat_client_destroy.link); + wlr_input_method_keyboard_grab_v2_destroy(input_method->keyboard_grab); free(input_method->pending.commit_text); free(input_method->pending.preedit.text); free(input_method->current.commit_text); @@ -101,10 +114,189 @@ static void im_get_input_popup_surface(struct wl_client *client, wlr_log(WLR_INFO, "Stub: zwp_input_method_v2::get_input_popup_surface"); } +void wlr_input_method_keyboard_grab_v2_destroy( + struct wlr_input_method_keyboard_grab_v2 *keyboard_grab) { + if (!keyboard_grab) { + return; + } + wlr_signal_emit_safe(&keyboard_grab->events.destroy, keyboard_grab); + keyboard_grab->input_method->keyboard_grab = NULL; + if (keyboard_grab->keyboard) { + wl_list_remove(&keyboard_grab->keyboard_keymap.link); + wl_list_remove(&keyboard_grab->keyboard_repeat_info.link); + wl_list_remove(&keyboard_grab->keyboard_destroy.link); + } + wl_resource_set_user_data(keyboard_grab->resource, NULL); + free(keyboard_grab); +} + +static void keyboard_grab_resource_destroy(struct wl_resource *resource) { + struct wlr_input_method_keyboard_grab_v2 *keyboard_grab = + keyboard_grab_from_resource(resource); + wlr_input_method_keyboard_grab_v2_destroy(keyboard_grab); +} + +static void keyboard_grab_release(struct wl_client *client, + struct wl_resource *resource) { + wl_resource_destroy(resource); +} + +static const struct zwp_input_method_keyboard_grab_v2_interface keyboard_grab_impl = { + .release = keyboard_grab_release, +}; + +void wlr_input_method_keyboard_grab_v2_send_key( + struct wlr_input_method_keyboard_grab_v2 *keyboard_grab, + uint32_t time, uint32_t key, uint32_t state) { + zwp_input_method_keyboard_grab_v2_send_key( + keyboard_grab->resource, + wlr_seat_client_next_serial(keyboard_grab->input_method->seat_client), + time, key, state); +} + +void wlr_input_method_keyboard_grab_v2_send_modifiers( + struct wlr_input_method_keyboard_grab_v2 *keyboard_grab, + struct wlr_keyboard_modifiers *modifiers) { + zwp_input_method_keyboard_grab_v2_send_modifiers( + keyboard_grab->resource, + wlr_seat_client_next_serial(keyboard_grab->input_method->seat_client), + modifiers->depressed, modifiers->latched, + modifiers->locked, modifiers->group); +} + +static bool keyboard_grab_send_keymap( + struct wlr_input_method_keyboard_grab_v2 *keyboard_grab, + struct wlr_keyboard *keyboard) { + int keymap_fd = allocate_shm_file(keyboard->keymap_size); + if (keymap_fd < 0) { + wlr_log(WLR_ERROR, "creating a keymap file for %zu bytes failed", + keyboard->keymap_size); + return false; + } + + void *ptr = mmap(NULL, keyboard->keymap_size, PROT_READ | PROT_WRITE, + MAP_SHARED, keymap_fd, 0); + if (ptr == MAP_FAILED) { + wlr_log(WLR_ERROR, "failed to mmap() %zu bytes", + keyboard->keymap_size); + close(keymap_fd); + return false; + } + + memcpy(ptr, keyboard->keymap_string, keyboard->keymap_size); + munmap(ptr, keyboard->keymap_size); + + zwp_input_method_keyboard_grab_v2_send_keymap(keyboard_grab->resource, + WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, keymap_fd, + keyboard->keymap_size); + + close(keymap_fd); + return true; +} + +static void keyboard_grab_send_repeat_info( + struct wlr_input_method_keyboard_grab_v2 *keyboard_grab, + struct wlr_keyboard *keyboard) { + zwp_input_method_keyboard_grab_v2_send_repeat_info( + keyboard_grab->resource, keyboard->repeat_info.rate, + keyboard->repeat_info.delay); +} + +static void handle_keyboard_keymap(struct wl_listener *listener, void *data) { + struct wlr_input_method_keyboard_grab_v2 *keyboard_grab = + wl_container_of(listener, keyboard_grab, keyboard_keymap); + keyboard_grab_send_keymap(keyboard_grab, data); +} + +static void handle_keyboard_repeat_info(struct wl_listener *listener, + void *data) { + struct wlr_input_method_keyboard_grab_v2 *keyboard_grab = + wl_container_of(listener, keyboard_grab, keyboard_repeat_info); + keyboard_grab_send_repeat_info(keyboard_grab, data); +} + +static void handle_keyboard_destroy(struct wl_listener *listener, + void *data) { + struct wlr_input_method_keyboard_grab_v2 *keyboard_grab = + wl_container_of(listener, keyboard_grab, keyboard_destroy); + wlr_input_method_keyboard_grab_v2_set_keyboard(keyboard_grab, NULL); +} + +void wlr_input_method_keyboard_grab_v2_set_keyboard( + struct wlr_input_method_keyboard_grab_v2 *keyboard_grab, + struct wlr_keyboard *keyboard) { + if (keyboard == keyboard_grab->keyboard) { + return; + } + + if (keyboard_grab->keyboard) { + wl_list_remove(&keyboard_grab->keyboard_keymap.link); + wl_list_remove(&keyboard_grab->keyboard_repeat_info.link); + wl_list_remove(&keyboard_grab->keyboard_destroy.link); + } + + if (keyboard) { + if (keyboard_grab->keyboard == NULL || + strcmp(keyboard_grab->keyboard->keymap_string, + keyboard->keymap_string) != 0) { + // send keymap only if it is changed, or if input method is not + // aware that it did not change and blindly send it back with + // virtual keyboard, it may cause an infinite recursion. + if (!keyboard_grab_send_keymap(keyboard_grab, keyboard)) { + wlr_log(WLR_ERROR, "Failed to send keymap for input-method keyboard grab"); + return; + } + } + keyboard_grab_send_repeat_info(keyboard_grab, keyboard); + keyboard_grab->keyboard_keymap.notify = handle_keyboard_keymap; + wl_signal_add(&keyboard->events.keymap, + &keyboard_grab->keyboard_keymap); + keyboard_grab->keyboard_repeat_info.notify = + handle_keyboard_repeat_info; + wl_signal_add(&keyboard->events.repeat_info, + &keyboard_grab->keyboard_repeat_info); + keyboard_grab->keyboard_destroy.notify = + handle_keyboard_destroy; + wl_signal_add(&keyboard->events.destroy, + &keyboard_grab->keyboard_destroy); + } + + keyboard_grab->keyboard = keyboard; +}; static void im_grab_keyboard(struct wl_client *client, struct wl_resource *resource, uint32_t keyboard) { - wlr_log(WLR_INFO, "Stub: zwp_input_method_v2::grab_keyboard"); + struct wlr_input_method_v2 *input_method = + input_method_from_resource(resource); + if (!input_method) { + return; + } + if (input_method->keyboard_grab) { + // Already grabbed + return; + } + struct wlr_input_method_keyboard_grab_v2 *keyboard_grab = + calloc(1, sizeof(struct wlr_input_method_keyboard_grab_v2)); + if (!keyboard_grab) { + wl_client_post_no_memory(client); + return; + } + struct wl_resource *keyboard_grab_resource = wl_resource_create( + client, &zwp_input_method_keyboard_grab_v2_interface, + wl_resource_get_version(resource), keyboard); + if (keyboard_grab_resource == NULL) { + free(keyboard_grab); + wl_client_post_no_memory(client); + return; + } + wl_resource_set_implementation(keyboard_grab_resource, + &keyboard_grab_impl, keyboard_grab, + keyboard_grab_resource_destroy); + keyboard_grab->resource = keyboard_grab_resource; + keyboard_grab->input_method = input_method; + input_method->keyboard_grab = keyboard_grab; + wl_signal_init(&keyboard_grab->events.destroy); + wlr_signal_emit_safe(&input_method->events.grab_keyboard, keyboard_grab); } static const struct zwp_input_method_v2_interface input_method_impl = { @@ -176,10 +368,10 @@ static struct wlr_input_method_manager_v2 *input_method_manager_from_resource( return wl_resource_get_user_data(resource); } -static void input_method_handle_seat_destroy(struct wl_listener *listener, +static void input_method_handle_seat_client_destroy(struct wl_listener *listener, void *data) { struct wlr_input_method_v2 *input_method = wl_container_of(listener, - input_method, seat_destroy); + input_method, seat_client_destroy); wlr_input_method_v2_send_unavailable(input_method); } @@ -196,6 +388,7 @@ static void manager_get_input_method(struct wl_client *client, return; } wl_signal_init(&input_method->events.commit); + wl_signal_init(&input_method->events.grab_keyboard); wl_signal_init(&input_method->events.destroy); int version = wl_resource_get_version(resource); struct wl_resource *im_resource = wl_resource_create(client, @@ -208,14 +401,14 @@ static void manager_get_input_method(struct wl_client *client, wl_resource_set_implementation(im_resource, &input_method_impl, input_method, input_method_resource_destroy); - struct wlr_seat_client *seat_client = wlr_seat_client_from_resource(seat); - wl_signal_add(&seat_client->events.destroy, - &input_method->seat_destroy); - input_method->seat_destroy.notify = - input_method_handle_seat_destroy; + input_method->seat_client = wlr_seat_client_from_resource(seat); + input_method->seat = input_method->seat_client->seat; + wl_signal_add(&input_method->seat_client->events.destroy, + &input_method->seat_client_destroy); + input_method->seat_client_destroy.notify = + input_method_handle_seat_client_destroy; input_method->resource = im_resource; - input_method->seat = seat_client->seat; wl_list_insert(&im_manager->input_methods, wl_resource_get_link(input_method->resource)); wlr_signal_emit_safe(&im_manager->events.input_method, input_method); From 842df2bd6c940c5f4933622987fc9a296f404d67 Mon Sep 17 00:00:00 2001 From: xdavidwu Date: Wed, 8 Jul 2020 10:48:29 +0200 Subject: [PATCH 6/9] examples/input-method-keyboard-grab: new example --- examples/input-method-keyboard-grab.c | 217 ++++++++++++++++++++++++++ examples/meson.build | 7 + 2 files changed, 224 insertions(+) create mode 100644 examples/input-method-keyboard-grab.c diff --git a/examples/input-method-keyboard-grab.c b/examples/input-method-keyboard-grab.c new file mode 100644 index 000000000..881f91a92 --- /dev/null +++ b/examples/input-method-keyboard-grab.c @@ -0,0 +1,217 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "input-method-unstable-v2-client-protocol.h" + +static struct wl_display *display = NULL; +static struct wl_seat *seat = NULL; +static struct zwp_input_method_manager_v2 *input_method_manager = NULL; +static struct zwp_input_method_v2 *input_method = NULL; +static struct zwp_input_method_keyboard_grab_v2 *kb_grab = NULL; + +static bool active = false; +static bool pending_active = false; + +static struct xkb_context *xkb_context = NULL; +static struct xkb_keymap *keymap = NULL; +static struct xkb_state *xkb_state = NULL; + +static void handle_key(void *data, + struct zwp_input_method_keyboard_grab_v2 *im_keyboard_grab, + uint32_t serial, uint32_t time, uint32_t key, uint32_t state) { + printf("handle_key %u %u %u %u\n", serial, time, key, state); + xkb_keysym_t keysym = xkb_state_key_get_one_sym(xkb_state, key + 8); + char keysym_name[64]; + xkb_keysym_get_name(keysym, keysym_name, sizeof(keysym_name)); + printf("xkb translated to %s\n", keysym_name); + if (state == WL_KEYBOARD_KEY_STATE_PRESSED) { + if (keysym == XKB_KEY_KP_Enter || keysym == XKB_KEY_Return) { + printf("Stopping grab\n"); + zwp_input_method_keyboard_grab_v2_release(kb_grab); + kb_grab = NULL; + } + } + +} + +static void handle_modifiers(void *data, + struct zwp_input_method_keyboard_grab_v2 *im_keyboard_grab, + uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, + uint32_t mods_locked, uint32_t group) { + printf("handle_modifiers %u %u %u %u %u\n", serial, mods_depressed, + mods_latched, mods_locked, group); + xkb_state_update_mask(xkb_state, mods_depressed, mods_latched, + mods_locked, 0, 0, group); +} + +static void handle_keymap(void *data, + struct zwp_input_method_keyboard_grab_v2 *im_keyboard_grab, + uint32_t format, int32_t fd, uint32_t size) { + printf("handle_keymap\n"); + char *keymap_string = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + xkb_keymap_unref(keymap); + keymap = xkb_keymap_new_from_string(xkb_context, keymap_string, + XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); + munmap(keymap_string, size); + close(fd); + xkb_state_unref(xkb_state); + xkb_state = xkb_state_new(keymap); +} + +static void handle_repeat_info(void *data, + struct zwp_input_method_keyboard_grab_v2 *im_keyboard_grab, + int32_t rate, int32_t delay) { + printf("handle_repeat_info %d %d", rate, delay); +} + + +static const struct zwp_input_method_keyboard_grab_v2_listener grab_listener = { + .key = handle_key, + .modifiers = handle_modifiers, + .keymap = handle_keymap, + .repeat_info = handle_repeat_info, +}; + +static void handle_activate(void *data, + struct zwp_input_method_v2 *zwp_input_method_v2) { + pending_active = true; +} + +static void handle_deactivate(void *data, + struct zwp_input_method_v2 *zwp_input_method_v2) { + pending_active = false; +} + +static void handle_unavailable(void *data, + struct zwp_input_method_v2 *zwp_input_method_v2) { + printf("IM unavailable\n"); + zwp_input_method_v2_destroy(zwp_input_method_v2); + input_method = NULL; +} + +static void im_activate(void *data, + struct zwp_input_method_v2 *id) { + kb_grab = zwp_input_method_v2_grab_keyboard(input_method); + if (kb_grab == NULL) { + fprintf(stderr, "Failed to grab\n"); + exit(EXIT_FAILURE); + } + zwp_input_method_keyboard_grab_v2_add_listener(kb_grab, &grab_listener, + NULL); + printf("Started grab, press enter to stop grab\n"); +} + +static void im_deactivate(void *data, + struct zwp_input_method_v2 *context) { + if (kb_grab != NULL) { + zwp_input_method_keyboard_grab_v2_release(kb_grab); + kb_grab = NULL; + } +} + +static void handle_done(void *data, + struct zwp_input_method_v2 *zwp_input_method_v2) { + bool prev_active = active; + if (active != pending_active) { + printf("Now %s\n", pending_active ? "active" : "inactive"); + } + active = pending_active; + if (active && !prev_active) { + im_activate(data, zwp_input_method_v2); + } else if (!active && prev_active) { + im_deactivate(data, zwp_input_method_v2); + } +} + +static void handle_surrounding_text(void *data, + struct zwp_input_method_v2 *zwp_input_method_v2, + const char *text, uint32_t cursor, uint32_t anchor) { + // not for this test +} + +static void handle_text_change_cause(void *data, + struct zwp_input_method_v2 *zwp_input_method_v2, + uint32_t cause) { + // not for this test +} + +static void handle_content_type(void *data, + struct zwp_input_method_v2 *zwp_input_method_v2, + uint32_t hint, uint32_t purpose) { + // not for this test +} + +static const struct zwp_input_method_v2_listener im_listener = { + .activate = handle_activate, + .deactivate = handle_deactivate, + .surrounding_text = handle_surrounding_text, + .text_change_cause = handle_text_change_cause, + .content_type = handle_content_type, + .done = handle_done, + .unavailable = handle_unavailable, +}; + +static void handle_global(void *data, struct wl_registry *registry, + uint32_t name, const char *interface, uint32_t version) { + if (strcmp(interface, zwp_input_method_manager_v2_interface.name) == 0) { + input_method_manager = wl_registry_bind(registry, name, + &zwp_input_method_manager_v2_interface, 1); + } else if (strcmp(interface, wl_seat_interface.name) == 0) { + seat = wl_registry_bind(registry, name, &wl_seat_interface, version); + } +} + +static void handle_global_remove(void *data, struct wl_registry *registry, + uint32_t name) { + // who cares +} + +static const struct wl_registry_listener registry_listener = { + .global = handle_global, + .global_remove = handle_global_remove, +}; + +int main(int argc, char **argv) { + xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + if (xkb_context == NULL) { + fprintf(stderr, "Failed to create xkb context\n"); + return EXIT_FAILURE; + } + + display = wl_display_connect(NULL); + if (display == NULL) { + fprintf(stderr, "Failed to create display\n"); + return EXIT_FAILURE; + } + + struct wl_registry *registry = wl_display_get_registry(display); + wl_registry_add_listener(registry, ®istry_listener, NULL); + wl_display_dispatch(display); + wl_display_roundtrip(display); + + if (input_method_manager == NULL) { + fprintf(stderr, "input-method not available\n"); + return EXIT_FAILURE; + } + if (seat == NULL) { + fprintf(stderr, "seat not available\n"); + return EXIT_FAILURE; + } + + input_method = zwp_input_method_manager_v2_get_input_method( + input_method_manager, seat); + zwp_input_method_v2_add_listener(input_method, &im_listener, NULL); + + wl_display_roundtrip(display); + + while (wl_display_dispatch(display) != -1) { + // This space is intentionally left blank + }; + + return EXIT_SUCCESS; +} diff --git a/examples/meson.build b/examples/meson.build index 5668b7ecb..c8016d3a0 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -170,6 +170,13 @@ clients = { 'dep': wlroots, 'proto': ['wlr-virtual-pointer-unstable-v1'], }, + 'input-method-keyboard-grab': { + 'src': 'input-method-keyboard-grab.c', + 'dep': xkbcommon, + 'proto': [ + 'input-method-unstable-v2', + ], + }, } foreach name, info : compositors From 6ef5d18757ef5ae2f38d41d914f7d7df100e3799 Mon Sep 17 00:00:00 2001 From: Andri Yngvason Date: Mon, 13 Jul 2020 18:45:57 +0000 Subject: [PATCH 7/9] render: egl: Use current display to restore NULL context eglGetCurrentDisplay() returns EGL_NO_DISPLAY when there is no context current and eglMakeCurrent() needs a display argument. Fixes #2327 --- render/egl.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/render/egl.c b/render/egl.c index 797d8f15a..f99b37f90 100644 --- a/render/egl.c +++ b/render/egl.c @@ -459,7 +459,20 @@ void wlr_egl_save_context(struct wlr_egl_context *context) { } bool wlr_egl_restore_context(struct wlr_egl_context *context) { - return eglMakeCurrent(context->display, context->draw_surface, + // If the saved context is a null-context, we must use the current + // display instead of the saved display because eglMakeCurrent() can't + // handle EGL_NO_DISPLAY. + EGLDisplay display = context->display == EGL_NO_DISPLAY ? + eglGetCurrentDisplay() : context->display; + + // If the current display is also EGL_NO_DISPLAY, we assume that there + // is currently no context set and no action needs to be taken to unset + // the context. + if (display == EGL_NO_DISPLAY) { + return true; + } + + return eglMakeCurrent(display, context->draw_surface, context->read_surface, context->context); } From a145430afac6e1d0fbf65250b25573fdf1b2e4fd Mon Sep 17 00:00:00 2001 From: Tudor Brindus Date: Fri, 3 Jul 2020 00:52:25 -0400 Subject: [PATCH 8/9] input/pointer: add wlr_seat_pointer_wrap It allows a compositor to do things like skip motion events on pointer constraint unlock. References: https://github.com/swaywm/sway/pull/5431 --- include/wlr/types/wlr_seat.h | 6 ++++++ types/seat/wlr_seat_pointer.c | 14 ++++++++------ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/include/wlr/types/wlr_seat.h b/include/wlr/types/wlr_seat.h index 7b47da089..332ab0d30 100644 --- a/include/wlr/types/wlr_seat.h +++ b/include/wlr/types/wlr_seat.h @@ -409,6 +409,12 @@ void wlr_seat_pointer_notify_enter(struct wlr_seat *wlr_seat, */ void wlr_seat_pointer_notify_clear_focus(struct wlr_seat *wlr_seat); +/** + * Warp the pointer of this seat to the given surface-local coordinates, without + * generating motion events. + */ +void wlr_seat_pointer_warp(struct wlr_seat *wlr_seat, double sx, double sy); + /** * Notify the seat of motion over the given surface. Pass surface-local * coordinates where the pointer motion occurred. Defers to any grab of the diff --git a/types/seat/wlr_seat_pointer.c b/types/seat/wlr_seat_pointer.c index 9ad5f88c6..37c637b53 100644 --- a/types/seat/wlr_seat_pointer.c +++ b/types/seat/wlr_seat_pointer.c @@ -199,11 +199,9 @@ void wlr_seat_pointer_enter(struct wlr_seat *wlr_seat, wlr_seat->pointer_state.focused_client = client; wlr_seat->pointer_state.focused_surface = surface; if (surface != NULL) { - wlr_seat->pointer_state.sx = sx; - wlr_seat->pointer_state.sy = sy; + wlr_seat_pointer_warp(wlr_seat, sx, sy); } else { - wlr_seat->pointer_state.sx = NAN; - wlr_seat->pointer_state.sy = NAN; + wlr_seat_pointer_warp(wlr_seat, NAN, NAN); } struct wlr_seat_pointer_focus_change_event event = { @@ -220,6 +218,11 @@ void wlr_seat_pointer_clear_focus(struct wlr_seat *wlr_seat) { wlr_seat_pointer_enter(wlr_seat, NULL, 0, 0); } +void wlr_seat_pointer_warp(struct wlr_seat *wlr_seat, double sx, double sy) { + wlr_seat->pointer_state.sx = sx; + wlr_seat->pointer_state.sy = sy; +} + void wlr_seat_pointer_send_motion(struct wlr_seat *wlr_seat, uint32_t time, double sx, double sy) { struct wlr_seat_client *client = wlr_seat->pointer_state.focused_client; @@ -241,8 +244,7 @@ void wlr_seat_pointer_send_motion(struct wlr_seat *wlr_seat, uint32_t time, wl_fixed_from_double(sy)); } - wlr_seat->pointer_state.sx = sx; - wlr_seat->pointer_state.sy = sy; + wlr_seat_pointer_warp(wlr_seat, sx, sy); } uint32_t wlr_seat_pointer_send_button(struct wlr_seat *wlr_seat, uint32_t time, From 751a21d94f1b4f0345d040ddfd54b723631d5991 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 16 Jul 2020 00:27:23 +0200 Subject: [PATCH 9/9] Update version to 0.11.0 --- meson.build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index a6dad5d6c..4abe63181 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'wlroots', 'c', - version: '0.10.0', + version: '0.11.0', license: 'MIT', meson_version: '>=0.54.0', default_options: [ @@ -15,7 +15,7 @@ project( # necessary for bugfix releases. Increasing soversion is required because # wlroots never guarantees ABI stability -- only API stability is guaranteed # between minor releases. -soversion = 5 +soversion = 6 add_project_arguments([ '-DWLR_USE_UNSTABLE',