From 375cf4f2007e64c427fb34e244e97f759bc26541 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Fri, 9 Oct 2020 16:23:32 +0200 Subject: 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 | 297 ++++++++++++++++++++++++++++++++++ src/wayland/meta-wayland-activation.h | 41 +++++ 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, 346 insertions(+) create mode 100644 src/wayland/meta-wayland-activation.c create mode 100644 src/wayland/meta-wayland-activation.h diff --git a/src/meson.build b/src/meson.build index 2ac8a696c..a8bd2ef75 100644 --- a/src/meson.build +++ b/src/meson.build @@ -513,6 +513,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 000000000..071ee7e0c --- /dev/null +++ b/src/wayland/meta-wayland-activation.c @@ -0,0 +1,297 @@ +/* + * 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 + */ + +#include "config.h" + +#include "meta-wayland-activation.h" + +#include +#include + +#include "wayland/meta-wayland-private.h" +#include "wayland/meta-wayland-versions.h" +#include "xdg-activation-v1-server-protocol.h" + +typedef struct _MetaXdgActivationToken MetaXdgActivationToken; + +struct _MetaXdgActivationToken +{ + MetaWaylandSurface *surface; + MetaWaylandSeat *seat; + MetaWaylandActivation *activation; + MetaStartupSequence *sequence; + char *app_id; + char *token; + uint32_t serial; + 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; + + g_hash_table_remove (activation->tokens, token->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 = g_uuid_string_random (); + token->sequence = g_object_new (META_TYPE_STARTUP_SEQUENCE, + "id", token->token, + "application-id", token->app_id, + "timestamp", timestamp, + NULL); + + 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 +free_token (struct wl_resource *token_resource) +{ + MetaXdgActivationToken *token = wl_resource_get_user_data (token_resource); + + g_clear_object (&token->sequence); + g_free (token->app_id); + g_free (token->token); + g_free (token); + + wl_list_remove (wl_resource_get_link (token_resource)); +} + +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, free_token); + 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); + MetaDisplay *display = meta_get_display (); + 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 && + 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); + + meta_startup_sequence_complete (token->sequence); + meta_startup_notification_remove_sequence (display->startup_notification, + 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); + } +} + +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; + activation->wl_display = compositor->wayland_display; + wl_list_init (&activation->resource_list); + wl_list_init (&activation->token_list); + + activation->tokens = g_hash_table_new (g_str_hash, g_str_equal); + + wl_global_create (activation->wl_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 000000000..cc0552bac --- /dev/null +++ b/src/wayland/meta-wayland-activation.h @@ -0,0 +1,41 @@ +/* + * 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 . + * + * Author: Carlos Garnacho + */ + +#ifndef META_WAYLAND_ACTIVATION_H +#define META_WAYLAND_ACTIVATION_H + +#include +#include + +#include "wayland/meta-wayland-types.h" + +struct _MetaWaylandActivation +{ + MetaWaylandCompositor *compositor; + struct wl_display *wl_display; + struct wl_list resource_list; + struct wl_list token_list; + GHashTable *tokens; +}; + +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 3306c192c..278278920 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 00712ad1f..aeb6f6178 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 8f71c19dc..05dd937b2 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 b032a8bfc..200ed2b14 100644 --- a/src/wayland/meta-wayland.c +++ b/src/wayland/meta-wayland.c @@ -32,6 +32,7 @@ #include "clutter/wayland/clutter-wayland-compositor.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" @@ -513,6 +514,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)) -- cgit v1.2.1