[gtk/wip/carlosg/focus-request-over-xdg-activation] wayland: Use xdg-activation for non-startup initiated focus requests




commit a071d9f5466f3e32b806e8ec7360c25bd0d27865
Author: Carlos Garnacho <carlosg gnome org>
Date:   Mon Feb 28 18:31:40 2022 +0100

    wayland: Use xdg-activation for non-startup initiated focus requests
    
    Currently, we have all the plumbing in place so that GTK consumes the
    startup notification ID when focusing a window through the xdg-activation
    protocol.
    
    This however misses the case that a window might be requested to be
    focused with no startup ID (i.e. via interaction with the application,
    not through GApplication or other application launching logic).
    
    In this case, we let the application create a token that will be
    consumed by itself. The serial used is that from the last
    interaction, so the compositor will still be able to do focus prevention
    logic if it applies.
    
    Since we already do have a last serial at hand, prefer xdg-activation
    all the way over the now stale gtk-shell focusing support. The timestamp
    argument becomes unused, but that is a weak argument to prefer the
    private protocol over the standard one. The gtk-shell protocol support
    is so far left for interaction with older Mutter.

 gdk/wayland/gdksurface-wayland.c | 78 +++++++++++++++++++++++++++++-----------
 1 file changed, 57 insertions(+), 21 deletions(-)
---
diff --git a/gdk/wayland/gdksurface-wayland.c b/gdk/wayland/gdksurface-wayland.c
index 25be2f0b7c..4538c01ce2 100644
--- a/gdk/wayland/gdksurface-wayland.c
+++ b/gdk/wayland/gdksurface-wayland.c
@@ -3453,40 +3453,76 @@ gdk_wayland_surface_destroy (GdkSurface *surface,
   display->toplevels = g_list_remove (display->toplevels, surface);
 }
 
+static void
+token_done (gpointer                        data,
+            struct xdg_activation_token_v1 *provider,
+            const char                     *token)
+{
+  char **token_out = data;
+
+  *token_out = g_strdup (token);
+}
+
+static const struct xdg_activation_token_v1_listener token_listener = {
+  token_done,
+};
+
 static void
 gdk_wayland_surface_focus (GdkSurface *surface,
                            guint32     timestamp)
 {
   GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
+  GdkDisplay *display = gdk_surface_get_display (surface);
+  GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
+  gchar *startup_id = NULL;
 
-  if (!impl->display_server.gtk_surface)
-    return;
+  if (display_wayland->startup_notification_id)
+    startup_id = g_steal_pointer (&display_wayland->startup_notification_id);
 
-  if (timestamp == GDK_CURRENT_TIME)
+  if (display_wayland->xdg_activation)
     {
-      GdkWaylandDisplay *display_wayland =
-        GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
+      GdkWaylandSeat *seat =
+        GDK_WAYLAND_SEAT (gdk_display_get_default_seat (display));
 
-      if (display_wayland->startup_notification_id)
+      /* If the focus request does not have a startup ID associated, get a
+       * new token to activate the window.
+       */
+      if (!startup_id)
         {
-          if (display_wayland->xdg_activation)
-            {
-              xdg_activation_v1_activate (display_wayland->xdg_activation,
-                                          display_wayland->startup_notification_id,
-                                          impl->display_server.wl_surface);
-              gdk_wayland_display_set_startup_notification_id (GDK_DISPLAY (display_wayland), NULL);
-            }
-          else if (display_wayland->gtk_shell_version >= 3)
-            {
-              gtk_surface1_request_focus (impl->display_server.gtk_surface,
-                                          display_wayland->startup_notification_id);
-            }
+          struct xdg_activation_token_v1 *token;
+
+          token = xdg_activation_v1_get_activation_token (display_wayland->xdg_activation);
+
+          xdg_activation_token_v1_add_listener (token,
+                                                &token_listener,
+                                                &startup_id);
+          xdg_activation_token_v1_set_serial (token,
+                                              _gdk_wayland_seat_get_last_implicit_grab_serial (seat, NULL),
+                                              gdk_wayland_seat_get_wl_seat (GDK_SEAT (seat)));
+          xdg_activation_token_v1_set_surface (token,
+                                               gdk_wayland_surface_get_wl_surface (surface));
+          xdg_activation_token_v1_commit (token);
+
+          while (startup_id == NULL)
+            wl_display_roundtrip (display_wayland->wl_display);
 
-          g_clear_pointer (&display_wayland->startup_notification_id, g_free);
+          xdg_activation_token_v1_destroy (token);
         }
+
+      xdg_activation_v1_activate (display_wayland->xdg_activation,
+                                  startup_id,
+                                  impl->display_server.wl_surface);
     }
-  else
-    gtk_surface1_present (impl->display_server.gtk_surface, timestamp);
+  else if (impl->display_server.gtk_surface)
+    {
+      if (timestamp != GDK_CURRENT_TIME)
+        gtk_surface1_present (impl->display_server.gtk_surface, timestamp);
+      else if (startup_id && display_wayland->gtk_shell_version >= 3)
+        gtk_surface1_request_focus (impl->display_server.gtk_surface,
+                                    startup_id);
+    }
+
+  g_free (startup_id);
 }
 
 static void


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