[gtk: 1/2] wayland: check native surface for crossing events



commit d3885e92a7db130d9686592f58386c9080f6eed9
Author: Olivier Fourdan <ofourdan redhat com>
Date:   Thu Apr 19 14:22:04 2018 +0200

    wayland: check native surface for crossing events
    
    gdk_wayland_*_grab()/ungrab() would emit crossing events which translate
    as focus_in/focus_out events for keyboard.
    
    However, the ungrab() functions compare the native toplevel as this is
    what gets the Wayland pointer enter/leave events with the grab surface,
    so if the grab is issued on a child gdk surface, those won't match and
    we would emit more focus_out events than focus_in.
    
    This means that a widget such as spice-gtk which issues a keyboard grab
    whenever the pointer enters the surface and releases the grab when it
    leaves the surface would get uneven numbers of focus_in/focus_out
    events.
    
    Also, gdk_wayland_seat_ungrab() would not emit crossing events for
    keyboard devices, whereas gdk_wayland_device_ungrab() does, which adds
    even more potential discrepancies between focus_in/focus_out events.
    
    To solve this problem, introduce two new helper functions which check
    the relevant native surfaces to emit crossing events when needed that
    get called evenly from both gdk_wayland_seat_grab()/ungrab() and gdk
    _wayland_device_grab()/ungrab() APIs.
    
    Fixes: https://bugzilla.gnome.org/show_bug.cgi?id=780422
    Closes https://gitlab.gnome.org/GNOME/gtk/issues/792

 gdk/wayland/gdkdevice-wayland.c | 116 +++++++++++++++++++---------------------
 1 file changed, 54 insertions(+), 62 deletions(-)
---
diff --git a/gdk/wayland/gdkdevice-wayland.c b/gdk/wayland/gdkdevice-wayland.c
index edeb32f283..64551c46a3 100644
--- a/gdk/wayland/gdkdevice-wayland.c
+++ b/gdk/wayland/gdkdevice-wayland.c
@@ -712,6 +712,43 @@ gdk_wayland_device_get_focus (GdkDevice *device)
   return NULL;
 }
 
