diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index 56b4f834..588608b1 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -795,8 +795,22 @@ struct workspace_switch_data { list_t *from_containers; list_t *to_containers; struct sway_root_filters *root_filters; + struct wl_listener from_destroy; + struct wl_listener to_destroy; }; +static void workspace_switch_from_destroy(struct wl_listener *listener, void *data) { + struct workspace_switch_data *ws_data = wl_container_of(listener, ws_data, from_destroy); + ws_data->from = NULL; + wl_list_remove(&listener->link); +} + +static void workspace_switch_to_destroy(struct wl_listener *listener, void *data) { + struct workspace_switch_data *ws_data = wl_container_of(listener, ws_data, to_destroy); + ws_data->to = NULL; + wl_list_remove(&listener->link); +} + static void workspace_switch_callback_end(void *callback_data) { struct workspace_switch_data *data = callback_data; root_filters_destroy(root, data->root_filters); @@ -815,10 +829,17 @@ static void workspace_switch_callback_end(void *callback_data) { if (data->from && data->from->output) { node_set_dirty(&data->from->node); } - if (data->to->output) { + if (data->to && data->to->output) { node_set_dirty(&data->to->node); } + if (data->from_destroy.link.next) { + wl_list_remove(&data->from_destroy.link); + } + if (data->to_destroy.link.next) { + wl_list_remove(&data->to_destroy.link); + } + list_free_items_and_destroy(data->from_containers); list_free_items_and_destroy(data->to_containers); free(data); @@ -840,7 +861,7 @@ static bool switching_output(struct sway_workspace *workspace, } struct sway_output *output = workspace->output; struct sway_output *from_output = data->from ? data->from->output : NULL; - struct sway_output *to_output = data->to->output; + struct sway_output *to_output = data->to ? data->to->output : NULL; if (!output || !from_output || !to_output) { return false; } @@ -1028,6 +1049,20 @@ static void animate_workspace_switch(struct sway_output *output, data->from_containers = create_list(); data->to_containers = create_list(); + data->from_destroy.notify = workspace_switch_from_destroy; + if (data->from) { + wl_signal_add(&data->from->node.events.destroy, &data->from_destroy); + } else { + wl_list_init(&data->from_destroy.link); + } + + data->to_destroy.notify = workspace_switch_to_destroy; + if (data->to) { + wl_signal_add(&data->to->node.events.destroy, &data->to_destroy); + } else { + wl_list_init(&data->to_destroy.link); + } + animation_end(); animation_set_type(ANIMATION_WORKSPACE_SWITCH); @@ -1102,12 +1137,13 @@ bool workspace_switch(struct sway_workspace *workspace) { seat_set_focus(seat, next); // old_ws may not have an output because it is being destroyed if empty - if (!layout_overview_workspaces_enabled() && old_ws != workspace && ( - (old_ws->output && old_ws->output == workspace->output) || - (old_ws->output && !workspace->output) || - (!old_ws->output && workspace->output)) && - workspace->split.sibling != old_ws && - animation_enabled() && animation_path_enabled(ANIMATION_WORKSPACE_SWITCH)) { + if (!layout_overview_workspaces_enabled() && old_ws != workspace && + ((old_ws->output && old_ws->output == workspace->output) || + (old_ws->output && !workspace->output) || + (!old_ws->output && workspace->output)) && + workspace->split.sibling != old_ws && animation_enabled() && + animation_path_enabled(ANIMATION_WORKSPACE_SWITCH) && !workspace->node.destroying && + !old_ws->node.destroying) { struct sway_output *output = old_ws->output ? old_ws->output : workspace->output; animate_workspace_switch(output, old_ws, workspace); } else {