[mutter/wip/carlosg/xdg-activation: 3/3] wayland: Implement the xdg-activation protocol




commit 6cf7a1c1528d5c677dcfb4cf63df44a0d493553c
Author: Carlos Garnacho <carlosg gnome org>
Date:   Fri Oct 9 16:23:32 2020 +0200

    wayland: Implement the xdg-activation protocol
    
    This protocol implements the IPC necessary to focus application
    windows across launcher/launchee. Add support for it.

 src/meson.build                       |   2 +
 src/wayland/meta-wayland-activation.c | 333 ++++++++++++++++++++++++++++++++++
 src/wayland/meta-wayland-activation.h |  32 ++++
 src/wayland/meta-wayland-private.h    |   1 +
 src/wayland/meta-wayland-types.h      |   2 +
 src/wayland/meta-wayland-versions.h   |   1 +
 src/wayland/meta-wayland.c            |   2 +
 7 files changed, 373 insertions(+)
---
diff --git a/src/meson.build b/src/meson.build
index 7fc0269b0f..74c2ebf349 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -514,6 +514,8 @@ if have_wayland
     'wayland/meta-pointer-lock-wayland.h',
     'wayland/meta-selection-source-wayland.c',
     'wayland/meta-selection-source-wayland-private.h',
+    'wayland/meta-wayland-activation.c',
+    'wayland/meta-wayland-activation.h',
     'wayland/meta-wayland-actor-surface.c',
     'wayland/meta-wayland-actor-surface.h',
     'wayland/meta-wayland-buffer.c',
