From ddad41f423db14f89f765fc134d45d1ea8a60caf Mon Sep 17 00:00:00 2001 From: Rouven Czerwinski Date: Sun, 16 Jun 2019 17:36:00 +0200 Subject: [PATCH] Fix sway crashes for scratchpad layouts Currently container_replace removes the container from the scratchpad and re-adds it afterwards. For the split commands this results in the container being send to the scratchpad, which results in a NULL segfault if the same container should be shown. Pass an optional workspace to root_scratchpad_add_container, if the workspace is passed the window will continue to show on the workspace. If NULL is passed it is sent to the scratchpad. This was an issue if no other window except the scratchpad container was on the workspace. Fixes #4240 --- include/sway/tree/root.h | 6 +++++- sway/commands/move.c | 2 +- sway/tree/container.c | 4 +++- sway/tree/root.c | 27 ++++++++++++++++----------- 4 files changed, 25 insertions(+), 14 deletions(-) diff --git a/include/sway/tree/root.h b/include/sway/tree/root.h index c4f84207d..799d751a9 100644 --- a/include/sway/tree/root.h +++ b/include/sway/tree/root.h @@ -46,8 +46,12 @@ void root_destroy(struct sway_root *root); /** * Move a container to the scratchpad. + * If a workspace is passed, the container is assumed to have been in + * the scratchpad before and is shown on the workspace. + * The ws parameter can safely be NULL. */ -void root_scratchpad_add_container(struct sway_container *con); +void root_scratchpad_add_container(struct sway_container *con, + struct sway_workspace *ws); /** * Remove a container from the scratchpad. diff --git a/sway/commands/move.c b/sway/commands/move.c index 9c6e69ece..6fd66f285 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c @@ -856,7 +856,7 @@ static struct cmd_results *cmd_move_to_scratchpad(void) { } if (!con->scratchpad) { - root_scratchpad_add_container(con); + root_scratchpad_add_container(con, NULL); } else if (con->workspace) { root_scratchpad_hide(con); } diff --git a/sway/tree/container.c b/sway/tree/container.c index c4d21f0ad..89a471513 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -1378,10 +1378,12 @@ void container_replace(struct sway_container *container, struct sway_container *replacement) { enum sway_fullscreen_mode fullscreen = container->fullscreen_mode; bool scratchpad = container->scratchpad; + struct sway_workspace *ws = NULL; if (fullscreen != FULLSCREEN_NONE) { container_fullscreen_disable(container); } if (scratchpad) { + ws = container->workspace; root_scratchpad_show(container); root_scratchpad_remove_container(container); } @@ -1390,7 +1392,7 @@ void container_replace(struct sway_container *container, container_detach(container); } if (scratchpad) { - root_scratchpad_add_container(replacement); + root_scratchpad_add_container(replacement, ws); } switch (fullscreen) { case FULLSCREEN_WORKSPACE: diff --git a/sway/tree/root.c b/sway/tree/root.c index 1dabc2870..55d784873 100644 --- a/sway/tree/root.c +++ b/sway/tree/root.c @@ -54,7 +54,7 @@ void root_destroy(struct sway_root *root) { free(root); } -void root_scratchpad_add_container(struct sway_container *con) { +void root_scratchpad_add_container(struct sway_container *con, struct sway_workspace *ws) { if (!sway_assert(!con->scratchpad, "Container is already in scratchpad")) { return; } @@ -77,18 +77,23 @@ void root_scratchpad_add_container(struct sway_container *con) { container_detach(con); con->scratchpad = true; list_add(root->scratchpad, con); + if (ws) { + workspace_add_floating(ws, con); + } - struct sway_seat *seat = input_manager_current_seat(); - struct sway_node *new_focus = NULL; - if (parent) { - arrange_container(parent); - new_focus = seat_get_focus_inactive(seat, &parent->node); + if (!ws) { + struct sway_seat *seat = input_manager_current_seat(); + struct sway_node *new_focus = NULL; + if (parent) { + arrange_container(parent); + new_focus = seat_get_focus_inactive(seat, &parent->node); + } + if (!new_focus) { + arrange_workspace(workspace); + new_focus = seat_get_focus_inactive(seat, &workspace->node); + } + seat_set_focus(seat, new_focus); } - if (!new_focus) { - arrange_workspace(workspace); - new_focus = seat_get_focus_inactive(seat, &workspace->node); - } - seat_set_focus(seat, new_focus); ipc_event_window(con, "move"); }