gdk/wayland: Use toplevel surface for activation
authorCarlos Garnacho <carlosg@gnome.org>
Mon, 18 Sep 2023 20:04:32 +0000 (22:04 +0200)
committerMatthias Clasen <mclasen@redhat.com>
Tue, 19 Sep 2023 20:32:27 +0000 (16:32 -0400)
At the moment of launching/activating an application, the
keyboard focus may be on a transient surface that quickly
disappears after activation. If this happens, and the
compositor handles surface destruction before the activated
application gets to reply, the activation request may be
deemed outdated, and the "demands attention" paths be taken.

Peek the toplevel from the focus surface, as that has larger
guarantees to remain valid for the whole duration of the
operation.

Closes: https://gitlab.gnome.org/GNOME/gtk/-/issues/5820
gdk/wayland/gdkapplaunchcontext-wayland.c

index 75742dd8e5db0a8a7021d91f30afa2f69ee59c05..d6252b3e5a88360b539e3ff30a07d4131e0513d5 100644 (file)
@@ -46,6 +46,21 @@ static const struct xdg_activation_token_v1_listener token_listener = {
   token_done,
 };
 
+static struct wl_surface *
+peek_launcher_toplevel (GdkSeat *seat)
+{
+  struct wl_surface *wl_surface = NULL;
+  GdkSurface *focus_surface;
+
+  focus_surface = gdk_wayland_device_get_focus (gdk_seat_get_keyboard (seat));
+  while (focus_surface && focus_surface->parent)
+    focus_surface = focus_surface->parent;
+  if (focus_surface)
+    wl_surface = gdk_wayland_surface_get_wl_surface (focus_surface);
+
+  return wl_surface;
+}
+
 static char *
 gdk_wayland_app_launch_context_get_startup_notify_id (GAppLaunchContext *context,
                                                       GAppInfo          *info,
@@ -62,7 +77,6 @@ gdk_wayland_app_launch_context_get_startup_notify_id (GAppLaunchContext *context
       struct wl_event_queue *event_queue;
       struct wl_surface *wl_surface = NULL;
       GdkWaylandSeat *seat;
-      GdkSurface *focus_surface;
       AppLaunchData app_launch_data = { 0 };
 
       event_queue = wl_display_create_queue (display->wl_display);
@@ -78,9 +92,7 @@ gdk_wayland_app_launch_context_get_startup_notify_id (GAppLaunchContext *context
                                           _gdk_wayland_seat_get_last_implicit_grab_serial (seat, NULL),
                                           gdk_wayland_seat_get_wl_seat (GDK_SEAT (seat)));
 
-      focus_surface = gdk_wayland_device_get_focus (gdk_seat_get_keyboard (GDK_SEAT (seat)));
-      if (focus_surface)
-        wl_surface = gdk_wayland_surface_get_wl_surface (focus_surface);
+      wl_surface = peek_launcher_toplevel (GDK_SEAT (seat));
       if (wl_surface)
         xdg_activation_token_v1_set_surface (token, wl_surface);