diff --git a/src/wayland/meta-wayland-activation.c b/src/wayland/meta-wayland-activation.c
new file mode 100644
index 0000000000..07bc1adaad
--- /dev/null
+++ b/src/wayland/meta-wayland-activation.c
@@ -0,0 +1,333 @@
+/*
+ * Copyright (C) 2020 Red Hat
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Author: Carlos Garnacho <carlosg gnome org>
+ */
+
+#include "config.h"
+
+#include "wayland/meta-wayland-activation.h"
+
+#include <glib.h>
+#include <wayland-server.h>
+
+#include "wayland/meta-wayland-private.h"
+#include "wayland/meta-wayland-versions.h"
+
+#include "xdg-activation-v1-server-protocol.h"
+
+typedef struct _MetaXdgActivationToken MetaXdgActivationToken;
+
+struct _MetaWaylandActivation
+{
+  MetaWaylandCompositor *compositor;
+  struct wl_list resource_list;
+  struct wl_list token_list;
+  GHashTable *tokens;
+};
+
+struct _MetaXdgActivationToken
+{
+  MetaWaylandSurface *surface;
+  MetaWaylandSeat *seat;
+  MetaWaylandActivation *activation;
+  MetaStartupSequence *sequence;
+  char *app_id;
+  char *token;
+  uint32_t serial;
+  gulong sequence_complete_id;
+  gboolean committed;
+};
+
+static void
+unbind_resource (struct wl_resource *resource)
+{
+  wl_list_remove (wl_resource_get_link (resource));
+}
+
+static void
+token_set_serial (struct wl_client   *client,
+                  struct wl_resource *resource,
+                  uint32_t            serial,
+                  struct wl_resource *seat_resource)
+{
+  MetaXdgActivationToken *token = wl_resource_get_user_data (resource);
+  MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource);
+
+  token->serial = serial;
+  token->seat = seat;
+}
+
+static void
+token_set_app_id (struct wl_client   *client,
+                  struct wl_resource *resource,
+                  const char         *app_id)
+{
+  MetaXdgActivationToken *token = wl_resource_get_user_data (resource);
+
+  g_clear_pointer (&token->app_id, g_free);
+  token->app_id = g_strdup (app_id);
+}
+
+static void
+token_set_surface (struct wl_client   *client,
+                   struct wl_resource *resource,
+                   struct wl_resource *surface_resource)
+{
+  MetaXdgActivationToken *token = wl_resource_get_user_data (resource);
+  MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
+
+  token->surface = surface;
+}
+
+static void
+sequence_complete_cb (MetaStartupSequence    *sequence,
+                      MetaXdgActivationToken *token)
+{
+  MetaWaylandActivation *activation = token->activation;
+  MetaDisplay *display = meta_get_display ();
+
+  meta_startup_notification_remove_sequence (display->startup_notification,
+                                             sequence);
+  g_hash_table_remove (activation->tokens, token->token);
+}
+
+static char *
+create_startup_token (MetaWaylandActivation *activation,
+                      MetaDisplay           *display)
+{
+  g_autofree char *uuid = NULL, *token = NULL;
+
+  do
+    {
+      g_clear_pointer (&uuid, g_free);
+      g_clear_pointer (&token, g_free);
+      uuid = g_uuid_string_random ();
+      token = g_strdup_printf ("%s_TIME%d", uuid,
+                               meta_display_get_current_time (display));
+    }
+  while (g_hash_table_contains (activation->tokens, token));
+
+  return g_steal_pointer (&token);
+}
+
+static void
+token_commit (struct wl_client   *client,
+              struct wl_resource *resource)
+{
+  MetaXdgActivationToken *token = wl_resource_get_user_data (resource);
+  MetaWaylandActivation *activation = token->activation;
+  MetaDisplay *display = meta_get_display ();
+  uint32_t timestamp;
+
+  if (token->committed)
+    {
+      wl_resource_post_error (resource,
+                              XDG_ACTIVATION_TOKEN_V1_ERROR_ALREADY_USED,
+                              "Activation token was already used");
+      return;
+    }
+
+  timestamp = meta_display_get_current_time_roundtrip (display);
+
+  token->committed = TRUE;
+  token->token = create_startup_token (activation, display);
+  token->sequence = g_object_new (META_TYPE_STARTUP_SEQUENCE,
+                                  "id", token->token,
+                                  "application-id", token->app_id,
+                                  "timestamp", timestamp,
+                                  NULL);
+
+  token->sequence_complete_id =
+    g_signal_connect (token->sequence,
+                      "complete",
+                      G_CALLBACK (sequence_complete_cb),
+                      token);
+
+  meta_startup_notification_add_sequence (display->startup_notification,
+                                          token->sequence);
+
+  xdg_activation_token_v1_send_done (resource, token->token);
+  g_hash_table_insert (activation->tokens, token->token, token);
+}
+
+static void
+token_destroy (struct wl_client   *client,
+               struct wl_resource *resource)
+{
+  wl_resource_destroy (resource);
+}
+
+static const struct xdg_activation_token_v1_interface token_interface = {
+  token_set_serial,
+  token_set_app_id,
+  token_set_surface,
+  token_commit,
+  token_destroy,
+};
+
+static void
+meta_xdg_activation_token_free (MetaXdgActivationToken *token)
+{
+  if (token->sequence)
+    {
+      g_clear_signal_handler (&token->sequence_complete_id,
+                              token->sequence);
+      g_clear_object (&token->sequence);
+    }
+
+  g_free (token->app_id);
+  g_free (token->token);
+  g_free (token);
+}
+
+static void
+meta_wayland_activation_token_create_new_resource (MetaWaylandActivation *activation,
+                                                   struct wl_client      *client,
+                                                   struct wl_resource    *activation_resource,
+                                                   uint32_t               id)
+{
+  MetaXdgActivationToken *token;
+  struct wl_resource *token_resource;
+
+  token = g_new0 (MetaXdgActivationToken, 1);
+  token->activation = activation;
+
+  token_resource =
+    wl_resource_create (client, &xdg_activation_token_v1_interface,
+                        wl_resource_get_version (activation_resource),
+                        id);
+  wl_resource_set_implementation (token_resource, &token_interface,
+                                  token, unbind_resource);
+  wl_resource_set_user_data (token_resource, token);
+  wl_list_insert (&activation->token_list,
+                  wl_resource_get_link (token_resource));
+}
+
+static void
+activation_destroy (struct wl_client   *client,
+                    struct wl_resource *resource)
+{
+  wl_resource_destroy (resource);
+}
+
+static void
+activation_get_activation_token (struct wl_client   *client,
+                                 struct wl_resource *resource,
+                                 uint32_t            id)
+{
+  MetaWaylandActivation *activation = wl_resource_get_user_data (resource);
+
+  meta_wayland_activation_token_create_new_resource (activation,
+                                                     client,
+                                                     resource,
+                                                     id);
+}
+
+static void
+activation_activate (struct wl_client   *client,
+                     struct wl_resource *resource,
+                     const char         *token_str,
+                     struct wl_resource *surface_resource)
+{
+  MetaWaylandActivation *activation = wl_resource_get_user_data (resource);
+  MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
+  MetaXdgActivationToken *token;
+  MetaWindow *window;
+
+  window = meta_wayland_surface_get_window (surface);
+  if (!window)
+    return;
+
+  token = g_hash_table_lookup (activation->tokens, token_str);
+  if (!token)
+    return;
+
+  if (meta_wayland_seat_get_grab_info (token->seat,
+                                       token->surface,
+                                       token->serial,
+                                       FALSE, NULL, NULL))
+    {
+      uint32_t timestamp;
+      int32_t workspace_idx;
+
+      workspace_idx = meta_startup_sequence_get_workspace (token->sequence);
+      timestamp = meta_startup_sequence_get_timestamp (token->sequence);
+
+      if (workspace_idx >= 0)
+        meta_window_change_workspace_by_index (window, workspace_idx, TRUE);
+
+      meta_window_activate_full (window, timestamp,
+                                 META_CLIENT_TYPE_APPLICATION, NULL);
+    }
+  else
+    {
+      meta_window_set_demands_attention (window);
+    }
+
+  meta_startup_sequence_complete (token->sequence);
+}
+
+static const struct xdg_activation_v1_interface activation_interface = {
+  activation_destroy,
+  activation_get_activation_token,
+  activation_activate,
+};
+
+static void
+bind_activation (struct wl_client *client,
+                 void             *data,
+                 uint32_t          version,
+                 uint32_t          id)
+{
+  MetaWaylandCompositor *compositor = data;
+  MetaWaylandActivation *activation = compositor->activation;
+  struct wl_resource *resource;
+
+  resource = wl_resource_create (client, &xdg_activation_v1_interface,
+                                 MIN (version, META_XDG_ACTIVATION_V1_VERSION),
+                                 id);
+  wl_resource_set_implementation (resource, &activation_interface,
+                                  activation, unbind_resource);
+  wl_resource_set_user_data (resource, activation);
+  wl_list_insert (&activation->resource_list,
+                  wl_resource_get_link (resource));
+}
+
+void
+meta_wayland_activation_init (MetaWaylandCompositor *compositor)
+{
+  MetaWaylandActivation *activation;
+
+  activation = g_new0 (MetaWaylandActivation, 1);
+  activation->compositor = compositor;
+  wl_list_init (&activation->resource_list);
+  wl_list_init (&activation->token_list);
+
+  activation->tokens =
+    g_hash_table_new_full (g_str_hash, g_str_equal,
+                           NULL,
+                           (GDestroyNotify) meta_xdg_activation_token_free);
+
+  wl_global_create (compositor->wayland_display,
+                    &xdg_activation_v1_interface,
+                    META_XDG_ACTIVATION_V1_VERSION,
+                    compositor, bind_activation);
+
+  compositor->activation = activation;
+}
diff --git a/src/wayland/meta-wayland-activation.h b/src/wayland/meta-wayland-activation.h
new file mode 100644
index 0000000000..8fcc0fa42e
--- /dev/null
+++ b/src/wayland/meta-wayland-activation.h
@@ -0,0 +1,32 @@
+/*
+ * Wayland Support
+ *
+ * Copyright (C) 2020 Red Hat
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Carlos Garnacho <carlosg gnome org>
+ */
+
+#ifndef META_WAYLAND_ACTIVATION_H
+#define META_WAYLAND_ACTIVATION_H
+
+#include <glib.h>
+#include <wayland-server.h>
+
+#include "wayland/meta-wayland-types.h"
+
+void meta_wayland_activation_init (MetaWaylandCompositor *compositor);
+
+#endif /* META_WAYLAND_ACTIVATION_H */
diff --git a/src/wayland/meta-wayland-private.h b/src/wayland/meta-wayland-private.h
index 3306c192c9..2782789206 100644
--- a/src/wayland/meta-wayland-private.h
+++ b/src/wayland/meta-wayland-private.h
@@ -93,6 +93,7 @@ struct _MetaWaylandCompositor
 
   MetaWaylandSeat *seat;
   MetaWaylandTabletManager *tablet_manager;
