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
|
.B \-geometry \fIWxH\fP
|
||||||
Sets the geometry of the \fIXwayland\fP window to \fIWxH\fP when running rootful.
|
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).
|
This option is not compatible with rootless mode (\fI-rootless\fP).
|
||||||
.TP 8
|
.TP 8
|
||||||
.B \-initfd \fIfd\fP
|
.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')
|
viewporter_xml = join_paths(protodir, 'stable', 'viewporter', 'viewporter.xml')
|
||||||
xdg_shell_xml = join_paths(protodir, 'stable', 'xdg-shell', 'xdg-shell.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')
|
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,
|
client_header = generator(scanner,
|
||||||
output : '@BASENAME@-client-protocol.h',
|
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(viewporter_xml)
|
||||||
srcs += client_header.process(xdg_shell_xml)
|
srcs += client_header.process(xdg_shell_xml)
|
||||||
srcs += client_header.process(drm_lease_xml)
|
srcs += client_header.process(drm_lease_xml)
|
||||||
|
srcs += client_header.process(shortcuts_inhibit_xml)
|
||||||
srcs += code.process(relative_xml)
|
srcs += code.process(relative_xml)
|
||||||
srcs += code.process(pointer_xml)
|
srcs += code.process(pointer_xml)
|
||||||
srcs += code.process(gestures_xml)
|
srcs += code.process(gestures_xml)
|
||||||
|
@ -82,6 +84,7 @@ srcs += code.process(dmabuf_xml)
|
||||||
srcs += code.process(viewporter_xml)
|
srcs += code.process(viewporter_xml)
|
||||||
srcs += code.process(xdg_shell_xml)
|
srcs += code.process(xdg_shell_xml)
|
||||||
srcs += code.process(drm_lease_xml)
|
srcs += code.process(drm_lease_xml)
|
||||||
|
srcs += code.process(shortcuts_inhibit_xml)
|
||||||
|
|
||||||
xwayland_glamor = []
|
xwayland_glamor = []
|
||||||
eglstream_srcs = []
|
eglstream_srcs = []
|
||||||
|
|
|
@ -49,6 +49,7 @@
|
||||||
#include "tablet-unstable-v2-client-protocol.h"
|
#include "tablet-unstable-v2-client-protocol.h"
|
||||||
#include "pointer-gestures-unstable-v1-client-protocol.h"
|
#include "pointer-gestures-unstable-v1-client-protocol.h"
|
||||||
#include "xwayland-keyboard-grab-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 axis_discrete_pending {
|
||||||
struct xorg_list l;
|
struct xorg_list l;
|
||||||
|
@ -128,6 +129,57 @@ init_pointer_buttons(DeviceIntPtr device)
|
||||||
return TRUE;
|
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
|
static int
|
||||||
xwl_pointer_proc(DeviceIntPtr device, int what)
|
xwl_pointer_proc(DeviceIntPtr device, int what)
|
||||||
{
|
{
|
||||||
|
@ -520,6 +572,8 @@ pointer_handle_enter(void *data, struct wl_pointer *pointer,
|
||||||
else {
|
else {
|
||||||
xwl_seat_maybe_lock_on_hidden_cursor(xwl_seat);
|
xwl_seat_maybe_lock_on_hidden_cursor(xwl_seat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
maybe_fake_grab_devices(xwl_seat);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -539,6 +593,8 @@ pointer_handle_leave(void *data, struct wl_pointer *pointer,
|
||||||
xwl_seat->focus_window = NULL;
|
xwl_seat->focus_window = NULL;
|
||||||
CheckMotion(NULL, GetMaster(dev, POINTER_OR_FLOAT));
|
CheckMotion(NULL, GetMaster(dev, POINTER_OR_FLOAT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
maybe_fake_ungrab_devices(xwl_seat);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -927,6 +983,34 @@ static const struct zwp_pointer_gesture_pinch_v1_listener pointer_gesture_pinch_
|
||||||
pointer_gesture_pinch_handle_end
|
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
|
static void
|
||||||
keyboard_handle_key(void *data, struct wl_keyboard *keyboard, uint32_t serial,
|
keyboard_handle_key(void *data, struct wl_keyboard *keyboard, uint32_t serial,
|
||||||
uint32_t time, uint32_t key, uint32_t state)
|
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,
|
QueueKeyboardEvents(xwl_seat->keyboard,
|
||||||
state ? KeyPress : KeyRelease, key + 8);
|
state ? KeyPress : KeyRelease, key + 8);
|
||||||
|
|
||||||
|
if (!state)
|
||||||
|
maybe_toggle_fake_grab(xwl_seat, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1009,6 +1096,8 @@ keyboard_handle_enter(void *data, struct wl_keyboard *keyboard,
|
||||||
wl_array_copy(&xwl_seat->keys, keys);
|
wl_array_copy(&xwl_seat->keys, keys);
|
||||||
wl_array_for_each(k, &xwl_seat->keys)
|
wl_array_for_each(k, &xwl_seat->keys)
|
||||||
QueueKeyboardEvents(xwl_seat->keyboard, EnterNotify, *k + 8);
|
QueueKeyboardEvents(xwl_seat->keyboard, EnterNotify, *k + 8);
|
||||||
|
|
||||||
|
maybe_fake_grab_devices(xwl_seat);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1024,6 +1113,8 @@ keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
|
||||||
QueueKeyboardEvents(xwl_seat->keyboard, LeaveNotify, *k + 8);
|
QueueKeyboardEvents(xwl_seat->keyboard, LeaveNotify, *k + 8);
|
||||||
|
|
||||||
xwl_seat->keyboard_focus = NULL;
|
xwl_seat->keyboard_focus = NULL;
|
||||||
|
|
||||||
|
maybe_fake_ungrab_devices(xwl_seat);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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.
|
/* 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
|
relative_pointer_manager or pointer_gesture interfaces. This would result in
|
||||||
devices being created in capabilities handler, but listeners not, because
|
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);
|
init_tablet_manager(xwl_screen, id, version);
|
||||||
} else if (strcmp(interface, "zwp_xwayland_keyboard_grab_manager_v1") == 0) {
|
} else if (strcmp(interface, "zwp_xwayland_keyboard_grab_manager_v1") == 0) {
|
||||||
init_keyboard_grab(xwl_screen, id, version);
|
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_seat *xwl_seat = device->public.devicePrivate;
|
||||||
struct xwl_window *xwl_window;
|
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)
|
if (!xwl_seat)
|
||||||
xwl_seat = xwl_screen_get_default_seat(xwl_screen);
|
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) {
|
else if (strcmp(argv[i], "-fullscreen") == 0) {
|
||||||
xwl_screen->fullscreen = 1;
|
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) {
|
if (use_fixed_size) {
|
||||||
|
@ -745,6 +755,11 @@ xwl_screen_init(ScreenPtr pScreen, int argc, char **argv)
|
||||||
xwl_screen->fullscreen = FALSE;
|
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) {
|
if (!xwl_screen->rootless && !xwl_screen->xdg_wm_base) {
|
||||||
ErrorF("missing XDG-WM-Base protocol\n");
|
ErrorF("missing XDG-WM-Base protocol\n");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
|
@ -59,6 +59,8 @@ struct xwl_screen {
|
||||||
int present;
|
int present;
|
||||||
int force_xrandr_emulation;
|
int force_xrandr_emulation;
|
||||||
int fullscreen;
|
int fullscreen;
|
||||||
|
int host_grab;
|
||||||
|
int has_grab;
|
||||||
|
|
||||||
CreateScreenResourcesProcPtr CreateScreenResources;
|
CreateScreenResourcesProcPtr CreateScreenResources;
|
||||||
CloseScreenProcPtr CloseScreen;
|
CloseScreenProcPtr CloseScreen;
|
||||||
|
@ -88,6 +90,8 @@ struct xwl_screen {
|
||||||
struct zwp_pointer_constraints_v1 *pointer_constraints;
|
struct zwp_pointer_constraints_v1 *pointer_constraints;
|
||||||
struct zwp_pointer_gestures_v1 *pointer_gestures;
|
struct zwp_pointer_gestures_v1 *pointer_gestures;
|
||||||
struct zwp_xwayland_keyboard_grab_manager_v1 *wp_grab;
|
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 zwp_linux_dmabuf_v1 *dmabuf;
|
||||||
struct zxdg_output_manager_v1 *xdg_output_manager;
|
struct zxdg_output_manager_v1 *xdg_output_manager;
|
||||||
struct wp_viewporter *viewporter;
|
struct wp_viewporter *viewporter;
|
||||||
|
|
|
@ -93,6 +93,7 @@ ddxUseMsg(void)
|
||||||
ErrorF("-rootless run rootless, requires wm support\n");
|
ErrorF("-rootless run rootless, requires wm support\n");
|
||||||
ErrorF("-fullscreen run fullscreen when rootful\n");
|
ErrorF("-fullscreen run fullscreen when rootful\n");
|
||||||
ErrorF("-geometry WxH set Xwayland window size 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("-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("-initfd fd add given fd as a listen socket for initialization clients\n");
|
||||||
ErrorF("-listenfd fd add given fd as a listen socket\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) {
|
else if (strcmp(argv[i], "-fullscreen") == 0) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
else if (strcmp(argv[i], "-host-grab") == 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,3 +15,4 @@ have_no_touch_pointer_emulation=true
|
||||||
have_force_xrandr_emulation=true
|
have_force_xrandr_emulation=true
|
||||||
have_geometry=true
|
have_geometry=true
|
||||||
have_fullscreen=true
|
have_fullscreen=true
|
||||||
|
have_host_grab=true
|
||||||
|
|
Loading…
Reference in New Issue