[gtk/wip/carlosg/backports-4-6: 6/9] wayland: Use xdg-activation for non-startup initiated focus requests




commit 9822d2b6b2ace41cb4c92e41545ea7dc66fd386c
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 | 82 ++++++++++++++++++++++++++++++----------
 1 file changed, 61 insertions(+), 21 deletions(-)
---
diff --git a/gdk/wayland/gdksurface-wayland.c b/gdk/wayland/gdksurface-wayland.c
index 25be2f0b7c..09328bdb89 100644
--- a/gdk/wayland/gdksurface-wayland.c
+++ b/gdk/wayland/gdksurface-wayland.c
@@ -3453,40 +3453,80 @@ 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;
+  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;
+          struct wl_event_queue *event_queue;
+
+          event_queue = wl_display_create_queue (display_wayland->wl_display);
+
+          token = xdg_activation_v1_get_activation_token (display_wayland->xdg_activation);
+          wl_proxy_set_queue ((struct wl_proxy *) token, event_queue);
+
+          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_dispatch_queue (display_wayland->wl_display, event_queue);
 
-          g_clear_pointer (&display_wayland->startup_notification_id, g_free);
+          xdg_activation_token_v1_destroy (token);
+          wl_event_queue_destroy (event_queue);
         }
+
+      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]