xwayland: add (fake) device grab support
Add a new command line option "-host-grab" to disable the keyboard shortcuts and confine the pointer on the host so that Xwayland can receive all keyboard events. This is useful when running a complete desktop environment within Xwayland rootful. Use [CTRL]+[SHIFT] to release the keyboard and pointer. This option is not compatible with rootless mode. Signed-off-by: Olivier Fourdan <ofourdan@redhat.com> Reviewed-by: Adam Jackson <ajax@redhat.com>
This commit is contained in:
parent
503e7663f8
commit
c03e582f0c
|
@ -61,6 +61,19 @@ This option is not compatible with rootless mode (\fI-rootless\fP).
|
|||
.B \-geometry \fIWxH\fP
|
||||
Sets the geometry of the \fIXwayland\fP window to \fIWxH\fP when running rootful.
|
||||
|
||||
This option is not compatible with rootless mode (\fI-rootless\fP).
|
||||
.TP 8
|
||||
.B \-host-grab
|
||||
Disable host keyboard shorcuts and confine the pointer when running rootful.
|
||||
|
||||
This feature relies on the protocol for inhibiting the compositor keyboard
|
||||
shortcuts and on the protocol for pointer locking and confinement and may
|
||||
have no effect if the Wayland compositor in use does not support these
|
||||
protocols.
|
||||
|
||||
Use the keys [CTRL]+[SHIFT] simultaneously to release the keyboard and
|
||||
pointer devices.
|
||||
|
||||
This option is not compatible with rootless mode (\fI-rootless\fP).
|
||||
.TP 8
|
||||
.B \-initfd \fIfd\fP
|
||||
|
|
|
@ -46,6 +46,7 @@ dmabuf_xml = join_paths(protodir, 'unstable', 'linux-dmabuf', 'linux-dmabuf-unst
|
|||
viewporter_xml = join_paths(protodir, 'stable', 'viewporter', 'viewporter.xml')
|
||||
xdg_shell_xml = join_paths(protodir, 'stable', 'xdg-shell', 'xdg-shell.xml')
|
||||
drm_lease_xml = join_paths(protodir, 'staging', 'drm-lease', 'drm-lease-v1.xml')
|
||||
shortcuts_inhibit_xml = join_paths(protodir, 'unstable', 'keyboard-shortcuts-inhibit', 'keyboard-shortcuts-inhibit-unstable-v1.xml')
|
||||
|
||||
client_header = generator(scanner,
|
||||
output : '@BASENAME@-client-protocol.h',
|
||||
|
@ -72,6 +73,7 @@ srcs += client_header.process(dmabuf_xml)
|
|||
srcs += client_header.process(viewporter_xml)
|
||||
srcs += client_header.process(xdg_shell_xml)
|
||||
srcs += client_header.process(drm_lease_xml)
|
||||
srcs += client_header.process(shortcuts_inhibit_xml)
|
||||
srcs += code.process(relative_xml)
|
||||
srcs += code.process(pointer_xml)
|
||||
srcs += code.process(gestures_xml)
|
||||
|
@ -82,6 +84,7 @@ srcs += code.process(dmabuf_xml)
|
|||
srcs += code.process(viewporter_xml)
|
||||
srcs += code.process(xdg_shell_xml)
|
||||
srcs += code.process(drm_lease_xml)
|
||||
srcs += code.process(shortcuts_inhibit_xml)
|
||||
|
||||
xwayland_glamor = []
|
||||
eglstream_srcs = []
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
#include "tablet-unstable-v2-client-protocol.h"
|
||||
#include "pointer-gestures-unstable-v1-client-protocol.h"
|
||||
#include "xwayland-keyboard-grab-unstable-v1-client-protocol.h"
|
||||
#include "keyboard-shortcuts-inhibit-unstable-v1-client-protocol.h"
|
||||
|
||||
struct axis_discrete_pending {
|
||||
struct xorg_list l;
|
||||
|
@ -128,6 +129,57 @@ init_pointer_buttons(DeviceIntPtr device)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
maybe_fake_grab_devices(struct xwl_seat *xwl_seat)
|
||||
{
|
||||
struct xwl_screen *xwl_screen = xwl_seat->xwl_screen;
|
||||
struct xwl_window *xwl_window;
|
||||
|
||||
if (xwl_screen->rootless)
|
||||
return;
|
||||
|
||||
if (!xwl_screen->host_grab)
|
||||
return;
|
||||
|
||||
if (!xwl_screen->has_grab)
|
||||
return;
|
||||
|
||||
if (!xwl_screen->screen->root)
|
||||
return;
|
||||
|
||||
xwl_window = xwl_window_get(xwl_screen->screen->root);
|
||||
if (!xwl_window)
|
||||
return;
|
||||
|
||||
xwl_seat_confine_pointer(xwl_seat, xwl_window);
|
||||
|
||||
if (!xwl_screen->shortcuts_inhibit_manager)
|
||||
return;
|
||||
|
||||
if (xwl_screen->shortcuts_inhibit)
|
||||
return;
|
||||
|
||||
xwl_screen->shortcuts_inhibit =
|
||||
zwp_keyboard_shortcuts_inhibit_manager_v1_inhibit_shortcuts (
|
||||
xwl_screen->shortcuts_inhibit_manager,
|
||||
xwl_window->surface,
|
||||
xwl_seat->seat);
|
||||
}
|
||||
|
||||
static void
|
||||
maybe_fake_ungrab_devices(struct xwl_seat *xwl_seat)
|
||||
{
|
||||
struct xwl_screen *xwl_screen = xwl_seat->xwl_screen;
|
||||
|
||||
xwl_seat_unconfine_pointer(xwl_seat);
|
||||
|
||||
if (!xwl_screen->shortcuts_inhibit)
|
||||
return;
|
||||
|
||||
zwp_keyboard_shortcuts_inhibitor_v1_destroy (xwl_screen->shortcuts_inhibit);
|
||||
xwl_screen->shortcuts_inhibit = NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
xwl_pointer_proc(DeviceIntPtr device, int what)
|
||||
{
|
||||
|
@ -520,6 +572,8 @@ pointer_handle_enter(void *data, struct wl_pointer *pointer,
|
|||
else {
|
||||
xwl_seat_maybe_lock_on_hidden_cursor(xwl_seat);
|
||||
}
|
||||
|
||||
maybe_fake_grab_devices(xwl_seat);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -539,6 +593,8 @@ pointer_handle_leave(void *data, struct wl_pointer *pointer,
|
|||
xwl_seat->focus_window = NULL;
|
||||
CheckMotion(NULL, GetMaster(dev, POINTER_OR_FLOAT));
|
||||
}
|
||||
|
||||
maybe_fake_ungrab_devices(xwl_seat);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -927,6 +983,34 @@ static const struct zwp_pointer_gesture_pinch_v1_listener pointer_gesture_pinch_
|
|||
pointer_gesture_pinch_handle_end
|
||||
};
|
||||
|
||||
static void
|
||||
maybe_toggle_fake_grab(struct xwl_seat *xwl_seat, uint32_t key)
|
||||
{
|
||||
struct xwl_screen *xwl_screen = xwl_seat->xwl_screen;
|
||||
XkbStateRec state_rec;
|
||||
uint32_t xkb_state;
|
||||
|
||||
if (xwl_screen->rootless)
|
||||
return;
|
||||
|
||||
if (!xwl_screen->host_grab)
|
||||
return;
|
||||
|
||||
state_rec = xwl_seat->keyboard->key->xkbInfo->state;
|
||||
xkb_state = (XkbStateFieldFromRec(&state_rec) & 0xff);
|
||||
|
||||
if (((key == KEY_LEFTSHIFT || key == KEY_RIGHTSHIFT) && (xkb_state & ControlMask)) ||
|
||||
((key == KEY_LEFTCTRL || key == KEY_RIGHTCTRL) && (xkb_state & ShiftMask))) {
|
||||
|
||||
xwl_screen->has_grab = !xwl_screen->has_grab;
|
||||
|
||||
if (xwl_screen->has_grab)
|
||||
maybe_fake_grab_devices(xwl_seat);
|
||||
else
|
||||
maybe_fake_ungrab_devices(xwl_seat);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
keyboard_handle_key(void *data, struct wl_keyboard *keyboard, uint32_t serial,
|
||||
uint32_t time, uint32_t key, uint32_t state)
|
||||
|
@ -949,6 +1033,9 @@ keyboard_handle_key(void *data, struct wl_keyboard *keyboard, uint32_t serial,
|
|||
|
||||
QueueKeyboardEvents(xwl_seat->keyboard,
|
||||
state ? KeyPress : KeyRelease, key + 8);
|
||||
|
||||
if (!state)
|
||||
maybe_toggle_fake_grab(xwl_seat, key);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1009,6 +1096,8 @@ keyboard_handle_enter(void *data, struct wl_keyboard *keyboard,
|
|||
wl_array_copy(&xwl_seat->keys, keys);
|
||||
wl_array_for_each(k, &xwl_seat->keys)
|
||||
QueueKeyboardEvents(xwl_seat->keyboard, EnterNotify, *k + 8);
|
||||
|
||||
maybe_fake_grab_devices(xwl_seat);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1024,6 +1113,8 @@ keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
|
|||
QueueKeyboardEvents(xwl_seat->keyboard, LeaveNotify, *k + 8);
|
||||
|
||||
xwl_seat->keyboard_focus = NULL;
|
||||
|
||||
maybe_fake_ungrab_devices(xwl_seat);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -2824,6 +2915,16 @@ init_keyboard_grab(struct xwl_screen *xwl_screen,
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
init_keyboard_shortcuts_inhibit(struct xwl_screen *xwl_screen,
|
||||
uint32_t id, uint32_t version)
|
||||
{
|
||||
xwl_screen->shortcuts_inhibit_manager =
|
||||
wl_registry_bind(xwl_screen->registry, id,
|
||||
&zwp_keyboard_shortcuts_inhibit_manager_v1_interface,
|
||||
1);
|
||||
}
|
||||
|
||||
/* The compositor may send us wl_seat and its capabilities before sending e.g.
|
||||
relative_pointer_manager or pointer_gesture interfaces. This would result in
|
||||
devices being created in capabilities handler, but listeners not, because
|
||||
|
@ -2873,6 +2974,8 @@ input_handler(void *data, struct wl_registry *registry, uint32_t id,
|
|||
init_tablet_manager(xwl_screen, id, version);
|
||||
} else if (strcmp(interface, "zwp_xwayland_keyboard_grab_manager_v1") == 0) {
|
||||
init_keyboard_grab(xwl_screen, id, version);
|
||||
} else if (strcmp(interface, "zwp_keyboard_shortcuts_inhibit_manager_v1") == 0) {
|
||||
init_keyboard_shortcuts_inhibit(xwl_screen, id, version);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -306,6 +306,12 @@ xwl_cursor_confined_to(DeviceIntPtr device,
|
|||
struct xwl_seat *xwl_seat = device->public.devicePrivate;
|
||||
struct xwl_window *xwl_window;
|
||||
|
||||
/* If running rootful with host grab requested, do not tamper with
|
||||
* pointer confinement.
|
||||
*/
|
||||
if (!xwl_screen->rootless && xwl_screen->host_grab && xwl_screen->has_grab)
|
||||
return;
|
||||
|
||||
if (!xwl_seat)
|
||||
xwl_seat = xwl_screen_get_default_seat(xwl_screen);
|
||||
|
||||
|
@ -679,6 +685,10 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
|
|||
else if (strcmp(argv[i], "-fullscreen") == 0) {
|
||||
xwl_screen->fullscreen = 1;
|
||||
}
|
||||
else if (strcmp(argv[i], "-host-grab") == 0) {
|
||||
xwl_screen->host_grab = 1;
|
||||
xwl_screen->has_grab = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (use_fixed_size) {
|
||||
|
@ -745,6 +755,11 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
|
|||
xwl_screen->fullscreen = FALSE;
|
||||
}
|
||||
|
||||
if (xwl_screen->host_grab && xwl_screen->rootless) {
|
||||
ErrorF("error, cannot use host grab when running rootless\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!xwl_screen->rootless && !xwl_screen->xdg_wm_base) {
|
||||
ErrorF("missing XDG-WM-Base protocol\n");
|
||||
return FALSE;
|
||||
|
|
|
@ -59,6 +59,8 @@ struct xwl_screen {
|
|||
int present;
|
||||
int force_xrandr_emulation;
|
||||
int fullscreen;
|
||||
int host_grab;
|
||||
int has_grab;
|
||||
|
||||
CreateScreenResourcesProcPtr CreateScreenResources;
|
||||
CloseScreenProcPtr CloseScreen;
|
||||
|
@ -88,6 +90,8 @@ struct xwl_screen {
|
|||
struct zwp_pointer_constraints_v1 *pointer_constraints;
|
||||
struct zwp_pointer_gestures_v1 *pointer_gestures;
|
||||
struct zwp_xwayland_keyboard_grab_manager_v1 *wp_grab;
|
||||
struct zwp_keyboard_shortcuts_inhibit_manager_v1 *shortcuts_inhibit_manager;
|
||||
struct zwp_keyboard_shortcuts_inhibitor_v1 *shortcuts_inhibit;
|
||||
struct zwp_linux_dmabuf_v1 *dmabuf;
|
||||
struct zxdg_output_manager_v1 *xdg_output_manager;
|
||||
struct wp_viewporter *viewporter;
|
||||
|
|
|
@ -93,6 +93,7 @@ ddxUseMsg(void)
|
|||
ErrorF("-rootless run rootless, requires wm support\n");
|
||||
ErrorF("-fullscreen run fullscreen when rootful\n");
|
||||
ErrorF("-geometry WxH set Xwayland window size when rootful\n");
|
||||
ErrorF("-host-grab disable host keyboard shortcuts when rootful\n");
|
||||
ErrorF("-wm fd create X client for wm on given fd\n");
|
||||
ErrorF("-initfd fd add given fd as a listen socket for initialization clients\n");
|
||||
ErrorF("-listenfd fd add given fd as a listen socket\n");
|
||||
|
@ -233,6 +234,9 @@ ddxProcessArgument(int argc, char *argv[], int i)
|
|||
else if (strcmp(argv[i], "-fullscreen") == 0) {
|
||||
return 1;
|
||||
}
|
||||
else if (strcmp(argv[i], "-host-grab") == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -15,3 +15,4 @@ have_no_touch_pointer_emulation=true
|
|||
have_force_xrandr_emulation=true
|
||||
have_geometry=true
|
||||
have_fullscreen=true
|
||||
have_host_grab=true
|
||||
|
|
Loading…
Reference in New Issue