mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2026-04-18 06:47:31 -04:00
Merge branch 'wayland-output-grab-input' into 'master'
Add the ability for wayland output to grab input See merge request wlroots/wlroots!4441
This commit is contained in:
commit
c873399d01
7 changed files with 266 additions and 5 deletions
|
|
@ -4,6 +4,8 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <strings.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include <wayland-server-core.h>
|
||||
|
||||
#include <wlr/backend/headless.h>
|
||||
|
|
@ -13,6 +15,7 @@
|
|||
#include <wlr/config.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include <wlr/types/wlr_keyboard.h>
|
||||
#include "backend/backend.h"
|
||||
#include "backend/multi.h"
|
||||
#include "render/allocator/allocator.h"
|
||||
|
|
@ -146,6 +149,37 @@ static size_t parse_outputs_env(const char *name) {
|
|||
return outputs;
|
||||
}
|
||||
|
||||
// This code was copied from sway wm source code,
|
||||
// from https://github.com/swaywm/sway/blob/7cf4e1d/sway/input/keyboard.c
|
||||
// ____________________________________________________
|
||||
static struct modifier_key {
|
||||
char *name;
|
||||
uint32_t mod;
|
||||
} modifiers[] = {
|
||||
{ XKB_MOD_NAME_SHIFT, WLR_MODIFIER_SHIFT },
|
||||
{ XKB_MOD_NAME_CAPS , WLR_MODIFIER_CAPS },
|
||||
{ XKB_MOD_NAME_CTRL , WLR_MODIFIER_CTRL },
|
||||
{ "Ctrl" , WLR_MODIFIER_CTRL },
|
||||
{ XKB_MOD_NAME_ALT , WLR_MODIFIER_ALT },
|
||||
{ "Alt" , WLR_MODIFIER_ALT },
|
||||
{ XKB_MOD_NAME_NUM , WLR_MODIFIER_MOD2 },
|
||||
{ "Mod3" , WLR_MODIFIER_MOD3 },
|
||||
{ XKB_MOD_NAME_LOGO , WLR_MODIFIER_LOGO },
|
||||
{ "Mod5" , WLR_MODIFIER_MOD5 },
|
||||
};
|
||||
|
||||
static uint32_t get_modifier_mask_by_name(const char *name) {
|
||||
int i;
|
||||
for (i = 0; i < (int)(sizeof(modifiers) / sizeof(struct modifier_key)); ++i) {
|
||||
if (strcasecmp(modifiers[i].name, name) == 0) {
|
||||
return modifiers[i].mod;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
// ____________________________________________________)
|
||||
|
||||
static struct wlr_backend *attempt_wl_backend(struct wl_display *display) {
|
||||
struct wlr_backend *backend = wlr_wl_backend_create(display, NULL);
|
||||
if (backend == NULL) {
|
||||
|
|
@ -157,6 +191,37 @@ static struct wlr_backend *attempt_wl_backend(struct wl_display *display) {
|
|||
wlr_wl_output_create(backend);
|
||||
}
|
||||
|
||||
char* keyboard_shortcut = getenv("WLR_WL_GRAB_INPUT_SHORTCUT");
|
||||
if (keyboard_shortcut) {
|
||||
wlr_log(WLR_INFO, "Loading user-specified input grab keyboard shortcut: %s",
|
||||
keyboard_shortcut);
|
||||
xkb_keysym_t input_grab_keysym = 0;
|
||||
uint32_t input_grab_modifier_mask = 0;
|
||||
keyboard_shortcut = strdup(keyboard_shortcut);
|
||||
|
||||
char *saveptr;
|
||||
char *key_name = strtok_r(keyboard_shortcut, "+", &saveptr);
|
||||
while (key_name != NULL) {
|
||||
|
||||
uint32_t modifier_mask = get_modifier_mask_by_name(key_name);
|
||||
input_grab_modifier_mask = input_grab_modifier_mask | modifier_mask;
|
||||
if(modifier_mask == 0) {
|
||||
input_grab_keysym = xkb_keysym_from_name(key_name,XKB_KEYSYM_CASE_INSENSITIVE);
|
||||
if(input_grab_keysym == 0) {
|
||||
wlr_log(WLR_ERROR,
|
||||
"The key shortcut contains an unrecognized key name. ignoring key shortcut");
|
||||
input_grab_keysym = 0;
|
||||
input_grab_modifier_mask = 0;
|
||||
free(keyboard_shortcut);
|
||||
return backend;
|
||||
}
|
||||
}
|
||||
key_name = strtok_r(NULL, "+", &saveptr);
|
||||
}
|
||||
free(keyboard_shortcut);
|
||||
wlr_wl_backend_set_grab_input_shortcut(backend, input_grab_modifier_mask, input_grab_keysym);
|
||||
}
|
||||
|
||||
return backend;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
|
||||
#include <wayland-client.h>
|
||||
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ wlroots reads these environment variables
|
|||
## Wayland backend
|
||||
|
||||
* *WLR_WL_OUTPUTS*: when using the wayland backend specifies the number of outputs
|
||||
* *WLR_WL_GRAB_INPUT_SHORTCUT*: when using the wayland backend, specify the shortcut (mods+key) to toggle input grab of the focused wayland output. Examples: control+shift+alt, control_r, alt_l.
|
||||
|
||||
## X11 backend
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
@ -135,6 +140,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;
|
||||
|
|
@ -151,6 +157,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
|
||||
};
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include <wayland-server-core.h>
|
||||
#include <wlr/backend.h>
|
||||
#include <wlr/types/wlr_output.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
|
||||
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.
|
||||
*
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue