From fae0a7d493c249e2faa47a13bdb651b574d4c8ff Mon Sep 17 00:00:00 2001 From: Lahav T Date: Tue, 21 Nov 2023 23:09:00 +0200 Subject: [PATCH] backend/wayland: Add wlr_wl_backend_set_grab_input_shortcut Note: For the function to work, keyboard_listener in backend/wayland/seat.c now passes wlr_wl_seat instead of wlr_keyboard by using this function, a compositor can specify a keyboard shortcut that when pressed, will disable the keyboard shortcuts and confine the pointer to the currently focused wayland output, if the system compositor supports these features. Signed-off-by: Lahav T --- backend/wayland/backend.c | 21 +++++ backend/wayland/meson.build | 2 + backend/wayland/seat.c | 164 ++++++++++++++++++++++++++++++++-- include/backend/wayland.h | 8 ++ include/wlr/backend/wayland.h | 10 +++ 5 files changed, 200 insertions(+), 5 deletions(-) diff --git a/backend/wayland/backend.c b/backend/wayland/backend.c index 9f78b6f1b..46f22c493 100644 --- a/backend/wayland/backend.c +++ b/backend/wayland/backend.c @@ -30,6 +30,8 @@ #include "tablet-unstable-v2-client-protocol.h" #include "relative-pointer-unstable-v1-client-protocol.h" #include "viewporter-client-protocol.h" +#include "pointer-constraints-unstable-v1-client-protocol.h" +#include "keyboard-shortcuts-inhibit-unstable-v1-client-protocol.h" struct wlr_wl_linux_dmabuf_feedback_v1 { struct wlr_wl_backend *backend; @@ -405,6 +407,12 @@ static void registry_global(void *data, struct wl_registry *registry, } else if (strcmp(iface, wp_viewporter_interface.name) == 0) { wl->viewporter = wl_registry_bind(registry, name, &wp_viewporter_interface, 1); + } else if (strcmp(iface,zwp_pointer_constraints_v1_interface.name)==0) { + wl->pointer_constraints = wl_registry_bind(registry, name, + &zwp_pointer_constraints_v1_interface, 1); + } else if(strcmp(iface,zwp_keyboard_shortcuts_inhibit_manager_v1_interface.name)==0) { + wl->shortcuts_inhibit_manager = wl_registry_bind(registry, name, + &zwp_keyboard_shortcuts_inhibit_manager_v1_interface, 1); } } @@ -506,6 +514,12 @@ static void backend_destroy(struct wlr_backend *backend) { if (wl->tablet_manager) { zwp_tablet_manager_v2_destroy(wl->tablet_manager); } + if(wl->pointer_constraints) { + zwp_pointer_constraints_v1_destroy (wl->pointer_constraints); + } + if(wl->shortcuts_inhibit_manager) { + zwp_keyboard_shortcuts_inhibit_manager_v1_destroy (wl->shortcuts_inhibit_manager); + } if (wl->presentation) { wp_presentation_destroy(wl->presentation); } @@ -702,3 +716,10 @@ struct wl_display *wlr_wl_backend_get_remote_display(struct wlr_backend *backend struct wlr_wl_backend *wl = get_wl_backend_from_backend(backend); return wl->remote_display; } + +void wlr_wl_backend_set_grab_input_shortcut(struct wlr_backend *backend, uint32_t modifiers_mask, + xkb_keysym_t keysym) { + struct wlr_wl_backend *wl = get_wl_backend_from_backend(backend); + wl->input_grab_modifiers_mask = modifiers_mask; + wl->input_grab_keysym = keysym; +} diff --git a/backend/wayland/meson.build b/backend/wayland/meson.build index 0fd528cf9..572216ffd 100644 --- a/backend/wayland/meson.build +++ b/backend/wayland/meson.build @@ -23,6 +23,8 @@ client_protos = [ 'xdg-activation-v1', 'xdg-decoration-unstable-v1', 'xdg-shell', + 'pointer-constraints-unstable-v1', + 'keyboard-shortcuts-inhibit-unstable-v1', ] foreach proto : client_protos diff --git a/backend/wayland/seat.c b/backend/wayland/seat.c index d88a370f3..57c657ece 100644 --- a/backend/wayland/seat.c +++ b/backend/wayland/seat.c @@ -6,6 +6,7 @@ #include #include #include +#include #include @@ -19,6 +20,151 @@ #include "backend/wayland.h" #include "util/time.h" +#include "keyboard-shortcuts-inhibit-unstable-v1-client-protocol.h" +#include "pointer-constraints-unstable-v1-client-protocol.h" + +//these functions are based on functions with simillar names from xwayland code +// (https://gitlab.freedesktop.org/xorg/xserver/-/blob/befef003/hw/xwayland/xwayland-input.c) +// ______________________________________________________________________ +static void wlr_wl_seat_destroy_confined_pointer(struct wlr_wl_seat *seat) { + if(seat->confined_pointer != NULL) { + zwp_confined_pointer_v1_destroy(seat->confined_pointer); + seat->confined_pointer = NULL; + } + +} + +static void wlr_wl_seat_unconfine_pointer(struct wlr_wl_seat *seat) { + + if (seat->confined_pointer) { + wlr_wl_seat_destroy_confined_pointer(seat); + } +} + +static void wlr_wl_seat_confine_pointer(struct wlr_wl_seat *seat) { + struct zwp_pointer_constraints_v1 *pointer_constraints = + seat->backend->pointer_constraints; + + if (!pointer_constraints) { + return; + } + + + if (!seat->wl_pointer) { + return; + } + + if (seat->confined_pointer) { + return; + } + + + wlr_wl_seat_unconfine_pointer(seat); + + struct wl_surface *surface = seat->grab_surface; + if(surface == NULL) { + wlr_log (WLR_INFO, "surface is null!!!"); + return; + } + seat->confined_pointer = + zwp_pointer_constraints_v1_confine_pointer(pointer_constraints, + surface, + seat->wl_pointer, + NULL, + ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT); +} + + +static void maybe_fake_grab_devices(struct wlr_wl_seat *seat) { + wlr_log (WLR_INFO,"Grabbed seat '%s' input!!!!", seat->name); + struct wlr_wl_backend *backend = seat->backend; + + wlr_wl_seat_confine_pointer(seat); + if (!backend->shortcuts_inhibit_manager) { + return; + } + + if (backend->shortcuts_inhibit) { + return; + } + struct wl_surface *surface = seat->grab_surface; + if(surface == NULL) { + wlr_log (WLR_INFO, "surface is null!!!"); + return; + } + backend->shortcuts_inhibit = + zwp_keyboard_shortcuts_inhibit_manager_v1_inhibit_shortcuts ( + backend->shortcuts_inhibit_manager, + surface, + seat->wl_seat); +} + +static void maybe_fake_ungrab_devices(struct wlr_wl_seat *seat) +{ + wlr_log (WLR_INFO,"Released seat '%s' input!!!!", seat->name); + struct wlr_wl_backend *backend = seat->backend; + + wlr_wl_seat_unconfine_pointer(seat); + + if (!backend->shortcuts_inhibit) { + return; + } + zwp_keyboard_shortcuts_inhibitor_v1_destroy (backend->shortcuts_inhibit); + backend->shortcuts_inhibit = NULL; +} +// ______________________________________________________________________ +static bool fake_grab_input_shortcut_was_pressed(xkb_keysym_t keysym, uint32_t depressed_modifiers, + xkb_keysym_t input_grab_keysym, uint32_t input_grab_modifiers_mask) { + + xkb_keysym_t input_grab_keysym_lowercase = xkb_keysym_to_lower(input_grab_keysym); + xkb_keysym_t keysym_lowercase = xkb_keysym_to_lower(keysym); + + if(!input_grab_keysym && !input_grab_modifiers_mask) { + return false; + } + + bool input_grab_only_modifiers = (input_grab_modifiers_mask == depressed_modifiers) + && !input_grab_keysym; + bool input_grab_only_keysym = !input_grab_modifiers_mask + && (input_grab_keysym_lowercase == keysym_lowercase); + bool input_grab_modifiers_and_keysym= (input_grab_modifiers_mask == depressed_modifiers) + && (input_grab_keysym_lowercase==keysym_lowercase); + + return input_grab_only_modifiers || input_grab_only_keysym || input_grab_modifiers_and_keysym; +} + +static void maybe_toggle_fake_grab(struct wlr_wl_seat *seat, uint32_t key, uint32_t state) { + if(seat->grab_surface == NULL) { + wlr_log (WLR_INFO, "input surface is null. not grabbing/releasing!"); + return; + } + + struct wlr_keyboard *keyboard = &seat->wlr_keyboard; + struct xkb_state *xkb_state = keyboard->xkb_state; + + xkb_keysym_t input_grab_keysym = seat->backend->input_grab_keysym; + uint32_t input_grab_modifiers_mask = seat->backend->input_grab_modifiers_mask; + uint32_t depressed_modifiers = keyboard->modifiers.depressed; + + xkb_keysym_t keysym = xkb_state_key_get_one_sym(xkb_state, key + 8); + + if(state != WL_KEYBOARD_KEY_STATE_RELEASED) { + return; + } + + if(fake_grab_input_shortcut_was_pressed(keysym, depressed_modifiers, input_grab_keysym, + input_grab_modifiers_mask)) { + seat->has_grab = !seat->has_grab; + + if (seat->has_grab) { + maybe_fake_grab_devices(seat); + } + + else { + maybe_fake_ungrab_devices(seat); + } + } +} static void keyboard_handle_keymap(void *data, struct wl_keyboard *wl_keyboard, uint32_t format, int32_t fd, uint32_t size) { @@ -27,8 +173,10 @@ static void keyboard_handle_keymap(void *data, struct wl_keyboard *wl_keyboard, static void keyboard_handle_enter(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys) { - struct wlr_keyboard *keyboard = data; + struct wlr_wl_seat *seat = data; + struct wlr_keyboard *keyboard = &seat->wlr_keyboard; + seat->grab_surface = surface; uint32_t *keycode_ptr; wl_array_for_each(keycode_ptr, keys) { struct wlr_keyboard_key_event event = { @@ -43,8 +191,10 @@ static void keyboard_handle_enter(void *data, struct wl_keyboard *wl_keyboard, static void keyboard_handle_leave(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface) { - struct wlr_keyboard *keyboard = data; + struct wlr_wl_seat *seat = data; + struct wlr_keyboard *keyboard = &seat->wlr_keyboard; + seat->grab_surface = NULL; size_t num_keycodes = keyboard->num_keycodes; uint32_t pressed[num_keycodes + 1]; memcpy(pressed, keyboard->keycodes, @@ -65,7 +215,8 @@ static void keyboard_handle_leave(void *data, struct wl_keyboard *wl_keyboard, static void keyboard_handle_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) { - struct wlr_keyboard *keyboard = data; + struct wlr_wl_seat *seat = data; + struct wlr_keyboard *keyboard = &seat->wlr_keyboard; struct wlr_keyboard_key_event wlr_event = { .keycode = key, @@ -74,12 +225,14 @@ static void keyboard_handle_key(void *data, struct wl_keyboard *wl_keyboard, .update_state = false, }; wlr_keyboard_notify_key(keyboard, &wlr_event); + maybe_toggle_fake_grab (seat,key,state); } static void keyboard_handle_modifiers(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) { - struct wlr_keyboard *keyboard = data; + struct wlr_wl_seat *seat = data; + struct wlr_keyboard *keyboard = &seat->wlr_keyboard; wlr_keyboard_notify_modifiers(keyboard, mods_depressed, mods_latched, mods_locked, group); } @@ -109,8 +262,9 @@ void init_seat_keyboard(struct wlr_wl_seat *seat) { snprintf(name, sizeof(name), "wayland-keyboard-%s", seat->name); wlr_keyboard_init(&seat->wlr_keyboard, &keyboard_impl, name); + //passing wlr_wl_seat instead of wlr_keyboard to enable the fake input grab functionality wl_keyboard_add_listener(seat->wl_keyboard, &keyboard_listener, - &seat->wlr_keyboard); + seat); wl_signal_emit_mutable(&seat->backend->backend.events.new_input, &seat->wlr_keyboard.base); diff --git a/include/backend/wayland.h b/include/backend/wayland.h index d6796b448..4134c8b36 100644 --- a/include/backend/wayland.h +++ b/include/backend/wayland.h @@ -18,6 +18,8 @@ struct wlr_wl_backend { struct wlr_backend backend; + uint32_t input_grab_modifiers_mask; //for input grab. + xkb_keysym_t input_grab_keysym; //for input grab. /* local state */ bool started; struct wl_display *local_display; @@ -49,6 +51,9 @@ struct wlr_wl_backend { struct xdg_activation_v1 *activation_v1; struct wl_subcompositor *subcompositor; struct wp_viewporter *viewporter; + struct zwp_pointer_constraints_v1 *pointer_constraints; + struct zwp_keyboard_shortcuts_inhibit_manager_v1 *shortcuts_inhibit_manager; + struct zwp_keyboard_shortcuts_inhibitor_v1 *shortcuts_inhibit; char *drm_render_name; }; @@ -134,6 +139,7 @@ struct wlr_wl_seat { struct wlr_wl_pointer *active_pointer; struct wl_list pointers; // wlr_wl_pointer.link + struct wl_surface *grab_surface; //for fake grabbing input. may be NULL when keyboard focus is not on any wayland output struct zwp_pointer_gesture_swipe_v1 *gesture_swipe; struct zwp_pointer_gesture_pinch_v1 *gesture_pinch; struct zwp_pointer_gesture_hold_v1 *gesture_hold; @@ -150,6 +156,8 @@ struct wlr_wl_seat { struct wlr_tablet_tool wlr_tablet_tool; struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2; struct wlr_tablet_pad wlr_tablet_pad; + struct zwp_confined_pointer_v1 *confined_pointer; + bool has_grab; //for fake grabbing input. may be NULL when no grab was initiated yet. struct wl_list link; // wlr_wl_backend.seats }; diff --git a/include/wlr/backend/wayland.h b/include/wlr/backend/wayland.h index a30bac257..017323e95 100644 --- a/include/wlr/backend/wayland.h +++ b/include/wlr/backend/wayland.h @@ -5,6 +5,7 @@ #include #include #include +#include struct wlr_input_device; @@ -23,6 +24,15 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_display *display, */ struct wl_display *wlr_wl_backend_get_remote_display(struct wlr_backend *backend); +/** + * Sets the keyboard shortcut for toggle grabbing input of the focused wayland backend output. + * + * If modifiers_mask and keysym are zero or null, no shortcut will be used. + * + */ +void wlr_wl_backend_set_grab_input_shortcut(struct wlr_backend *backend, uint32_t modifiers_mask, + xkb_keysym_t keysym); + /** * Adds a new output to this backend. *