+static void
+device_maybe_emit_grab_crossing (GdkDevice  *device,
+                                 GdkSurface *window,
+                                 guint32     time)
+{
+  GdkSurface *native = gdk_wayland_device_get_focus (device);
+  GdkSurface *focus = gdk_surface_get_toplevel (window);
+
+  if (focus != native)
+    device_emit_grab_crossing (device, focus, window, GDK_CROSSING_GRAB, time);
+}
+
+static GdkSurface*
+device_maybe_emit_ungrab_crossing (GdkDevice      *device,
+                                   guint32         time)
+{
+  GdkDeviceGrabInfo *grab;
+  GdkSurface *focus = NULL;
+  GdkSurface *native = NULL;
+  GdkSurface *prev_focus = NULL;
+
+  focus = gdk_wayland_device_get_focus (device);
+  grab = _gdk_display_get_last_device_grab (gdk_device_get_display (device), device);
+
+  if (grab)
+    {
+      grab->serial_end = grab->serial_start;
+      prev_focus = grab->surface;
+      native = grab->native_surface;
+    }
+
+  if (focus != native)
+    device_emit_grab_crossing (device, prev_focus, focus, GDK_CROSSING_UNGRAB, time);
+
+  return prev_focus;
+}
+
 static GdkGrabStatus
 gdk_wayland_device_grab (GdkDevice    *device,
                          GdkSurface    *surface,
@@ -722,7 +759,6 @@ gdk_wayland_device_grab (GdkDevice    *device,
                          guint32       time_)
 {
   GdkWaylandSeat *wayland_seat = GDK_WAYLAND_SEAT (gdk_device_get_seat (device));
-  GdkSurface *prev_focus = gdk_wayland_device_get_focus (device);
   GdkWaylandPointerData *pointer = GDK_WAYLAND_DEVICE (device)->pointer;
 
   if (gdk_surface_get_surface_type (surface) == GDK_SURFACE_TEMP &&
@@ -734,8 +770,7 @@ gdk_wayland_device_grab (GdkDevice    *device,
                  surface);
     }
 
-  if (prev_focus != surface)
-    device_emit_grab_crossing (device, prev_focus, surface, GDK_CROSSING_GRAB, time_);
+  device_maybe_emit_grab_crossing (device, surface, time_);
 
   if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
     {
@@ -776,24 +811,9 @@ gdk_wayland_device_ungrab (GdkDevice *device,
                            guint32    time_)
 {
   GdkWaylandPointerData *pointer = GDK_WAYLAND_DEVICE (device)->pointer;
-  GdkDisplay *display;
-  GdkDeviceGrabInfo *grab;
-  GdkSurface *focus, *prev_focus = NULL;
-
-  display = gdk_device_get_display (device);
-
-  grab = _gdk_display_get_last_device_grab (display, device);
+  GdkSurface *prev_focus;
 
-  if (grab)
-    {
-      grab->serial_end = grab->serial_start;
-      prev_focus = grab->surface;
-    }
-
-  focus = gdk_wayland_device_get_focus (device);
-
-  if (focus != prev_focus)
-    device_emit_grab_crossing (device, prev_focus, focus, GDK_CROSSING_UNGRAB, time_);
+  prev_focus = device_maybe_emit_ungrab_crossing (device, time_);
 
   if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
     {
@@ -4665,11 +4685,8 @@ gdk_wayland_seat_grab (GdkSeat                *seat,
   if (wayland_seat->master_pointer &&
       capabilities & GDK_SEAT_CAPABILITY_POINTER)
     {
-      GdkSurface *prev_focus = gdk_wayland_device_get_focus (wayland_seat->master_pointer);
-
-      if (prev_focus != native)
-        device_emit_grab_crossing (wayland_seat->master_pointer, prev_focus,
-                                   native, GDK_CROSSING_GRAB, evtime);
+      device_maybe_emit_grab_crossing (wayland_seat->master_pointer,
+                                       native, evtime);
 
       _gdk_display_add_device_grab (display,
                                     wayland_seat->master_pointer,
@@ -4690,11 +4707,8 @@ gdk_wayland_seat_grab (GdkSeat                *seat,
   if (wayland_seat->touch_master &&
       capabilities & GDK_SEAT_CAPABILITY_TOUCH)
     {
-      GdkSurface *prev_focus = gdk_wayland_device_get_focus (wayland_seat->touch_master);
-
-      if (prev_focus != native)
-        device_emit_grab_crossing (wayland_seat->touch_master, prev_focus,
-                                   native, GDK_CROSSING_GRAB, evtime);
+      device_maybe_emit_grab_crossing (wayland_seat->touch_master,
+                                       native, evtime);
 
       _gdk_display_add_device_grab (display,
                                     wayland_seat->touch_master,
@@ -4711,11 +4725,8 @@ gdk_wayland_seat_grab (GdkSeat                *seat,
   if (wayland_seat->master_keyboard &&
       capabilities & GDK_SEAT_CAPABILITY_KEYBOARD)
     {
-      GdkSurface *prev_focus = gdk_wayland_device_get_focus (wayland_seat->master_keyboard);
-
-      if (prev_focus != native)
-        device_emit_grab_crossing (wayland_seat->master_keyboard, prev_focus,
-                                   native, GDK_CROSSING_GRAB, evtime);
+      device_maybe_emit_grab_crossing (wayland_seat->master_keyboard,
+                                       native, evtime);
 
       _gdk_display_add_device_grab (display,
                                     wayland_seat->master_keyboard,
@@ -4739,11 +4750,8 @@ gdk_wayland_seat_grab (GdkSeat                *seat,
       for (l = wayland_seat->tablets; l; l = l->next)
         {
           GdkWaylandTabletData *tablet = l->data;
-          GdkSurface *prev_focus = gdk_wayland_device_get_focus (tablet->master);
 
-          if (prev_focus != native)
-            device_emit_grab_crossing (tablet->master, prev_focus,
-                                       native, GDK_CROSSING_GRAB, evtime);
+          device_maybe_emit_grab_crossing (tablet->master, native, evtime);
 
           _gdk_display_add_device_grab (display,
                                         tablet->master,
@@ -4777,36 +4785,20 @@ gdk_wayland_seat_ungrab (GdkSeat *seat)
 
   if (wayland_seat->master_pointer)
     {
-      GdkSurface *focus, *prev_focus = NULL;
-
-      grab = _gdk_display_get_last_device_grab (display, wayland_seat->master_pointer);
-
-      if (grab)
-        {
-          grab->serial_end = grab->serial_start;
-          prev_focus = grab->surface;
-        }
-
-      focus = gdk_wayland_device_get_focus (wayland_seat->master_pointer);
-
-      if (focus != prev_focus)
-        device_emit_grab_crossing (wayland_seat->master_pointer, prev_focus,
-                                   focus, GDK_CROSSING_UNGRAB,
-                                   GDK_CURRENT_TIME);
+      device_maybe_emit_ungrab_crossing (wayland_seat->master_pointer,
+                                         GDK_CURRENT_TIME);
 
       gdk_wayland_device_update_surface_cursor (wayland_seat->master_pointer);
     }
 
   if (wayland_seat->master_keyboard)
     {
-      grab = _gdk_display_get_last_device_grab (display, wayland_seat->master_keyboard);
+      GdkSurface *prev_focus;
 
-      if (grab)
-        {
-          grab->serial_end = grab->serial_start;
-          if (grab->surface)
-            gdk_wayland_surface_restore_shortcuts (grab->surface, seat);
-        }
+      prev_focus = device_maybe_emit_ungrab_crossing (wayland_seat->master_keyboard,
+                                                      GDK_CURRENT_TIME);
+      if (prev_focus)
+        gdk_wayland_surface_restore_shortcuts (prev_focus, seat);
     }
 
   if (wayland_seat->touch_master)


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]