diff --git a/src/wayland/meta-wayland-activation.c b/src/wayland/meta-wayland-activation.c index b6061c9a5..93846b6d5 100644 --- a/src/wayland/meta-wayland-activation.c +++ b/src/wayland/meta-wayland-activation.c @@ -37,6 +37,7 @@ struct _MetaWaylandActivation struct wl_list resource_list; struct wl_list token_list; GHashTable *tokens; + GHashTable *pending_activations; }; struct _MetaXdgActivationToken @@ -322,22 +323,20 @@ startup_sequence_is_recent (MetaDisplay *display, return seq_timestamp_ms >= last_user_time_ms; } -static void -activation_activate (struct wl_client *client, - struct wl_resource *resource, - const char *token_str, - struct wl_resource *surface_resource) +static gboolean +maybe_activate (MetaWaylandActivation *activation, + MetaWindow *window, + const char *token_str) { - MetaWaylandActivation *activation = wl_resource_get_user_data (resource); - MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource); MetaDisplay *display = display_from_activation (activation); MetaXdgActivationToken *token; MetaStartupSequence *sequence; - MetaWindow *window; - window = meta_wayland_surface_get_window (surface); - if (!window) - return; + if (!window || window->unmanaging) + return TRUE; + + if (!window->mapped) + return FALSE; token = g_hash_table_lookup (activation->tokens, token_str); if (token) @@ -351,7 +350,7 @@ activation_activate (struct wl_client *client, } if (!sequence) - return; + return TRUE; if ((token && token_can_activate (token)) || (!token && startup_sequence_is_recent (display, sequence))) @@ -374,6 +373,50 @@ activation_activate (struct wl_client *client, } meta_startup_sequence_complete (sequence); + + return TRUE; +} + +static void +complete_pending_activate (MetaWaylandActivation *activation, + MetaWindow *window) +{ + g_autofree char *token_str = NULL; + + g_signal_handlers_disconnect_by_func (window, complete_pending_activate, + activation); + g_hash_table_steal_extended (activation->pending_activations, window, + NULL, (gpointer *) &token_str); + + maybe_activate (activation, window, token_str); +} + +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); + MetaWindow *window = meta_wayland_surface_get_window (surface); + + if (maybe_activate (activation, window, token_str)) + return; + + g_assert (window != NULL); + + g_signal_handlers_disconnect_by_func (window, + complete_pending_activate, + activation); + g_signal_connect_swapped (window, "notify::mapped", + G_CALLBACK (complete_pending_activate), + activation); + g_signal_connect_swapped (window, "unmanaged", + G_CALLBACK (complete_pending_activate), + activation); + g_hash_table_insert (activation->pending_activations, + window, g_strdup (token_str)); } static const struct xdg_activation_v1_interface activation_interface = { @@ -406,6 +449,7 @@ void meta_wayland_activation_finalize (MetaWaylandCompositor *compositor) { g_hash_table_destroy (compositor->activation->tokens); + g_hash_table_destroy (compositor->activation->pending_activations); g_clear_pointer (&compositor->activation, g_free); } @@ -424,6 +468,9 @@ meta_wayland_activation_init (MetaWaylandCompositor *compositor) NULL, (GDestroyNotify) meta_xdg_activation_token_free); + activation->pending_activations = + g_hash_table_new_full (NULL, NULL, NULL, g_free); + wl_global_create (compositor->wayland_display, &xdg_activation_v1_interface, META_XDG_ACTIVATION_V1_VERSION,