From ad4053ab84eceabdd3584e380c9037e20d8e8636 Mon Sep 17 00:00:00 2001 From: Giovanni Campagna Date: Wed, 28 Aug 2013 16:23:34 +0200 Subject: [PATCH] wayland: fix pointer focus for destroyed surfaces We had an assertion in meta_wayland_surface_free() that after a repick() we would not choose the freed surface, but that didn't consider surfaces destroyed while holding the implicit pointer grab (ie, because the user clicked on the X button). In that case, we need to bypass the grab infrastructure and explicitly unfocus the dead surface. https://bugzilla.gnome.org/show_bug.cgi?id=706982 --- src/wayland/meta-wayland-pointer.c | 18 ++++++++++++++++++ src/wayland/meta-wayland-pointer.h | 4 ++++ src/wayland/meta-wayland.c | 9 +++++++-- 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/wayland/meta-wayland-pointer.c b/src/wayland/meta-wayland-pointer.c index 758d60a85..f6c23d049 100644 --- a/src/wayland/meta-wayland-pointer.c +++ b/src/wayland/meta-wayland-pointer.c @@ -324,3 +324,21 @@ meta_wayland_pointer_end_modal (MetaWaylandPointer *pointer) meta_wayland_pointer_end_grab (pointer); g_slice_free (MetaWaylandPointerGrab, grab); } + +/* Called when the focused resource is destroyed */ +void +meta_wayland_pointer_destroy_focus (MetaWaylandPointer *pointer) +{ + if (pointer->grab == &pointer->default_grab) + { + /* The surface was destroyed, but had the implicit pointer grab. + Bypass the grab interface. */ + g_assert (pointer->button_count > 0); + + /* Note: we focus the NULL interface, not the current one, because + we have button down, and the clients would be confused if the + pointer enters the surface. + */ + meta_wayland_pointer_set_focus (pointer, NULL, 0, 0); + } +} diff --git a/src/wayland/meta-wayland-pointer.h b/src/wayland/meta-wayland-pointer.h index db6d3bf9b..491cdbcc7 100644 --- a/src/wayland/meta-wayland-pointer.h +++ b/src/wayland/meta-wayland-pointer.h @@ -35,6 +35,10 @@ meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer, MetaWaylandSurface *surface, wl_fixed_t sx, wl_fixed_t sy); + +void +meta_wayland_pointer_destroy_focus (MetaWaylandPointer *pointer); + void meta_wayland_pointer_start_grab (MetaWaylandPointer *pointer, MetaWaylandPointerGrab *grab); diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c index ba3726f7c..56ac249ba 100644 --- a/src/wayland/meta-wayland.c +++ b/src/wayland/meta-wayland.c @@ -497,9 +497,14 @@ meta_wayland_surface_free (MetaWaylandSurface *surface) meta_wayland_compositor_repick (compositor); - /* Check that repick didn't pick the freed surface */ - g_assert (surface != compositor->seat->pointer.focus); g_assert (surface != compositor->seat->keyboard.focus); + if (surface == compositor->seat->pointer.focus) + { + meta_wayland_pointer_destroy_focus (&compositor->seat->pointer); + + g_assert (surface != compositor->seat->pointer.focus); + g_assert (surface != compositor->seat->pointer.grab->focus); + } if (compositor->implicit_grab_surface == surface) compositor->implicit_grab_surface = compositor->seat->pointer.current;