diff --git a/src/commands.c b/src/commands.c index 070f6353..0263802f 100644 --- a/src/commands.c +++ b/src/commands.c @@ -1158,6 +1158,7 @@ void cmd_move_workspace_to_output(I3_CMD, char *name) { /* notify the IPC listeners */ ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"init\"}"); } + DLOG("Detaching\n"); /* detach from the old output and attach to the new output */ Con *old_content = ws->parent; @@ -1182,10 +1183,21 @@ void cmd_move_workspace_to_output(I3_CMD, char *name) { workspace_show(ws); } - /* Call the on_remove_child callback of the workspace which previously - * was visible on the destination output. Since it is no longer - * visible, it might need to get cleaned up. */ - CALL(previously_visible_ws, on_remove_child); + /* NB: We cannot simply work with previously_visible_ws since it might + * have been cleaned up by workspace_show() already, depending on the + * focus order/number of other workspaces on the output. + * Instead, we loop through the available workspaces and only work with + * previously_visible_ws if we still find it. */ + TAILQ_FOREACH(ws, &(content->nodes_head), nodes) { + if (ws != previously_visible_ws) + continue; + + /* Call the on_remove_child callback of the workspace which previously + * was visible on the destination output. Since it is no longer + * visible, it might need to get cleaned up. */ + CALL(previously_visible_ws, on_remove_child); + break; + } } cmd_output->needs_tree_render = true; diff --git a/src/workspace.c b/src/workspace.c index 3a5844cb..14840e4a 100644 --- a/src/workspace.c +++ b/src/workspace.c @@ -365,7 +365,7 @@ static void _workspace_show(Con *workspace) { workspace_reassign_sticky(workspace); - LOG("switching to %p\n", workspace); + DLOG("switching to %p / %s\n", workspace, workspace->name); Con *next = con_descend_focused(workspace); /* Memorize current output */ @@ -400,6 +400,7 @@ static void _workspace_show(Con *workspace) { } else con_focus(next); + DLOG("old = %p / %s\n", old, (old ? old->name : "(null)")); /* Close old workspace if necessary. This must be done *after* doing * urgency handling, because tree_close() will do a con_focus() on the next * client, which will clear the urgency flag too early. Also, there is no diff --git a/testcases/t/507-workspace-move-crash.t b/testcases/t/507-workspace-move-crash.t new file mode 100644 index 00000000..9e80553b --- /dev/null +++ b/testcases/t/507-workspace-move-crash.t @@ -0,0 +1,48 @@ +#!perl +# vim:ts=4:sw=4:expandtab +# +# Please read the following documents before working on tests: +# • http://build.i3wm.org/docs/testsuite.html +# (or docs/testsuite) +# +# • http://build.i3wm.org/docs/lib-i3test.html +# (alternatively: perldoc ./testcases/lib/i3test.pm) +# +# • http://build.i3wm.org/docs/ipc.html +# (or docs/ipc) +# +# • http://onyxneon.com/books/modern_perl/modern_perl_a4.pdf +# (unless you are already familiar with Perl) +# +# Tests whether i3 crashes on cross-output moves with one workspace per output. +# Ticket: #827 +# Bug still in: 4.3-78-g66b389c +# +use List::Util qw(first); +use i3test i3_autostart => 0; + +# Ensure the pointer is at (0, 0) so that we really start on the first +# (the left) workspace. +$x->root->warp_pointer(0, 0); + +my $config = <