diff --git a/include/sway/desktop/launcher.h b/include/sway/desktop/launcher.h index 91915604..3b577f74 100644 --- a/include/sway/desktop/launcher.h +++ b/include/sway/desktop/launcher.h @@ -9,6 +9,8 @@ struct launcher_ctx { struct wlr_xdg_activation_token_v1 *token; struct wl_listener token_destroy; + bool activated; + struct sway_node *node; struct wl_listener node_destroy; @@ -25,4 +27,6 @@ void launcher_ctx_destroy(struct launcher_ctx *ctx); struct launcher_ctx *launcher_ctx_create(void); +const char *launcher_ctx_get_token_name(struct launcher_ctx *ctx); + #endif diff --git a/sway/commands/exec_always.c b/sway/commands/exec_always.c index 13deb9e3..2dfba7ff 100644 --- a/sway/commands/exec_always.c +++ b/sway/commands/exec_always.c @@ -27,6 +27,11 @@ struct cmd_results *cmd_exec_validate(int argc, char **argv) { return error; } +static void export_xdga_token(struct launcher_ctx *ctx) { + const char *token = launcher_ctx_get_token_name(ctx); + setenv("XDG_ACTIVATION_TOKEN", token, 1); +} + struct cmd_results *cmd_exec_process(int argc, char **argv) { struct cmd_results *error = NULL; char *cmd = NULL; @@ -66,6 +71,9 @@ struct cmd_results *cmd_exec_process(int argc, char **argv) { close(fd[0]); if ((child = fork()) == 0) { close(fd[1]); + if (ctx) { + export_xdga_token(ctx); + } execlp("sh", "sh", "-c", cmd, (void *)NULL); sway_log_errno(SWAY_ERROR, "execlp failed"); _exit(1); diff --git a/sway/desktop/launcher.c b/sway/desktop/launcher.c index b983dcb0..48e5d24c 100644 --- a/sway/desktop/launcher.c +++ b/sway/desktop/launcher.c @@ -50,7 +50,10 @@ void launcher_ctx_consume(struct launcher_ctx *ctx) { wl_list_remove(&ctx->token_destroy.link); wl_list_init(&ctx->token_destroy.link); - wlr_xdg_activation_token_v1_destroy(ctx->token); + if (!ctx->activated) { + // An unactivated token hasn't been destroyed yet + wlr_xdg_activation_token_v1_destroy(ctx->token); + } ctx->token = NULL; // Prevent additional matches @@ -201,3 +204,8 @@ struct launcher_ctx *launcher_ctx_create() { wl_list_insert(&server.pending_launcher_ctxs, &ctx->link); return ctx; } + +const char *launcher_ctx_get_token_name(struct launcher_ctx *ctx) { + const char *token = wlr_xdg_activation_token_v1_get_name(ctx->token); + return token; +} diff --git a/sway/xdg_activation_v1.c b/sway/xdg_activation_v1.c index 99e7f9b5..2b94136c 100644 --- a/sway/xdg_activation_v1.c +++ b/sway/xdg_activation_v1.c @@ -1,4 +1,5 @@ #include +#include "sway/desktop/launcher.h" #include "sway/tree/view.h" void xdg_activation_v1_handle_request_activate(struct wl_listener *listener, @@ -15,7 +16,22 @@ void xdg_activation_v1_handle_request_activate(struct wl_listener *listener, return; } struct sway_view *view = xdg_surface->data; - if (!xdg_surface->mapped || view == NULL) { + if (view == NULL) { + return; + } + + if (!xdg_surface->mapped) { + // This is a startup notification. If we are tracking it, the data + // field is a launcher_ctx. + struct launcher_ctx *ctx = event->token->data; + if (!ctx || ctx->activated) { + // This ctx has already been activated and cannot be used again + // for a startup notification. It will be destroyed + return; + } else { + ctx->activated = true; + view_assign_ctx(view, ctx); + } return; }