[Spice-commits] 2 commits - src/spice-widget.c

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Fri Feb 22 11:03:35 UTC 2019


 src/spice-widget.c |   97 ++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 92 insertions(+), 5 deletions(-)

New commits:
commit e1bf254f60d78d6a4e7b0664d344b6bfcb70f2ae
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Fri Feb 1 14:35:39 2019 +0100

    spice-widget: Ungrab mouse on leave event on Wayland
    
    The Spice Gtk widget relies on pointer grabs to receive all pointer
    events even after the pointer has left the window.
    
    While that works on X11, on Wayland there is no active pointer grab,
    so once the pointer has left the SPICE widget on Wayland, the events
    are routed to the window with the pointer focus instead of ours.
    
    To avoid the problem, on Wayland, we simply ungrab the pointer once it
    leaves the window.
    
    Thanks-to: Peter Hutterer <peter.hutterer at who-t.net>
    Signed-off-by: Olivier Fourdan <ofourdan at redhat.com>
    https://gitlab.freedesktop.org/spice/spice-gtk/issues/83
    Acked-by: Victor Toso <victortoso at redhat.com>

diff --git a/src/spice-widget.c b/src/spice-widget.c
index fd0c935..d924731 100644
--- a/src/spice-widget.c
+++ b/src/spice-widget.c
@@ -1854,8 +1854,21 @@ static gboolean leave_event(GtkWidget *widget, GdkEventCrossing *crossing G_GNUC
 
     DISPLAY_DEBUG(display, "%s", __FUNCTION__);
 
-    if (d->mouse_grab_active)
+    if (d->mouse_grab_active) {
+#ifdef GDK_WINDOWING_WAYLAND
+        /* On Wayland, there is no active pointer grab, so once the pointer
+         * has left the window, the events are routed to the window with
+         * pointer focus instead of ours, in which case we should just
+         * ungrab to avoid nasty side effects. */
+        if (GDK_IS_WAYLAND_DISPLAY(gdk_display_get_default())) {
+            GdkWindow *window = gtk_widget_get_window(widget);
+
+            if (window == crossing->window)
+                try_mouse_ungrab(display);
+        }
+#endif
         return true;
+    }
 
     d->mouse_have_pointer = false;
     spice_gtk_session_set_mouse_has_pointer(d->gtk_session, false);
commit ae3a8e1b2d952385646046e33f12d8540407f0a5
Author: Olivier Fourdan <ofourdan at redhat.com>
Date:   Wed Feb 6 15:42:53 2019 +0100

    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 <peter.hutterer at who-t.net>
    Signed-off-by: Olivier Fourdan <ofourdan at redhat.com>
    Fixes: https://gitlab.freedesktop.org/spice/spice-gtk/issues/83
    See-also: https://gitlab.gnome.org/GNOME/gtk/issues/787
    Acked-by: Victor Toso <victortoso at redhat.com>

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 <va/va_x11.h>
 #endif
 #endif
+#ifdef GDK_WINDOWING_WAYLAND
+#include <gdk/gdkwayland.h>
+#endif
 #ifdef G_OS_WIN32
 #include <windows.h>
 #include <dinput.h>
@@ -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
 }


More information about the Spice-commits mailing list