diff options
author | Olivier Fourdan <ofourdan@redhat.com> | 2018-04-19 14:22:04 +0200 |
---|---|---|
committer | Olivier Fourdan <ofourdan@redhat.com> | 2018-05-09 17:30:34 +0200 |
commit | d3885e92a7db130d9686592f58386c9080f6eed9 (patch) | |
tree | 6c37a45c24e4f82c53dff2030dd07a73d08f8026 | |
parent | 47872e517224264a30e4ae33a7f3c103361bb82a (diff) | |
download | gtk+-d3885e92a7db130d9686592f58386c9080f6eed9.tar.gz |
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
-rw-r--r-- | gdk/wayland/gdkdevice-wayland.c | 116 |
1 files 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) |