diff --git a/src/wayland/meta-wayland-pointer.c b/src/wayland/meta-wayland-pointer.c index e513ee258..d01919f57 100644 --- a/src/wayland/meta-wayland-pointer.c +++ b/src/wayland/meta-wayland-pointer.c @@ -248,6 +248,18 @@ meta_wayland_pointer_unbind_pointer_client_resource (struct wl_resource *resourc client); } +static MetaWindow * +surface_get_effective_window (MetaWaylandSurface *surface) +{ + MetaWaylandSurface *toplevel; + + toplevel = meta_wayland_surface_get_toplevel (surface); + if (!toplevel) + return NULL; + + return meta_wayland_surface_get_window (toplevel); +} + static void sync_focus_surface (MetaWaylandPointer *pointer) { @@ -453,6 +465,17 @@ default_grab_focus (MetaWaylandPointerGrab *grab, break; } + if (surface) + { + MetaWindow *window = NULL; + + window = surface_get_effective_window (surface); + + /* Avoid focusing a non-alive surface */ + if (!window || !meta_window_get_alive (window)) + surface = NULL; + } + meta_wayland_pointer_set_focus (pointer, surface); } @@ -901,6 +924,16 @@ focus_surface_destroyed (MetaWaylandSurface *surface, meta_wayland_pointer_set_focus (pointer, NULL); } +static void +focus_surface_alive_notify (MetaWindow *window, + GParamSpec *pspec, + MetaWaylandPointer *pointer) +{ + if (!meta_window_get_alive (window)) + meta_wayland_pointer_set_focus (pointer, NULL); + sync_focus_surface (pointer); +} + void meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer, MetaWaylandSurface *surface) @@ -910,6 +943,7 @@ meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer, MetaCursorTracker *cursor_tracker = meta_backend_get_cursor_tracker (backend); ClutterBackend *clutter_backend = clutter_get_default_backend (); ClutterSeat *clutter_seat = clutter_backend_get_default_seat (clutter_backend); + MetaWindow *toplevel_window; g_return_if_fail (meta_cursor_tracker_get_pointer_visible (cursor_tracker) || clutter_seat_is_unfocus_inhibited (clutter_seat) || @@ -932,6 +966,13 @@ meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer, pointer->focus_client = NULL; } + toplevel_window = surface_get_effective_window (pointer->focus_surface); + if (toplevel_window) + { + g_clear_signal_handler (&pointer->focus_surface_alive_notify_id, + toplevel_window); + } + g_clear_signal_handler (&pointer->focus_surface_destroyed_handler_id, pointer->focus_surface); pointer->focus_surface = NULL; @@ -960,6 +1001,15 @@ meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer, clutter_get_current_event_time (), pos.x, pos.y); + toplevel_window = surface_get_effective_window (pointer->focus_surface); + if (toplevel_window) + { + pointer->focus_surface_alive_notify_id = + g_signal_connect (toplevel_window, "notify::is-alive", + G_CALLBACK (focus_surface_alive_notify), + pointer); + } + pointer->focus_client = meta_wayland_pointer_get_pointer_client (pointer, client); if (pointer->focus_client) diff --git a/src/wayland/meta-wayland-pointer.h b/src/wayland/meta-wayland-pointer.h index 86810ebac..088312f2f 100644 --- a/src/wayland/meta-wayland-pointer.h +++ b/src/wayland/meta-wayland-pointer.h @@ -72,6 +72,7 @@ struct _MetaWaylandPointer MetaWaylandSurface *focus_surface; gulong focus_surface_destroyed_handler_id; + gulong focus_surface_alive_notify_id; guint32 focus_serial; guint32 click_serial;