+  MetaWaylandActivation *activation;
 
   GHashTable *scheduled_surface_associations;
 
diff --git a/src/wayland/meta-wayland-types.h b/src/wayland/meta-wayland-types.h
index 00712ad1f1..aeb6f61786 100644
--- a/src/wayland/meta-wayland-types.h
+++ b/src/wayland/meta-wayland-types.h
@@ -61,4 +61,6 @@ typedef struct _MetaWaylandWindowConfiguration MetaWaylandWindowConfiguration;
 
 typedef struct _MetaWaylandPointerClient MetaWaylandPointerClient;
 
+typedef struct _MetaWaylandActivation MetaWaylandActivation;
+
 #endif
diff --git a/src/wayland/meta-wayland-versions.h b/src/wayland/meta-wayland-versions.h
index 8f71c19dce..05dd937b29 100644
--- a/src/wayland/meta-wayland-versions.h
+++ b/src/wayland/meta-wayland-versions.h
@@ -58,5 +58,6 @@
 #define META_GTK_PRIMARY_SELECTION_VERSION  1
 #define META_ZWP_PRIMARY_SELECTION_V1_VERSION 1
 #define META_WP_PRESENTATION_VERSION        1
+#define META_XDG_ACTIVATION_V1_VERSION 1
 
 #endif
diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c
index 4febb7d061..d96b60fe29 100644
--- a/src/wayland/meta-wayland.c
+++ b/src/wayland/meta-wayland.c
@@ -32,6 +32,7 @@
 #include "cogl/cogl-egl.h"
 #include "compositor/meta-surface-actor-wayland.h"
 #include "core/main-private.h"
+#include "wayland/meta-wayland-activation.h"
 #include "wayland/meta-wayland-buffer.h"
 #include "wayland/meta-wayland-data-device.h"
 #include "wayland/meta-wayland-dma-buf.h"
@@ -542,6 +543,7 @@ meta_wayland_compositor_setup (MetaWaylandCompositor *compositor)
   meta_wayland_text_input_init (compositor);
   meta_wayland_gtk_text_input_init (compositor);
   meta_wayland_init_presentation_time (compositor);
+  meta_wayland_activation_init (compositor);
 
   /* Xwayland specific protocol, needs to be filtered out for all other clients */
   if (meta_xwayland_grab_keyboard_init (compositor))


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