diff --git a/.builds/alpine.yml b/.builds/alpine.yml index 04f36a920..34f780e9e 100644 --- a/.builds/alpine.yml +++ b/.builds/alpine.yml @@ -20,7 +20,7 @@ packages: - xcb-util-image-dev - xcb-util-wm-dev - xwayland-dev - - hwdata + - hwdata-dev sources: - https://github.com/swaywm/sway - https://gitlab.freedesktop.org/wlroots/wlroots.git diff --git a/include/sway/desktop/launcher.h b/include/sway/desktop/launcher.h index d5651adfd..b7716e824 100644 --- a/include/sway/desktop/launcher.h +++ b/include/sway/desktop/launcher.h @@ -6,7 +6,7 @@ struct launcher_ctx { pid_t pid; - char *name; + char *fallback_name; struct wlr_xdg_activation_token_v1 *token; struct wl_listener token_destroy; @@ -26,7 +26,10 @@ void launcher_ctx_consume(struct launcher_ctx *ctx); void launcher_ctx_destroy(struct launcher_ctx *ctx); -struct launcher_ctx *launcher_ctx_create(void); +struct launcher_ctx *launcher_ctx_create_internal(void); + +struct launcher_ctx *launcher_ctx_create( + struct wlr_xdg_activation_token_v1 *token, struct sway_node *node); const char *launcher_ctx_get_token_name(struct launcher_ctx *ctx); diff --git a/include/sway/server.h b/include/sway/server.h index 309d9d3e0..a65843ce8 100644 --- a/include/sway/server.h +++ b/include/sway/server.h @@ -114,6 +114,7 @@ struct sway_server { struct wlr_xdg_activation_v1 *xdg_activation_v1; struct wl_listener xdg_activation_v1_request_activate; + struct wl_listener xdg_activation_v1_new_token; struct wl_list pending_launcher_ctxs; // launcher_ctx::link @@ -175,6 +176,8 @@ void handle_xdg_decoration(struct wl_listener *listener, void *data); void handle_pointer_constraint(struct wl_listener *listener, void *data); void xdg_activation_v1_handle_request_activate(struct wl_listener *listener, void *data); +void xdg_activation_v1_handle_new_token(struct wl_listener *listener, + void *data); void set_rr_scheduling(void); diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index 273ff3646..7fc2d95d8 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h @@ -271,7 +271,7 @@ void view_set_activated(struct sway_view *view, bool activated); /** * Called when the view requests to be focused. */ -void view_request_activate(struct sway_view *view); +void view_request_activate(struct sway_view *view, struct sway_seat *seat); /** * If possible, instructs the client to change their decoration mode. diff --git a/sway/commands/exec_always.c b/sway/commands/exec_always.c index bb982621d..8fca19093 100644 --- a/sway/commands/exec_always.c +++ b/sway/commands/exec_always.c @@ -63,7 +63,7 @@ struct cmd_results *cmd_exec_process(int argc, char **argv) { } pid_t pid, child; - struct launcher_ctx *ctx = launcher_ctx_create(); + struct launcher_ctx *ctx = launcher_ctx_create_internal(); // Fork process if ((pid = fork()) == 0) { // Fork child process again diff --git a/sway/desktop/launcher.c b/sway/desktop/launcher.c index 48e5d24c4..b666da1eb 100644 --- a/sway/desktop/launcher.c +++ b/sway/desktop/launcher.c @@ -69,7 +69,7 @@ void launcher_ctx_destroy(struct launcher_ctx *ctx) { wl_list_remove(&ctx->token_destroy.link); wl_list_remove(&ctx->link); wlr_xdg_activation_token_v1_destroy(ctx->token); - free(ctx->name); + free(ctx->fallback_name); free(ctx); } @@ -114,22 +114,22 @@ struct sway_workspace *launcher_ctx_get_workspace( break; case N_OUTPUT: output = ctx->node->sway_output; - ws = workspace_by_name(ctx->name); + ws = workspace_by_name(ctx->fallback_name); if (!ws) { sway_log(SWAY_DEBUG, "Creating workspace %s for pid %d because it disappeared", - ctx->name, ctx->pid); + ctx->fallback_name, ctx->pid); if (!output->enabled) { sway_log(SWAY_DEBUG, "Workspace output %s is disabled, trying another one", output->wlr_output->name); output = NULL; } - ws = workspace_create(output, ctx->name); + ws = workspace_create(output, ctx->fallback_name); } break; case N_ROOT: - ws = workspace_create(NULL, ctx->name); + ws = workspace_create(NULL, ctx->fallback_name); break; } @@ -148,8 +148,8 @@ static void ctx_handle_node_destroy(struct wl_listener *listener, void *data) { wl_list_init(&ctx->node_destroy.link); // We want to save this ws name to recreate later, hopefully on the // same output - free(ctx->name); - ctx->name = strdup(ws->name); + free(ctx->fallback_name); + ctx->fallback_name = strdup(ws->name); if (!ws->output || ws->output->node.destroying) { // If the output is being destroyed it would be pointless to track // If the output is being disabled, we'll find out if it's still @@ -178,21 +178,41 @@ static void token_handle_destroy(struct wl_listener *listener, void *data) { launcher_ctx_destroy(ctx); } -struct launcher_ctx *launcher_ctx_create() { - struct sway_seat *seat = input_manager_current_seat(); - struct sway_workspace *ws = seat_get_focused_workspace(seat); - if (!ws) { - sway_log(SWAY_DEBUG, "Failed to create launch context. No workspace."); +struct launcher_ctx *launcher_ctx_create(struct wlr_xdg_activation_token_v1 *token, + struct sway_node *node) { + struct launcher_ctx *ctx = calloc(1, sizeof(struct launcher_ctx)); + + const char *fallback_name = NULL; + struct sway_workspace *ws = NULL; + switch (node->type) { + case N_CONTAINER: + // Unimplemented + free(ctx); + return NULL; + case N_WORKSPACE: + ws = node->sway_workspace; + fallback_name = ws->name; + break; + case N_OUTPUT:; + struct sway_output *output = node->sway_output; + ws = output_get_active_workspace(output); + fallback_name = ws ? ws->name : NULL; + break; + case N_ROOT: + // Unimplemented + free(ctx); return NULL; } - struct launcher_ctx *ctx = calloc(1, sizeof(struct launcher_ctx)); - struct wlr_xdg_activation_token_v1 *token = - wlr_xdg_activation_token_v1_create(server.xdg_activation_v1); - token->data = ctx; - ctx->name = strdup(ws->name); + if (!fallback_name) { + // TODO: implement a better fallback. + free(ctx); + return NULL; + } + + ctx->fallback_name = strdup(fallback_name); ctx->token = token; - ctx->node = &ws->node; + ctx->node = node; ctx->node_destroy.notify = ctx_handle_node_destroy; wl_signal_add(&ctx->node->events.destroy, &ctx->node_destroy); @@ -202,6 +222,30 @@ struct launcher_ctx *launcher_ctx_create() { wl_list_init(&ctx->link); wl_list_insert(&server.pending_launcher_ctxs, &ctx->link); + + token->data = ctx; + return ctx; +} + +// Creates a context with a new token for the internal launcher +struct launcher_ctx *launcher_ctx_create_internal() { + struct sway_seat *seat = input_manager_current_seat(); + struct sway_workspace *ws = seat_get_focused_workspace(seat); + if (!ws) { + sway_log(SWAY_DEBUG, "Failed to create launch context. No workspace."); + return NULL; + } + + struct wlr_xdg_activation_token_v1 *token = + wlr_xdg_activation_token_v1_create(server.xdg_activation_v1); + token->seat = seat->wlr_seat; + + struct launcher_ctx *ctx = launcher_ctx_create(token, &ws->node); + if (!ctx) { + wlr_xdg_activation_token_v1_destroy(token); + return NULL; + } + return ctx; } diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index e15a33415..9c29f66ba 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -630,7 +630,7 @@ static void handle_request_activate(struct wl_listener *listener, void *data) { if (!xsurface->mapped) { return; } - view_request_activate(view); + view_request_activate(view, NULL); transaction_commit_dirty(); } diff --git a/sway/server.c b/sway/server.c index 43ff8cfb1..1ff0b461f 100644 --- a/sway/server.c +++ b/sway/server.c @@ -225,6 +225,10 @@ bool server_init(struct sway_server *server) { xdg_activation_v1_handle_request_activate; wl_signal_add(&server->xdg_activation_v1->events.request_activate, &server->xdg_activation_v1_request_activate); + server->xdg_activation_v1_new_token.notify = + xdg_activation_v1_handle_new_token; + wl_signal_add(&server->xdg_activation_v1->events.new_token, + &server->xdg_activation_v1_new_token); wl_list_init(&server->pending_launcher_ctxs); diff --git a/sway/tree/view.c b/sway/tree/view.c index ec0ad4afb..ba3ef4891 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -366,12 +366,14 @@ void view_set_activated(struct sway_view *view, bool activated) { } } -void view_request_activate(struct sway_view *view) { +void view_request_activate(struct sway_view *view, struct sway_seat *seat) { struct sway_workspace *ws = view->container->pending.workspace; if (!ws) { // hidden scratchpad container return; } - struct sway_seat *seat = input_manager_current_seat(); + if (!seat) { + seat = input_manager_current_seat(); + } switch (config->focus_on_window_activation) { case FOWA_SMART: diff --git a/sway/xdg_activation_v1.c b/sway/xdg_activation_v1.c index cc3dcec09..614f51cdc 100644 --- a/sway/xdg_activation_v1.c +++ b/sway/xdg_activation_v1.c @@ -1,6 +1,7 @@ #include #include "sway/desktop/launcher.h" #include "sway/tree/view.h" +#include "sway/tree/workspace.h" void xdg_activation_v1_handle_request_activate(struct wl_listener *listener, void *data) { @@ -31,5 +32,22 @@ void xdg_activation_v1_handle_request_activate(struct wl_listener *listener, return; } - view_request_activate(view); + struct wlr_seat *wlr_seat = event->token->seat; + // The requesting seat may have been destroyed. + if (wlr_seat) { + struct sway_seat *seat = wlr_seat->data; + view_request_activate(view, seat); + } +} + +void xdg_activation_v1_handle_new_token(struct wl_listener *listener, void *data) { + struct wlr_xdg_activation_token_v1 *token = data; + struct sway_seat *seat = token->seat ? token->seat->data : + input_manager_current_seat(); + + struct sway_workspace *ws = seat_get_focused_workspace(seat); + if (ws) { + launcher_ctx_create(token, &ws->node); + return; + } }