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
This commit is contained in:
Rouven Czerwinski 2019-06-16 17:36:00 +02:00 committed by Drew DeVault
parent bdd4d69205
commit ddad41f423
4 changed files with 25 additions and 14 deletions

View file

@ -46,8 +46,12 @@ void root_destroy(struct sway_root *root);
/** /**
* Move a container to the scratchpad. * 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. * Remove a container from the scratchpad.

View file

@ -856,7 +856,7 @@ static struct cmd_results *cmd_move_to_scratchpad(void) {
} }
if (!con->scratchpad) { if (!con->scratchpad) {
root_scratchpad_add_container(con); root_scratchpad_add_container(con, NULL);
} else if (con->workspace) { } else if (con->workspace) {
root_scratchpad_hide(con); root_scratchpad_hide(con);
} }

View file

@ -1378,10 +1378,12 @@ void container_replace(struct sway_container *container,
struct sway_container *replacement) { struct sway_container *replacement) {
enum sway_fullscreen_mode fullscreen = container->fullscreen_mode; enum sway_fullscreen_mode fullscreen = container->fullscreen_mode;
bool scratchpad = container->scratchpad; bool scratchpad = container->scratchpad;
struct sway_workspace *ws = NULL;
if (fullscreen != FULLSCREEN_NONE) { if (fullscreen != FULLSCREEN_NONE) {
container_fullscreen_disable(container); container_fullscreen_disable(container);
} }
if (scratchpad) { if (scratchpad) {
ws = container->workspace;
root_scratchpad_show(container); root_scratchpad_show(container);
root_scratchpad_remove_container(container); root_scratchpad_remove_container(container);
} }
@ -1390,7 +1392,7 @@ void container_replace(struct sway_container *container,
container_detach(container); container_detach(container);
} }
if (scratchpad) { if (scratchpad) {
root_scratchpad_add_container(replacement); root_scratchpad_add_container(replacement, ws);
} }
switch (fullscreen) { switch (fullscreen) {
case FULLSCREEN_WORKSPACE: case FULLSCREEN_WORKSPACE:

View file

@ -54,7 +54,7 @@ void root_destroy(struct sway_root *root) {
free(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")) { if (!sway_assert(!con->scratchpad, "Container is already in scratchpad")) {
return; return;
} }
@ -77,18 +77,23 @@ void root_scratchpad_add_container(struct sway_container *con) {
container_detach(con); container_detach(con);
con->scratchpad = true; con->scratchpad = true;
list_add(root->scratchpad, con); list_add(root->scratchpad, con);
if (ws) {
workspace_add_floating(ws, con);
}
struct sway_seat *seat = input_manager_current_seat(); if (!ws) {
struct sway_node *new_focus = NULL; struct sway_seat *seat = input_manager_current_seat();
if (parent) { struct sway_node *new_focus = NULL;
arrange_container(parent); if (parent) {
new_focus = seat_get_focus_inactive(seat, &parent->node); 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"); ipc_event_window(con, "move");
} }