From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Olivier Fourdan Date: Wed, 6 Feb 2019 15:42:53 +0100 Subject: [PATCH] spice-widget: Use GdkSeat API on Wayland Using different GDK APIs to grab and ungrab devices leads to undetermined behavior and can cause the cursor to remain hidden on ungrab on Wayland because GDK Wayland backend keeps a reference of the GdkSeat cursor. On Wayland, use the GdkSeat API only even for ungrab, by ungrabbing the seat and immediately re-grabbing the remaining keyboard or pointer if the grab is to be retained. Thanks-to: Peter Hutterer Signed-off-by: Olivier Fourdan Fixes: https://gitlab.freedesktop.org/spice/spice-gtk/issues/83 See-also: https://gitlab.gnome.org/GNOME/gtk/issues/787 Acked-by: Victor Toso --- src/spice-widget.c | 82 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 78 insertions(+), 4 deletions(-) diff --git a/src/spice-widget.c b/src/spice-widget.c index 8adcc38..fd0c935 100644 --- a/src/spice-widget.c +++ b/src/spice-widget.c @@ -32,6 +32,9 @@ #include #endif #endif +#ifdef GDK_WINDOWING_WAYLAND +#include +#endif #ifdef G_OS_WIN32 #include #include @@ -887,12 +890,46 @@ static void try_keyboard_grab(SpiceDisplay *display) } } -static void ungrab_keyboard(G_GNUC_UNUSED SpiceDisplay *display) +static void ungrab_keyboard(SpiceDisplay *display) { + GdkSeat *seat = spice_display_get_default_seat(display); + GdkDevice *keyboard = gdk_seat_get_keyboard(seat); + +#ifdef GDK_WINDOWING_WAYLAND + /* On Wayland, use the GdkSeat API alone. + * We simply issue a gdk_seat_ungrab() followed immediately by another + * gdk_seat_grab() on the pointer if the pointer grab is to be kept. + */ + if (GDK_IS_WAYLAND_DISPLAY(gdk_display_get_default())) { + SpiceDisplayPrivate *d = display->priv; + + gdk_seat_ungrab(seat); + + if (d->mouse_grab_active) { + GdkGrabStatus status; + GdkCursor *blank = spice_display_get_blank_cursor(display); + + status = gdk_seat_grab(seat, + gtk_widget_get_window(GTK_WIDGET(display)), + GDK_SEAT_CAPABILITY_ALL_POINTING, + TRUE, + blank, + NULL, + NULL, + NULL); + if (status != GDK_GRAB_SUCCESS) { + g_warning("pointer grab failed %u", status); + d->mouse_grab_active = false; + } + } + + return; + } +#endif + G_GNUC_BEGIN_IGNORE_DEPRECATIONS /* we want to ungrab just the keyboard - it is not possible using gdk_seat_ungrab(). See also https://bugzilla.gnome.org/show_bug.cgi?id=780133 */ - GdkDevice *keyboard = gdk_seat_get_keyboard(spice_display_get_default_seat(display)); gdk_device_ungrab(keyboard, GDK_CURRENT_TIME); G_GNUC_END_IGNORE_DEPRECATIONS } @@ -1148,12 +1185,49 @@ static void mouse_wrap(SpiceDisplay *display, GdkEventMotion *motion) } -static void ungrab_pointer(G_GNUC_UNUSED SpiceDisplay *display) +static void ungrab_pointer(SpiceDisplay *display) { + GdkSeat *seat = spice_display_get_default_seat(display); + GdkDevice *pointer = gdk_seat_get_pointer(seat); + +#ifdef GDK_WINDOWING_WAYLAND + /* On Wayland, mixing the GdkSeat and the GdkDevice APIs leave the + * cursor unchanged because the GDK Wayland backend keeps a reference + * of the cursor set previously using gdk_seat_grab() attached to the + * GdkSeat. + * To avoid that issue, we simply issue a gdk_seat_ungrab() followed + * immediately by another gdk_seat_grab() on the keyboard if the + * keyboard grab is to be kept. + */ + if (GDK_IS_WAYLAND_DISPLAY(gdk_display_get_default())) { + SpiceDisplayPrivate *d = display->priv; + + gdk_seat_ungrab(seat); + + if (d->keyboard_grab_active) { + GdkGrabStatus status; + + status = gdk_seat_grab(seat, + gtk_widget_get_window(GTK_WIDGET(display)), + GDK_SEAT_CAPABILITY_KEYBOARD, + FALSE, + NULL, + NULL, + NULL, + NULL); + if (status != GDK_GRAB_SUCCESS) { + g_warning("keyboard grab failed %u", status); + d->keyboard_grab_active = false; + } + } + + return; + } +#endif + G_GNUC_BEGIN_IGNORE_DEPRECATIONS /* we want to ungrab just the pointer - it is not possible using gdk_seat_ungrab(). See also https://bugzilla.gnome.org/show_bug.cgi?id=780133 */ - GdkDevice *pointer = gdk_seat_get_pointer(spice_display_get_default_seat(display)); gdk_device_ungrab(pointer, GDK_CURRENT_TIME); G_GNUC_END_IGNORE_DEPRECATIONS }